Modularize ThumbnailProvider

This CL moves ThumbnailProvider.java and all associated Java/C++ files to a
separate chrome/browser/thumbnail directory.  This CL pulls in all obvious
dependencies and splits them to a modularized build target.

Files moved:
download.DownloadMediaData.java
download.DownloadMediaParserBridge.java
download.DownloadMediaParserTest.java
widget.ThumbnailDiskStorage.java
widget.ThumbnailGenerator.java
widget.ThumbnailGeneratorCallback.java
widget.ThumbnailProvider.java
widget.ThumbnailProviderImpl.java
widget.ThumbnailStorageDelegate.java
widget.ThumbnailDiskStorageTest.java
widget.ThumbnailProviderImplTest.java
widget.thumbnail_cache_entry.proto

download/download_media_parser.cc
download/download_media_parser.h
download/download_media_parser_bridge.cc
download/download_media_parser_bridge.h
download/image_thumbnail_request.cc
download/image_thumbnail_request.h
download/local_media_data_source_factory.cc
download/local_media_data_source_factory.h
download/thumbnail_util.cc
download/thumbnail_util.h
thumbnail/scoped_ptr_expiring_cache.h
thumbnail/scoped_ptr_expiring_cache_unittest.cc
thumbnail/thumbnail.cc
thumbnail/thumbnail.h
thumbnail/thumbnail_cache.cc
thumbnail/thumbnail_cache.h
widget/thumbnail_generator.cc
widget/thumbnail_generator.h

chrome/browser/image_decoder.cc
chrome/browser/image_decoder.h
chrome/browser/image_decoder_browsertest.cc

data/android/thumbnail_provider/test_image_10x10.jpg
data/android/thumbnail_provider/test_image_10x20.jpg
data/android/thumbnail_provider/test_image_20x10.jpg
data/android/thumbnail_provider/test_image_20x20.jpg

Conceptual targets pulled into chrome/browser/thumbnail:
- C++ target
- Java target
- proto target
- JNI target
- javatests
- junit tests
- browsertests
- unit tests
- test data

Extra notes:
- chrome/browser/thumbnail/generator/stats.h/cc contains functions/enums from
download_stats.h/cc
- Fixed presubmit warnings on NULL vs. nullptr
- Fixed presubmit warnings on using content::MessageLoopRunner vs. base::RunLoop.

Bug:1018427

Change-Id: I81c48e427fd135c7b4e9e0791b5e74ca951fa62b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1865624
Commit-Queue: David Trainor <[email protected]>
Reviewed-by: Scott Violet <[email protected]>
Reviewed-by: Tommy Nyquist <[email protected]>
Reviewed-by: Min Qin <[email protected]>
Cr-Commit-Position: refs/heads/master@{#735252}
diff --git a/chrome/android/BUILD.gn b/chrome/android/BUILD.gn
index 2b8c267..73aa190 100644
--- a/chrome/android/BUILD.gn
+++ b/chrome/android/BUILD.gn
@@ -212,6 +212,7 @@
 
 android_library("chrome_java") {
   deps = [
+    ":chrome_android_java_switches",
     ":chrome_app_java_resources",
     ":chrome_download_java_resources",
     ":chrome_public_android_manifest",
@@ -219,7 +220,6 @@
     ":chrome_public_java",
     ":chrome_version_constants",
     ":partner_location_descriptor_proto_java",
-    ":thumbnail_cache_entry_proto_java",
     ":update_proto_java",
     ":usage_stats_proto_java",
     "$google_play_services_package:google_play_services_auth_base_java",
@@ -255,6 +255,7 @@
     "//chrome/browser/settings:java",
     "//chrome/browser/share/android:java_resources",
     "//chrome/browser/share/android:screenshot_java",
+    "//chrome/browser/thumbnail:java",
     "//chrome/browser/ui/android/appmenu:factory_java",
     "//chrome/browser/ui/android/appmenu:java",
     "//chrome/browser/ui/android/native_page:java",
@@ -379,7 +380,6 @@
   srcjar_deps = [
     ":chrome_android_java_enums_srcjar",
     ":chrome_android_java_google_api_keys_srcjar",
-    ":chrome_android_java_switches_srcjar",
     ":chrome_product_config",
     ":photo_picker_aidl",
     ":resource_id_javagen",
@@ -592,16 +592,15 @@
   template = "//chrome/android/java_templates/ChromeSwitches.java.tmpl"
 }
 
+android_library("chrome_android_java_switches") {
+  srcjar_deps = [ ":chrome_android_java_switches_srcjar" ]
+}
+
 proto_java_library("partner_location_descriptor_proto_java") {
   proto_path = "java/src/org/chromium/chrome/browser/omnibox/geo"
   sources = [ "$proto_path/partner_location_descriptor.proto" ]
 }
 
-proto_java_library("thumbnail_cache_entry_proto_java") {
-  proto_path = "java/src/org/chromium/chrome/browser/widget"
-  sources = [ "$proto_path/thumbnail_cache_entry.proto" ]
-}
-
 proto_java_library("update_proto_java") {
   proto_path = "java/src/org/chromium/chrome/browser/omaha/metrics"
   sources = [ "$proto_path/update_success_tracking.proto" ]
@@ -647,6 +646,7 @@
     "//chrome/android/webapk/test:junit_test_support",
     "//chrome/browser/image_fetcher:java",
     "//chrome/browser/preferences:preferences_junit_tests",
+    "//chrome/browser/thumbnail:java",
     "//chrome/browser/ui/android/appmenu/internal:junit",
     "//chrome/browser/ui/messages/android:junit",
     "//chrome/test/android:chrome_java_test_support",
@@ -738,6 +738,7 @@
 
   deps = [
     ":browser_java_test_support",
+    ":chrome_android_java_switches",
     ":chrome_app_java_resources",
     ":chrome_test_util_java",
     ":partner_location_descriptor_proto_java",
@@ -767,6 +768,8 @@
     "//chrome/browser/flags:java",
     "//chrome/browser/preferences:java",
     "//chrome/browser/settings:java",
+    "//chrome/browser/thumbnail:java",
+    "//chrome/browser/thumbnail:javatests",
     "//chrome/browser/ui/android/appmenu:java",
     "//chrome/browser/ui/android/appmenu:test_support_java",
     "//chrome/browser/ui/messages/android:java",
@@ -1480,6 +1483,7 @@
     "//chrome/android/features/autofill_assistant:autofill_assistant_java_test_support",
     "//chrome/browser/android/metrics:ukm_java_test_support",
     "//chrome/browser/subresource_filter:subresource_filter_java_test_support",
+    "//chrome/browser/thumbnail:thumbnail_java_test_support",
     "//components/minidump_uploader:minidump_uploader_java",
     "//content/public/test/android:content_java_test_support",
   ]
@@ -1544,6 +1548,7 @@
   deps = [
     ":test_support_jni_headers",
     "//chrome/browser",
+    "//chrome/browser/thumbnail:test_support",
     "//components/offline_pages/core/background:test_support",
     "//content/test:test_support",
   ]
@@ -2598,8 +2603,6 @@
     "java/src/org/chromium/chrome/browser/download/DownloadItem.java",
     "java/src/org/chromium/chrome/browser/download/DownloadLocationDialogBridge.java",
     "java/src/org/chromium/chrome/browser/download/DownloadManagerService.java",
-    "java/src/org/chromium/chrome/browser/download/DownloadMediaData.java",
-    "java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java",
     "java/src/org/chromium/chrome/browser/download/DownloadUtils.java",
     "java/src/org/chromium/chrome/browser/download/home/rename/RenameUtils.java",
     "java/src/org/chromium/chrome/browser/download/items/OfflineContentAggregatorFactory.java",
@@ -2812,7 +2815,6 @@
     "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenCoordinator.java",
     "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenInstaller.java",
     "java/src/org/chromium/chrome/browser/webapps/addtohomescreen/AddToHomescreenMediator.java",
-    "java/src/org/chromium/chrome/browser/widget/ThumbnailGenerator.java",
   ]
 
   # Used for testing only, should not be shipped to end users.
diff --git a/chrome/android/chrome_java_sources.gni b/chrome/android/chrome_java_sources.gni
index c69c83b..65b2568a 100644
--- a/chrome/android/chrome_java_sources.gni
+++ b/chrome/android/chrome_java_sources.gni
@@ -515,8 +515,6 @@
   "java/src/org/chromium/chrome/browser/download/DownloadLocationCustomView.java",
   "java/src/org/chromium/chrome/browser/download/DownloadLocationDialogBridge.java",
   "java/src/org/chromium/chrome/browser/download/DownloadManagerService.java",
-  "java/src/org/chromium/chrome/browser/download/DownloadMediaData.java",
-  "java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java",
   "java/src/org/chromium/chrome/browser/download/DownloadMetrics.java",
   "java/src/org/chromium/chrome/browser/download/DownloadNotificationFactory.java",
   "java/src/org/chromium/chrome/browser/download/DownloadNotificationService.java",
@@ -1867,12 +1865,6 @@
   "java/src/org/chromium/chrome/browser/widget/FeatureHighlightProvider.java",
   "java/src/org/chromium/chrome/browser/widget/NumberRollView.java",
   "java/src/org/chromium/chrome/browser/widget/ScrimView.java",
-  "java/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorage.java",
-  "java/src/org/chromium/chrome/browser/widget/ThumbnailGenerator.java",
-  "java/src/org/chromium/chrome/browser/widget/ThumbnailGeneratorCallback.java",
-  "java/src/org/chromium/chrome/browser/widget/ThumbnailProvider.java",
-  "java/src/org/chromium/chrome/browser/widget/ThumbnailProviderImpl.java",
-  "java/src/org/chromium/chrome/browser/widget/ThumbnailStorageDelegate.java",
   "java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheet.java",
   "java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetContent.java",
   "java/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetController.java",
diff --git a/chrome/android/chrome_test_java_sources.gni b/chrome/android/chrome_test_java_sources.gni
index 25fe500..659b9a2 100644
--- a/chrome/android/chrome_test_java_sources.gni
+++ b/chrome/android/chrome_test_java_sources.gni
@@ -147,7 +147,6 @@
   "javatests/src/org/chromium/chrome/browser/download/DownloadInfoBarControllerTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadLocationChangeTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadManagerServiceTest.java",
-  "javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadNotificationServiceTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadTest.java",
   "javatests/src/org/chromium/chrome/browser/download/DownloadTestRule.java",
@@ -527,8 +526,6 @@
   "javatests/src/org/chromium/chrome/browser/webauth/AuthenticatorTest.java",
   "javatests/src/org/chromium/chrome/browser/webshare/WebShareTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/ScrimTest.java",
-  "javatests/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorageTest.java",
-  "javatests/src/org/chromium/chrome/browser/widget/ThumbnailProviderImplTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetControllerTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetObserverTest.java",
   "javatests/src/org/chromium/chrome/browser/widget/bottomsheet/BottomSheetTest.java",
diff --git a/chrome/android/java/DEPS b/chrome/android/java/DEPS
index 630cf85..6143b0c 100644
--- a/chrome/android/java/DEPS
+++ b/chrome/android/java/DEPS
@@ -3,6 +3,7 @@
 
   "+chrome/browser/android/thin_webview/java",
   "+chrome/browser/share/android",
+  "+chrome/browser/thumbnail/generator/android/java",
   "+chrome/browser/ui/android/appmenu",
   "-chrome/browser/ui/android/appmenu/internal",
   "+chrome/browser/ui/messages/android/java",
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java b/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java
deleted file mode 100644
index 03db9da..0000000
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaParserBridge.java
+++ /dev/null
@@ -1,56 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package org.chromium.chrome.browser.download;
-
-import org.chromium.base.Callback;
-import org.chromium.base.annotations.NativeMethods;
-
-/**
- * A JNI bridge that owns a native side DownloadMediaParser, which parses media file safely in an
- * utility process.
- */
-public class DownloadMediaParserBridge {
-    private long mNativeDownloadMediaParserBridge;
-
-    /** Creates a media parser to analyze media metadata and retrieve thumbnails.
-     * @param mimeType The mime type of the media file.
-     * @param filePath The absolute path of the media file.
-     * @param totalSize Total size of the media file.
-     * @param callback Callback to get the result.
-     */
-    public DownloadMediaParserBridge(
-            String mimeType, String filePath, Callback<DownloadMediaData> callback) {
-        mNativeDownloadMediaParserBridge = DownloadMediaParserBridgeJni.get().init(
-                DownloadMediaParserBridge.this, mimeType, filePath, callback);
-    }
-
-    /**
-     * Destroys the native object of DownloadMediaParser. This will result in the utility process
-     * being destroyed.
-     */
-    public void destroy() {
-        DownloadMediaParserBridgeJni.get().destroy(
-                mNativeDownloadMediaParserBridge, DownloadMediaParserBridge.this);
-        mNativeDownloadMediaParserBridge = 0;
-    }
-
-    /**
-     * Starts to parse a media file to retrieve media metadata and video thumbnail.
-     */
-    public void start() {
-        if (mNativeDownloadMediaParserBridge != 0) {
-            DownloadMediaParserBridgeJni.get().start(
-                    mNativeDownloadMediaParserBridge, DownloadMediaParserBridge.this);
-        }
-    }
-
-    @NativeMethods
-    interface Natives {
-        long init(DownloadMediaParserBridge caller, String mimeType, String filePath,
-                Callback<DownloadMediaData> callback);
-        void destroy(long nativeDownloadMediaParserBridge, DownloadMediaParserBridge caller);
-        void start(long nativeDownloadMediaParserBridge, DownloadMediaParserBridge caller);
-    }
-}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
index 3b440e76..834c519 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/OfflineContentProviderGlue.java
@@ -7,7 +7,7 @@
 import org.chromium.base.Callback;
 import org.chromium.base.ObserverList;
 import org.chromium.chrome.browser.download.home.DownloadManagerUiConfig;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
 import org.chromium.components.offline_items_collection.ContentId;
 import org.chromium.components.offline_items_collection.LaunchLocation;
 import org.chromium.components.offline_items_collection.LegacyHelpers;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java
index 5f13033..4179514 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/glue/ThumbnailRequestGlue.java
@@ -8,9 +8,9 @@
 
 import org.chromium.base.Callback;
 import org.chromium.base.ContextUtils;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
-import org.chromium.chrome.browser.widget.ThumbnailProvider.ThumbnailRequest;
-import org.chromium.chrome.browser.widget.ThumbnailProviderImpl;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider.ThumbnailRequest;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProviderImpl;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
 import org.chromium.components.offline_items_collection.OfflineItemVisuals;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
index ebaa3bb..057adf7c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/download/home/list/DateOrderedListMediator.java
@@ -36,9 +36,9 @@
 import org.chromium.chrome.browser.download.home.metrics.OfflineItemStartupLogger;
 import org.chromium.chrome.browser.download.home.metrics.UmaUtils;
 import org.chromium.chrome.browser.download.home.metrics.UmaUtils.ViewAction;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
-import org.chromium.chrome.browser.widget.ThumbnailProvider.ThumbnailRequest;
-import org.chromium.chrome.browser.widget.ThumbnailProviderImpl;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider.ThumbnailRequest;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProviderImpl;
 import org.chromium.chrome.browser.widget.selection.SelectionDelegate;
 import org.chromium.components.offline_items_collection.OfflineContentProvider;
 import org.chromium.components.offline_items_collection.OfflineItem;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java
index f97662575..db79d57 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/ImageFetcher.java
@@ -15,7 +15,7 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
 
 /**
  * Class responsible for fetching images for the views in the NewTabPage and Chrome Home.
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsDependencyFactory.java b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsDependencyFactory.java
index 9013614..5756c1f 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsDependencyFactory.java
+++ b/chrome/android/java/src/org/chromium/chrome/browser/suggestions/SuggestionsDependencyFactory.java
@@ -20,8 +20,8 @@
 import org.chromium.chrome.browser.profiles.Profile;
 import org.chromium.chrome.browser.suggestions.mostvisited.MostVisitedSites;
 import org.chromium.chrome.browser.suggestions.mostvisited.MostVisitedSitesBridge;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
-import org.chromium.chrome.browser.widget.ThumbnailProviderImpl;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProviderImpl;
 
 /**
  * Provides an injection mechanisms for dependencies of the suggestions package.
diff --git a/chrome/android/javatests/DEPS b/chrome/android/javatests/DEPS
index 5d4d2db5..baa346c 100644
--- a/chrome/android/javatests/DEPS
+++ b/chrome/android/javatests/DEPS
@@ -1,6 +1,7 @@
 include_rules = [
   "+chrome/app",
   "+chrome/browser/preferences/android/java",
+  "+chrome/browser/thumbnail/generator/android/java",
   "+chrome/browser/ui/android/appmenu",
   "-chrome/browser/ui/android/appmenu/internal",
   "+chrome/browser/ui/messages/android/java",
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
index 38309fdd..7ed4092 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
+++ b/chrome/android/javatests/src/org/chromium/chrome/browser/ntp/snippets/ArticleSnippetsTest.java
@@ -58,8 +58,8 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsRecyclerView;
 import org.chromium.chrome.browser.suggestions.SuggestionsUiDelegate;
 import org.chromium.chrome.browser.suggestions.ThumbnailGradient;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
 import org.chromium.chrome.browser.ui.messages.snackbar.SnackbarManager;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
 import org.chromium.chrome.test.ChromeActivityTestRule;
 import org.chromium.chrome.test.ChromeJUnit4RunnerDelegate;
 import org.chromium.chrome.test.util.ChromeRenderTestRule;
diff --git a/chrome/android/junit/DEPS b/chrome/android/junit/DEPS
index c724b369..193cbed 100644
--- a/chrome/android/junit/DEPS
+++ b/chrome/android/junit/DEPS
@@ -3,6 +3,7 @@
   "+chrome/lib/lifecycle/public",
   "+chrome/browser/image_fetcher",
   "+chrome/browser/preferences/android/java",
+  "+chrome/browser/thumbnail/generator/android/java",
   "+chrome/browser/ui/messages/android/java",
   "+chrome/browser/util",
   "+components/autofill/android/java/src/org/chromium/components/autofill",
diff --git a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/SuggestionsImageFetcherTest.java b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/SuggestionsImageFetcherTest.java
index c4a05b0..2e27f8c 100644
--- a/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/SuggestionsImageFetcherTest.java
+++ b/chrome/android/junit/src/org/chromium/chrome/browser/suggestions/SuggestionsImageFetcherTest.java
@@ -32,7 +32,7 @@
 import org.chromium.chrome.browser.ntp.snippets.SnippetArticle;
 import org.chromium.chrome.browser.ntp.snippets.SuggestionsSource;
 import org.chromium.chrome.browser.profiles.Profile;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
 import org.chromium.chrome.test.util.browser.suggestions.SuggestionsDependenciesRule;
 
 import java.util.HashMap;
diff --git a/chrome/browser/BUILD.gn b/chrome/browser/BUILD.gn
index 48539f0d..497a9f9f2 100644
--- a/chrome/browser/BUILD.gn
+++ b/chrome/browser/BUILD.gn
@@ -458,8 +458,6 @@
     "download/download_ui_model.cc",
     "download/download_ui_model.h",
     "download/drag_download_item.h",
-    "download/image_thumbnail_request.cc",
-    "download/image_thumbnail_request.h",
     "download/mixed_content_download_blocking.cc",
     "download/mixed_content_download_blocking.h",
     "download/offline_item_model.cc",
@@ -475,8 +473,6 @@
     "download/save_package_file_picker.h",
     "download/simple_download_manager_coordinator_factory.cc",
     "download/simple_download_manager_coordinator_factory.h",
-    "download/thumbnail_util.cc",
-    "download/thumbnail_util.h",
     "download/trusted_sources_manager.cc",
     "download/trusted_sources_manager.h",
     "download/trusted_sources_manager_win.cc",
@@ -597,8 +593,6 @@
     "icon_manager.h",
     "idle/idle_detection_permission_context.cc",
     "idle/idle_detection_permission_context.h",
-    "image_decoder.cc",
-    "image_decoder.h",
     "image_fetcher/image_decoder_impl.cc",
     "image_fetcher/image_decoder_impl.h",
     "image_fetcher/image_fetcher_service_factory.cc",
@@ -1958,6 +1952,7 @@
     "//chrome/app/resources:platform_locale_settings",
     "//chrome/app/theme:theme_resources",
     "//chrome/browser/devtools",
+    "//chrome/browser/image_decoder",
     "//chrome/browser/media:media_engagement_preload_proto",
     "//chrome/browser/media:mojo_bindings",
     "//chrome/browser/media/router",
@@ -1975,6 +1970,7 @@
     "//chrome/browser/sharing:buildflags",
     "//chrome/browser/sharing/proto",
     "//chrome/browser/ssl:proto",
+    "//chrome/browser/thumbnail",
     "//chrome/browser/touch_to_fill",
     "//chrome/browser/ui",
     "//chrome/browser/ui/webui/bluetooth_internals",
@@ -2679,11 +2675,6 @@
       "android/tab_state.h",
       "android/tab_web_contents_delegate_android.cc",
       "android/tab_web_contents_delegate_android.h",
-      "android/thumbnail/scoped_ptr_expiring_cache.h",
-      "android/thumbnail/thumbnail.cc",
-      "android/thumbnail/thumbnail.h",
-      "android/thumbnail/thumbnail_cache.cc",
-      "android/thumbnail/thumbnail_cache.h",
       "android/trusted_cdn.cc",
       "android/trusted_cdn.h",
       "android/usage_stats/notification_suspender.cc",
@@ -2732,8 +2723,6 @@
       "android/webapps/add_to_homescreen_params.h",
       "android/webapps/webapp_registry.cc",
       "android/webapps/webapp_registry.h",
-      "android/widget/thumbnail_generator.cc",
-      "android/widget/thumbnail_generator.h",
       "autofill/accessory_controller.h",
       "autofill/address_accessory_controller.h",
       "autofill/address_accessory_controller_impl.cc",
@@ -2780,10 +2769,6 @@
       "download/android/download_manager_bridge.h",
       "download/android/download_manager_service.cc",
       "download/android/download_manager_service.h",
-      "download/android/download_media_parser.cc",
-      "download/android/download_media_parser.h",
-      "download/android/download_media_parser_bridge.cc",
-      "download/android/download_media_parser_bridge.h",
       "download/android/download_open_source.h",
       "download/android/download_startup_utils.cc",
       "download/android/download_startup_utils.h",
@@ -2794,8 +2779,6 @@
       "download/android/intercept_oma_download_navigation_throttle.cc",
       "download/android/intercept_oma_download_navigation_throttle.h",
       "download/android/items/offline_content_aggregator_factory_android.cc",
-      "download/android/local_media_data_source_factory.cc",
-      "download/android/local_media_data_source_factory.h",
       "download/android/rename_utils.cc",
       "download/android/service/download_background_task.cc",
       "download/android/service/download_task_scheduler.cc",
diff --git a/chrome/browser/android/compositor/layer/thumbnail_layer.cc b/chrome/browser/android/compositor/layer/thumbnail_layer.cc
index 3f385c0..d23502e 100644
--- a/chrome/browser/android/compositor/layer/thumbnail_layer.cc
+++ b/chrome/browser/android/compositor/layer/thumbnail_layer.cc
@@ -5,7 +5,7 @@
 #include "chrome/browser/android/compositor/layer/thumbnail_layer.h"
 
 #include "cc/layers/ui_resource_layer.h"
-#include "chrome/browser/android/thumbnail/thumbnail.h"
+#include "chrome/browser/thumbnail/cc/thumbnail.h"
 #include "ui/gfx/geometry/size_conversions.h"
 
 namespace android {
diff --git a/chrome/browser/android/compositor/tab_content_manager.cc b/chrome/browser/android/compositor/tab_content_manager.cc
index 58ae9fa3..47eb766 100644
--- a/chrome/browser/android/compositor/tab_content_manager.cc
+++ b/chrome/browser/android/compositor/tab_content_manager.cc
@@ -23,8 +23,8 @@
 #include "chrome/android/chrome_jni_headers/TabContentManager_jni.h"
 #include "chrome/browser/android/compositor/layer/thumbnail_layer.h"
 #include "chrome/browser/android/tab_android.h"
-#include "chrome/browser/android/thumbnail/thumbnail.h"
 #include "chrome/browser/flags/android/chrome_feature_list.h"
+#include "chrome/browser/thumbnail/cc/thumbnail.h"
 #include "content/public/browser/interstitial_page.h"
 #include "content/public/browser/render_frame_host.h"
 #include "content/public/browser/render_view_host.h"
@@ -130,12 +130,14 @@
                                      jboolean use_approximation_thumbnail,
                                      jboolean save_jpeg_thumbnails)
     : weak_java_tab_content_manager_(env, obj) {
+  double jpeg_aspect_ratio = base::GetFieldTrialParamByFeatureAsDouble(
+      chrome::android::kTabGridLayoutAndroid, "thumbnail_aspect_ratio", 1.0);
   thumbnail_cache_ = std::make_unique<ThumbnailCache>(
       static_cast<size_t>(default_cache_size),
       static_cast<size_t>(approximation_cache_size),
       static_cast<size_t>(compression_queue_max_size),
       static_cast<size_t>(write_queue_max_size), use_approximation_thumbnail,
-      save_jpeg_thumbnails);
+      save_jpeg_thumbnails, jpeg_aspect_ratio);
   thumbnail_cache_->AddThumbnailCacheObserver(this);
 }
 
diff --git a/chrome/browser/android/compositor/tab_content_manager.h b/chrome/browser/android/compositor/tab_content_manager.h
index 1f7b049..23035f1 100644
--- a/chrome/browser/android/compositor/tab_content_manager.h
+++ b/chrome/browser/android/compositor/tab_content_manager.h
@@ -16,7 +16,7 @@
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
 #include "cc/layers/ui_resource_layer.h"
-#include "chrome/browser/android/thumbnail/thumbnail_cache.h"
+#include "chrome/browser/thumbnail/cc/thumbnail_cache.h"
 #include "content/public/browser/render_widget_host_view.h"
 
 using base::android::ScopedJavaLocalRef;
diff --git a/chrome/browser/android/thumbnail/DEPS b/chrome/browser/android/thumbnail/DEPS
deleted file mode 100644
index 1935ff4..0000000
--- a/chrome/browser/android/thumbnail/DEPS
+++ /dev/null
@@ -1,4 +0,0 @@
-include_rules = [
-  "+cc/resources",
-  "+third_party/android_opengl/etc1",
-]
diff --git a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
index ec48691..3100d00 100644
--- a/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
+++ b/chrome/browser/bitmap_fetcher/bitmap_fetcher.h
@@ -10,7 +10,7 @@
 #include "base/callback_forward.h"
 #include "base/macros.h"
 #include "chrome/browser/bitmap_fetcher/bitmap_fetcher_delegate.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "net/traffic_annotation/network_traffic_annotation.h"
 #include "net/url_request/url_request.h"
 #include "services/network/public/cpp/simple_url_loader.h"
diff --git a/chrome/browser/chromeos/BUILD.gn b/chrome/browser/chromeos/BUILD.gn
index 3606d7b..3274c5b1 100644
--- a/chrome/browser/chromeos/BUILD.gn
+++ b/chrome/browser/chromeos/BUILD.gn
@@ -73,6 +73,7 @@
     "//chrome/browser/chromeos/power/ml/smart_dim",
     "//chrome/browser/devtools",
     "//chrome/browser/extensions",
+    "//chrome/browser/image_decoder",
     "//chrome/browser/resource_coordinator:tab_metrics_event_proto",
     "//chrome/browser/ssl:proto",
     "//chrome/browser/ui/webui/bluetooth_internals:mojo_bindings",
diff --git a/chrome/browser/chromeos/DEPS b/chrome/browser/chromeos/DEPS
index ebf3424e..8ef852e 100644
--- a/chrome/browser/chromeos/DEPS
+++ b/chrome/browser/chromeos/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+chrome/browser/image_decoder",
   # TODO(ananta): Remove this when we move files which display UI in
   # chrome/browser/chromeos to chrome/browser/ui/views/chromeos
   # crbug.com/728877
diff --git a/chrome/browser/chromeos/app_mode/kiosk_app_icon_loader.cc b/chrome/browser/chromeos/app_mode/kiosk_app_icon_loader.cc
index a1ead92..7382535 100644
--- a/chrome/browser/chromeos/app_mode/kiosk_app_icon_loader.cc
+++ b/chrome/browser/chromeos/app_mode/kiosk_app_icon_loader.cc
@@ -12,7 +12,7 @@
 #include "base/sequenced_task_runner.h"
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 
diff --git a/chrome/browser/chromeos/arc/icon_decode_request.h b/chrome/browser/chromeos/arc/icon_decode_request.h
index 7ca0a62..b151d08 100644
--- a/chrome/browser/chromeos/arc/icon_decode_request.h
+++ b/chrome/browser/chromeos/arc/icon_decode_request.h
@@ -9,7 +9,7 @@
 
 #include "base/callback.h"
 #include "base/macros.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 
 namespace gfx {
 class ImageSkia;
diff --git a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.h b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.h
index c515c1da..e5fc8a83 100644
--- a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.h
+++ b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service.h
@@ -11,7 +11,7 @@
 #include <vector>
 
 #include "base/macros.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "components/arc/mojom/wallpaper.mojom.h"
 #include "components/keyed_service/core/keyed_service.h"
 
diff --git a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
index 66b6576..4c95913 100644
--- a/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
+++ b/chrome/browser/chromeos/arc/wallpaper/arc_wallpaper_service_unittest.cc
@@ -14,7 +14,7 @@
 #include "base/macros.h"
 #include "base/memory/ptr_util.h"
 #include "chrome/browser/chromeos/login/users/fake_chrome_user_manager.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/ui/ash/test_wallpaper_controller.h"
 #include "chrome/browser/ui/ash/wallpaper_controller_client.h"
 #include "chrome/common/pref_names.h"
diff --git a/chrome/browser/chromeos/extensions/wallpaper_function_base.cc b/chrome/browser/chromeos/extensions/wallpaper_function_base.cc
index a5cc0cf..c0ec2da 100644
--- a/chrome/browser/chromeos/extensions/wallpaper_function_base.cc
+++ b/chrome/browser/chromeos/extensions/wallpaper_function_base.cc
@@ -10,7 +10,7 @@
 #include "base/synchronization/atomic_flag.h"
 #include "base/task/lazy_task_runner.h"
 #include "base/task/task_traits.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/grit/generated_resources.h"
 #include "chromeos/login/login_state/login_state.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_loader.h b/chrome/browser/chromeos/login/users/avatar/user_image_loader.h
index b48d3ba..19e7965 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_loader.h
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_loader.h
@@ -10,7 +10,7 @@
 #include "base/callback_forward.h"
 #include "base/files/file_path.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 
 namespace base {
 class SequencedTaskRunner;
diff --git a/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.h b/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.h
index fa6b597..ceca2c71 100644
--- a/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.h
+++ b/chrome/browser/chromeos/login/users/avatar/user_image_manager_test_util.h
@@ -9,7 +9,7 @@
 #include "base/files/file_path.h"
 #include "base/macros.h"
 #include "base/run_loop.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "ui/gfx/image/image_skia.h"
 
 namespace base {
diff --git a/chrome/browser/download/android/download_media_parser_bridge.h b/chrome/browser/download/android/download_media_parser_bridge.h
deleted file mode 100644
index d59b031..0000000
--- a/chrome/browser/download/android/download_media_parser_bridge.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MEDIA_PARSER_BRIDGE_H_
-#define CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MEDIA_PARSER_BRIDGE_H_
-
-#include <memory>
-
-#include "base/android/scoped_java_ref.h"
-#include "base/macros.h"
-#include "base/single_thread_task_runner.h"
-#include "chrome/browser/download/android/download_media_parser.h"
-
-class DownloadMediaParser;
-
-// The JNI bridge that uses DownloadMediaParser to parse local media file. The
-// bridge is owned by the Java side.
-class DownloadMediaParserBridge {
- public:
-  DownloadMediaParserBridge(
-      const std::string& mime_type,
-      const base::FilePath& file_path,
-      DownloadMediaParser::ParseCompleteCB parse_complete_cb);
-  ~DownloadMediaParserBridge();
-
-  void Destroy(JNIEnv* env, jobject obj);
-  void Start(JNIEnv* env, jobject obj);
-
- private:
-  // The media parser that does actual jobs in a sandboxed process.
-  std::unique_ptr<DownloadMediaParser> parser_;
-  DownloadMediaParser::ParseCompleteCB parse_complete_cb_;
-
-  DISALLOW_COPY_AND_ASSIGN(DownloadMediaParserBridge);
-};
-
-#endif  // CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MEDIA_PARSER_BRIDGE_H_
diff --git a/chrome/browser/download/download_commands.cc b/chrome/browser/download/download_commands.cc
index 671936f..d255335 100644
--- a/chrome/browser/download/download_commands.cc
+++ b/chrome/browser/download/download_commands.cc
@@ -18,7 +18,7 @@
 #include "chrome/browser/browser_process.h"
 #include "chrome/browser/download/download_crx_util.h"
 #include "chrome/browser/download/download_ui_model.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/profiles/profile_manager.h"
 #include "chrome/common/url_constants.h"
 #include "components/google/core/common/google_util.h"
diff --git a/chrome/browser/download/download_offline_content_provider.cc b/chrome/browser/download/download_offline_content_provider.cc
index 4800113..f583397 100644
--- a/chrome/browser/download/download_offline_content_provider.cc
+++ b/chrome/browser/download/download_offline_content_provider.cc
@@ -12,10 +12,10 @@
 #include "base/time/time.h"
 #include "build/build_config.h"
 #include "chrome/browser/browser_process.h"
-#include "chrome/browser/download/image_thumbnail_request.h"
 #include "chrome/browser/download/offline_item_utils.h"
 #include "chrome/browser/offline_items_collection/offline_content_aggregator_factory.h"
 #include "chrome/browser/profiles/profile.h"
+#include "chrome/browser/thumbnail/generator/image_thumbnail_request.h"
 #include "components/download/public/common/download_item.h"
 #include "content/public/browser/browser_context.h"
 #include "third_party/skia/include/core/SkBitmap.h"
diff --git a/chrome/browser/download/download_stats.cc b/chrome/browser/download/download_stats.cc
index 1b58b69b..aff3077 100644
--- a/chrome/browser/download/download_stats.cc
+++ b/chrome/browser/download/download_stats.cc
@@ -65,19 +65,3 @@
                             DownloadShelfDragEvent::COUNT);
 }
 
-#if defined(OS_ANDROID)
-void RecordMediaParserEvent(MediaParserEvent event) {
-  UMA_HISTOGRAM_ENUMERATION("Download.MediaParser.Event", event,
-                            MediaParserEvent::kCount);
-}
-
-void RecordMediaMetadataEvent(MediaMetadataEvent event) {
-  UMA_HISTOGRAM_ENUMERATION("Download.MediaMetadata.Event", event,
-                            MediaMetadataEvent::kCount);
-}
-
-void RecordVideoThumbnailEvent(VideoThumbnailEvent event) {
-  UMA_HISTOGRAM_ENUMERATION("Download.VideoThumbnail.Event", event,
-                            VideoThumbnailEvent::kCount);
-}
-#endif
diff --git a/chrome/browser/download/download_stats.h b/chrome/browser/download/download_stats.h
index 81fadd3..d2f7b934 100644
--- a/chrome/browser/download/download_stats.h
+++ b/chrome/browser/download/download_stats.h
@@ -135,68 +135,4 @@
 
 void RecordDownloadShelfDragEvent(DownloadShelfDragEvent drag_event);
 
-#if defined(OS_ANDROID)
-// Tracks media parser events. Each media parser hubs IPC channels for local
-// media analysis tasks. Used in UMA, do not remove, change or reuse existing
-// entries.
-enum class MediaParserEvent {
-  // Started to initialize the media parser.
-  kInitialize = 0,
-  // The mime type is not supported by the media parser.
-  kUnsupportedMimeType = 1,
-  // Failed to read the local media file.
-  kReadFileError = 2,
-  // Utility process connection error.
-  kUtilityConnectionError = 3,
-  // GPU process connection error.
-  kGpuConnectionError = 4,
-  // Failed to parse metadata.
-  kMetadataFailed = 5,
-  // Failed to retrieve video thumbnail.
-  kVideoThumbnailFailed = 6,
-  // Failed to parse media file, aggregation of all failure reasons.
-  kFailure = 7,
-  // Media file successfully parsed.
-  kSuccess = 8,
-  // Time out and failed.
-  kTimeout = 9,
-  kCount
-};
-
-// Tracks local media metadata requests. Used in UMA, do not remove, change or
-// reuse existing entries.
-enum class MediaMetadataEvent {
-  // Started to retrieve metadata.
-  kMetadataStart = 0,
-  // Failed to retrieve metadata.
-  kMetadataFailed = 1,
-  // Completed to retrieve metadata.
-  kMetadataComplete = 2,
-  kCount
-};
-
-// Tracks video thumbnail requests. Used in UMA, do not remove, change or
-// reuse existing entries.
-enum class VideoThumbnailEvent {
-  kVideoThumbnailStart = 0,
-  // Failed to extract video frame.
-  kVideoFrameExtractionFailed = 1,
-  // Failed to decode video frame.
-  kVideoDecodeFailed = 2,
-  // Completed to retrieve video thumbnail.
-  kVideoThumbnailComplete = 3,
-  kCount
-};
-
-// Records download media parser event.
-void RecordMediaParserEvent(MediaParserEvent event);
-
-// Records media metadata parsing events.
-void RecordMediaMetadataEvent(MediaMetadataEvent event);
-
-// Records video thumbnail retrieval events.
-void RecordVideoThumbnailEvent(VideoThumbnailEvent event);
-
-#endif
-
 #endif  // CHROME_BROWSER_DOWNLOAD_DOWNLOAD_STATS_H_
diff --git a/chrome/browser/download/notification/download_item_notification.h b/chrome/browser/download/notification/download_item_notification.h
index 1c7cd936..4fbc44b 100644
--- a/chrome/browser/download/notification/download_item_notification.h
+++ b/chrome/browser/download/notification/download_item_notification.h
@@ -12,7 +12,7 @@
 #include "base/strings/string_number_conversions.h"
 #include "chrome/browser/download/download_commands.h"
 #include "chrome/browser/download/download_ui_model.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/ui/browser.h"
 #include "components/download/public/common/download_item.h"
 #include "components/offline_items_collection/core/offline_item.h"
diff --git a/chrome/browser/extensions/BUILD.gn b/chrome/browser/extensions/BUILD.gn
index 0575bcb..bd78ed6 100644
--- a/chrome/browser/extensions/BUILD.gn
+++ b/chrome/browser/extensions/BUILD.gn
@@ -790,6 +790,7 @@
     "//chrome/browser:theme_properties",
     "//chrome/browser/devtools",
     "//chrome/browser/engagement:mojo_bindings",
+    "//chrome/browser/image_decoder",
     "//chrome/browser/media/router",
     "//chrome/browser/media/router/discovery",
     "//chrome/browser/resource_coordinator:mojo_bindings",
diff --git a/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc b/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc
index e1dc2a1..7f8a047f 100644
--- a/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc
+++ b/chrome/browser/extensions/clipboard_extension_helper_chromeos.cc
@@ -11,7 +11,7 @@
 #include "base/strings/string_util.h"
 #include "base/strings/utf_string_conversions.h"
 #include "base/synchronization/atomic_flag.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/base/clipboard/scoped_clipboard_writer.h"
 
diff --git a/chrome/browser/image_decoder/BUILD.gn b/chrome/browser/image_decoder/BUILD.gn
new file mode 100644
index 0000000..068448f
--- /dev/null
+++ b/chrome/browser/image_decoder/BUILD.gn
@@ -0,0 +1,45 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+import("//build/util/version.gni")
+
+source_set("image_decoder") {
+  deps = [
+    "//base",
+    "//content/public/browser",
+    "//ipc",
+    "//services/data_decoder/public/cpp",
+    "//services/service_manager/public/cpp",
+    "//skia",
+    "//ui/gfx",
+  ]
+
+  sources = [
+    "image_decoder.cc",
+    "image_decoder.h",
+  ]
+}
+
+if (!is_android) {
+  source_set("browser_tests") {
+    testonly = true
+
+    configs += [ "//build/config:precompiled_headers" ]
+    defines = [
+      "HAS_OUT_OF_PROC_TEST_RUNNER",
+      "CHROME_VERSION_MAJOR=" + chrome_version_major,
+    ]
+
+    deps = [
+      "//base",
+      "//chrome/app:generated_resources",
+      "//chrome/test:test_support",
+      "//content/public/browser",
+      "//content/test:test_support",
+      "//ui/base",
+    ]
+
+    sources = [ "image_decoder_browsertest.cc" ]
+  }
+}
diff --git a/chrome/browser/image_decoder/DEPS b/chrome/browser/image_decoder/DEPS
new file mode 100644
index 0000000..da0e266
--- /dev/null
+++ b/chrome/browser/image_decoder/DEPS
@@ -0,0 +1,16 @@
+noparent = True
+
+include_rules = [
+  "+base",
+  "+build/build_config.h",
+  "+chrome/grit/generated_resources.h",
+  "+chrome/test",
+  "+content/public/browser",
+  "+content/public/test",
+  "+ipc",
+  "+services/data_decoder/public/cpp",
+  "+services/service_manager/public/cpp",
+  "+third_party/skia/include/core",
+  "+ui/base",
+  "+ui/gfx/geometry",
+]
\ No newline at end of file
diff --git a/chrome/browser/image_decoder/OWNERS b/chrome/browser/image_decoder/OWNERS
new file mode 100644
index 0000000..0fb1cd4
--- /dev/null
+++ b/chrome/browser/image_decoder/OWNERS
@@ -0,0 +1,3 @@
+file://chrome/browser/OWNERS
+
+# COMPONENT: UI>Browser
\ No newline at end of file
diff --git a/chrome/browser/image_decoder.cc b/chrome/browser/image_decoder/image_decoder.cc
similarity index 94%
rename from chrome/browser/image_decoder.cc
rename to chrome/browser/image_decoder/image_decoder.cc
index 191ff6a..ec67ab3 100644
--- a/chrome/browser/image_decoder.cc
+++ b/chrome/browser/image_decoder/image_decoder.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 
 #include <utility>
 
@@ -63,17 +63,17 @@
 
 ImageDecoder::ImageRequest::ImageRequest()
     : task_runner_(base::ThreadTaskRunnerHandle::Get()) {
-  DCHECK(sequence_checker_.CalledOnValidSequence());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
 ImageDecoder::ImageRequest::ImageRequest(
     const scoped_refptr<base::SequencedTaskRunner>& task_runner)
     : task_runner_(task_runner) {
-  DCHECK(sequence_checker_.CalledOnValidSequence());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
 }
 
 ImageDecoder::ImageRequest::~ImageRequest() {
-  DCHECK(sequence_checker_.CalledOnValidSequence());
+  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
   ImageDecoder::Cancel(this);
 }
 
@@ -180,9 +180,8 @@
   }
 }
 
-void ImageDecoder::OnDecodeImageSucceeded(
-    const SkBitmap& decoded_image,
-    int request_id) {
+void ImageDecoder::OnDecodeImageSucceeded(const SkBitmap& decoded_image,
+                                          int request_id) {
   ImageRequest* image_request;
   {
     base::AutoLock lock(map_lock_);
diff --git a/chrome/browser/image_decoder.h b/chrome/browser/image_decoder/image_decoder.h
similarity index 91%
rename from chrome/browser/image_decoder.h
rename to chrome/browser/image_decoder/image_decoder.h
index 2a0d322..26fad3c 100644
--- a/chrome/browser/image_decoder.h
+++ b/chrome/browser/image_decoder/image_decoder.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_IMAGE_DECODER_H_
-#define CHROME_BROWSER_IMAGE_DECODER_H_
+#ifndef CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_
+#define CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_
 
 #include <map>
 #include <string>
@@ -64,15 +64,15 @@
     // the image has been decoded.
     const scoped_refptr<base::SequencedTaskRunner> task_runner_;
 
-    base::SequenceChecker sequence_checker_;
+    SEQUENCE_CHECKER(sequence_checker_);
   };
 
   enum ImageCodec {
     DEFAULT_CODEC = 0,  // Uses WebKit image decoding (via WebImage).
 #if defined(OS_CHROMEOS)
     ROBUST_JPEG_CODEC,  // Restrict decoding to robust jpeg codec.
-    ROBUST_PNG_CODEC,  // Restrict decoding to robust PNG codec.
-#endif  // defined(OS_CHROMEOS)
+    ROBUST_PNG_CODEC,   // Restrict decoding to robust PNG codec.
+#endif                  // defined(OS_CHROMEOS)
   };
 
   static ImageDecoder* GetInstance();
@@ -82,8 +82,7 @@
   static void Start(ImageRequest* image_request,
                     std::vector<uint8_t> image_data);
   // Deprecated. Use std::vector<uint8_t> version to avoid an extra copy.
-  static void Start(ImageRequest* image_request,
-                    const std::string& image_data);
+  static void Start(ImageRequest* image_request, const std::string& image_data);
 
   // Starts asynchronous image decoding. Once finished, the callback will be
   // posted back to image_request's |task_runner_|.
@@ -137,4 +136,4 @@
   DISALLOW_COPY_AND_ASSIGN(ImageDecoder);
 };
 
-#endif  // CHROME_BROWSER_IMAGE_DECODER_H_
+#endif  // CHROME_BROWSER_IMAGE_DECODER_IMAGE_DECODER_H_
diff --git a/chrome/browser/image_decoder_browsertest.cc b/chrome/browser/image_decoder/image_decoder_browsertest.cc
similarity index 80%
rename from chrome/browser/image_decoder_browsertest.cc
rename to chrome/browser/image_decoder/image_decoder_browsertest.cc
index b8979ac..b095a40 100644
--- a/chrome/browser/image_decoder_browsertest.cc
+++ b/chrome/browser/image_decoder/image_decoder_browsertest.cc
@@ -2,9 +2,10 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 
 #include "base/macros.h"
+#include "base/run_loop.h"
 #include "build/build_config.h"
 #include "chrome/grit/generated_resources.h"
 #include "chrome/test/base/in_process_browser_test.h"
@@ -79,9 +80,7 @@
     Quit();
   }
 
-  void OnDecodeImageFailed() override {
-    Quit();
-  }
+  void OnDecodeImageFailed() override { Quit(); }
 
   void Quit() {
     EXPECT_FALSE(quit_called_);
@@ -100,75 +99,68 @@
 
 }  // namespace
 
-class ImageDecoderBrowserTest : public InProcessBrowserTest {
-};
+class ImageDecoderBrowserTest : public InProcessBrowserTest {};
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, Basic) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  TestImageRequest test_request(runner->QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   ImageDecoder::Start(&test_request, std::vector<uint8_t>());
-  runner->Run();
+  run_loop.Run();
   EXPECT_FALSE(test_request.decode_succeeded());
 }
 
 #if defined(OS_CHROMEOS)
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecodeWithOptionsString) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  TestImageRequest test_request(runner->QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   const std::vector<uint8_t> data = GetValidPngData();
   ImageDecoder::StartWithOptions(&test_request,
                                  std::string(data.begin(), data.end()),
                                  ImageDecoder::ROBUST_PNG_CODEC,
                                  /*shrink_to_fit=*/false);
-  runner->Run();
+  run_loop.Run();
   EXPECT_TRUE(test_request.decode_succeeded());
 }
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustJpegCodecWithJpegData) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  TestImageRequest test_request(runner->QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   ImageDecoder::StartWithOptions(
       &test_request, GetValidJpgData(), ImageDecoder::ROBUST_JPEG_CODEC,
       /*shrink_to_fit=*/false, /*desired_image_frame_size=*/gfx::Size());
-  runner->Run();
+  run_loop.Run();
   EXPECT_TRUE(test_request.decode_succeeded());
 }
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustJpegCodecWithPngData) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  TestImageRequest test_request(runner->QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   ImageDecoder::StartWithOptions(
       &test_request, GetValidPngData(), ImageDecoder::ROBUST_JPEG_CODEC,
       /*shrink_to_fit=*/false, /*desired_image_frame_size=*/gfx::Size());
-  runner->Run();
+  run_loop.Run();
   // Should fail with PNG data because only JPEG data is allowed.
   EXPECT_FALSE(test_request.decode_succeeded());
 }
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustPngCodecWithPngData) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  TestImageRequest test_request(runner->QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   ImageDecoder::StartWithOptions(
       &test_request, GetValidPngData(), ImageDecoder::ROBUST_PNG_CODEC,
       /*shrink_to_fit=*/false, /*desired_image_frame_size=*/gfx::Size());
-  runner->Run();
+  run_loop.Run();
   EXPECT_TRUE(test_request.decode_succeeded());
 }
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, RobustPngCodecWithJpegData) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  TestImageRequest test_request(runner->QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   ImageDecoder::StartWithOptions(
       &test_request, GetValidJpgData(), ImageDecoder::ROBUST_PNG_CODEC,
       /*shrink_to_fit=*/false, /*desired_image_frame_size=*/gfx::Size());
-  runner->Run();
+  run_loop.Run();
   // Should fail with JPEG data because only PNG data is allowed.
   EXPECT_FALSE(test_request.decode_succeeded());
 }
@@ -176,20 +168,19 @@
 #endif  // defined(OS_CHROMEOS)
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecode) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
-  TestImageRequest test_request(runner->QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   ImageDecoder::Start(&test_request, GetValidPngData());
-  runner->Run();
+  run_loop.Run();
   EXPECT_TRUE(test_request.decode_succeeded());
 }
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecodeString) {
-  base::RunLoop runner;
-  TestImageRequest test_request(runner.QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   const std::vector<uint8_t> data = GetValidPngData();
   ImageDecoder::Start(&test_request, std::string(data.begin(), data.end()));
-  runner.Run();
+  run_loop.Run();
   EXPECT_TRUE(test_request.decode_succeeded());
   EXPECT_EQ(test_request.get_bitmap().height(), 1);
   EXPECT_EQ(test_request.get_bitmap().width(), 1);
@@ -197,11 +188,11 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, BasicDecodeStringJpeg) {
-  base::RunLoop runner;
-  TestImageRequest test_request(runner.QuitClosure());
+  base::RunLoop run_loop;
+  TestImageRequest test_request(run_loop.QuitClosure());
   const std::vector<uint8_t> data = GetValidJpgData();
   ImageDecoder::Start(&test_request, std::string(data.begin(), data.end()));
-  runner.Run();
+  run_loop.Run();
   EXPECT_TRUE(test_request.decode_succeeded());
   EXPECT_EQ(test_request.get_bitmap().height(), 1);
   EXPECT_EQ(test_request.get_bitmap().width(), 1);
@@ -209,11 +200,10 @@
 }
 
 IN_PROC_BROWSER_TEST_F(ImageDecoderBrowserTest, StartAndDestroy) {
-  scoped_refptr<content::MessageLoopRunner> runner =
-      new content::MessageLoopRunner;
+  base::RunLoop run_loop;
   std::unique_ptr<TestImageRequest> test_request(
-      new TestImageRequest(runner->QuitClosure()));
+      new TestImageRequest(run_loop.QuitClosure()));
   ImageDecoder::Start(test_request.get(), std::vector<uint8_t>());
   test_request.reset();
-  runner->Run();
+  run_loop.Run();
 }
diff --git a/chrome/browser/image_fetcher/image_decoder_impl.h b/chrome/browser/image_fetcher/image_decoder_impl.h
index a242838f..d8463a2 100644
--- a/chrome/browser/image_fetcher/image_decoder_impl.h
+++ b/chrome/browser/image_fetcher/image_decoder_impl.h
@@ -8,7 +8,7 @@
 #include <memory>
 #include <vector>
 
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "components/image_fetcher/core/image_decoder.h"
 
 // image_fetcher::ImageDecoder implementation.
diff --git a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
index 574a45c..e41d393f 100644
--- a/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
+++ b/chrome/browser/media_galleries/fileapi/supported_image_type_validator.cc
@@ -18,7 +18,7 @@
 #include "base/task/post_task.h"
 #include "base/task/task_traits.h"
 #include "base/threading/scoped_blocking_call.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "content/public/browser/browser_thread.h"
 
 using content::BrowserThread;
diff --git a/chrome/browser/profiles/profile_downloader.h b/chrome/browser/profiles/profile_downloader.h
index 5a83589..d04312ef0 100644
--- a/chrome/browser/profiles/profile_downloader.h
+++ b/chrome/browser/profiles/profile_downloader.h
@@ -13,7 +13,7 @@
 #include "base/scoped_observer.h"
 #include "base/sequence_checker.h"
 #include "base/strings/string16.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "components/signin/public/identity_manager/account_info.h"
 #include "components/signin/public/identity_manager/identity_manager.h"
 #include "services/network/public/cpp/simple_url_loader.h"
diff --git a/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h b/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h
index 3739836..ad10c7d 100644
--- a/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h
+++ b/chrome/browser/sharing/shared_clipboard/remote_copy_message_handler.h
@@ -12,7 +12,7 @@
 #include "base/macros.h"
 #include "base/strings/string16.h"
 #include "base/timer/elapsed_timer.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/sharing/shared_clipboard/remote_copy_handle_message_result.h"
 #include "chrome/browser/sharing/sharing_message_handler.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/thumbnail/BUILD.gn b/chrome/browser/thumbnail/BUILD.gn
new file mode 100644
index 0000000..2388bac
--- /dev/null
+++ b/chrome/browser/thumbnail/BUILD.gn
@@ -0,0 +1,48 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_android) {
+  import("//build/config/android/config.gni")
+  import("//build/config/android/rules.gni")
+  import("//third_party/protobuf/proto_library.gni")
+}
+
+group("thumbnail") {
+  public_deps = [ "//chrome/browser/thumbnail/generator" ]
+
+  if (is_android) {
+    public_deps += [ "//chrome/browser/thumbnail/cc" ]
+  }
+}
+
+if (is_android) {
+  java_group("java") {
+    deps = [ "//chrome/browser/thumbnail/generator:java" ]
+  }
+
+  group("unit_tests") {
+    testonly = true
+
+    deps = [ "//chrome/browser/thumbnail/cc:unit_tests" ]
+  }
+
+  java_group("javatests") {
+    testonly = true
+
+    deps = [ "//chrome/browser/thumbnail/generator:javatests" ]
+  }
+
+  java_group("thumbnail_java_test_support") {
+    testonly = true
+
+    deps =
+        [ "//chrome/browser/thumbnail/generator:generator_java_test_support" ]
+  }
+
+  group("test_support") {
+    testonly = true
+
+    public_deps = [ "//chrome/browser/thumbnail/generator:test_support" ]
+  }
+}
diff --git a/chrome/browser/thumbnail/DEPS b/chrome/browser/thumbnail/DEPS
new file mode 100644
index 0000000..a7a41dfc
--- /dev/null
+++ b/chrome/browser/thumbnail/DEPS
@@ -0,0 +1,32 @@
+noparent = True
+
+include_rules = [
+  "+base",
+  "+build/build_config.h",
+  "+cc",
+  "+cc/resources",
+  "+chrome/browser/image_decoder",
+  "+chrome/browser/util/android",
+  "+chrome/common",
+  "+chrome/grit/generated_resources.h",
+  "+chrome/services/media_gallery_util/public",
+  "+chrome/test",
+  "+content/public/android/java/src/org/chromium/content_public",
+  "+content/public/browser",
+  "+content/public/test",
+  "+gpu/config",
+  "+ipc",
+  "+media",
+  "+mojo/public",
+  "+net",
+  "+services/data_decoder/public",
+  "+services/service_manager/public",
+  "+services/viz/public",
+  "+skia",
+  "+testing/gmock",
+  "+testing/gtest",
+  "+third_party/android_opengl/etc1",
+  "+third_party/skia/include",
+  "+ui",
+  "+url",
+]
\ No newline at end of file
diff --git a/chrome/browser/thumbnail/OWNERS b/chrome/browser/thumbnail/OWNERS
new file mode 100644
index 0000000..c38b7ccb
--- /dev/null
+++ b/chrome/browser/thumbnail/OWNERS
@@ -0,0 +1,4 @@
[email protected]
[email protected]
+
+# COMPONENT: UI>Browser>Thumbnail
\ No newline at end of file
diff --git a/chrome/browser/thumbnail/cc/BUILD.gn b/chrome/browser/thumbnail/cc/BUILD.gn
new file mode 100644
index 0000000..9d20cff
--- /dev/null
+++ b/chrome/browser/thumbnail/cc/BUILD.gn
@@ -0,0 +1,46 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_android) {
+  import("//build/config/android/config.gni")
+  import("//build/config/android/rules.gni")
+  import("//third_party/protobuf/proto_library.gni")
+}
+
+source_set("cc") {
+  deps = [
+    "//base",
+    "//cc",
+    "//chrome/browser/image_decoder",
+    "//chrome/common",
+    "//chrome/services/media_gallery_util/public/cpp",
+    "//chrome/services/media_gallery_util/public/mojom",
+    "//content/public/browser",
+    "//media",
+    "//mojo/public/cpp/bindings",
+    "//skia",
+    "//ui/gfx",
+  ]
+
+  sources = [
+    "scoped_ptr_expiring_cache.h",
+    "thumbnail.cc",
+    "thumbnail.h",
+    "thumbnail_cache.cc",
+    "thumbnail_cache.h",
+  ]
+}
+
+source_set("unit_tests") {
+  testonly = true
+
+  deps = [
+    ":cc",
+    "//base",
+    "//testing/gmock",
+    "//testing/gtest",
+  ]
+
+  sources = [ "scoped_ptr_expiring_cache_unittest.cc" ]
+}
diff --git a/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h b/chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache.h
similarity index 85%
rename from chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h
rename to chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache.h
index 8acf9c03..7ff84d8 100644
--- a/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h
+++ b/chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache.h
@@ -1,9 +1,9 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_THUMBNAIL_SCOPED_PTR_EXPIRING_CACHE_H_
-#define CHROME_BROWSER_ANDROID_THUMBNAIL_SCOPED_PTR_EXPIRING_CACHE_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_CC_SCOPED_PTR_EXPIRING_CACHE_H_
+#define CHROME_BROWSER_THUMBNAIL_CC_SCOPED_PTR_EXPIRING_CACHE_H_
 
 #include <stddef.h>
 
@@ -35,7 +35,7 @@
     iterator iter = map_.find(key);
     if (iter != map_.end())
       return iter->second;
-    return NULL;
+    return nullptr;
   }
 
   std::unique_ptr<Value> Remove(const Key& key) {
@@ -75,4 +75,4 @@
   DISALLOW_COPY_AND_ASSIGN(ScopedPtrExpiringCache);
 };
 
-#endif  // CHROME_BROWSER_ANDROID_THUMBNAIL_SCOPED_PTR_EXPIRING_CACHE_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_CC_SCOPED_PTR_EXPIRING_CACHE_H_
diff --git a/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc b/chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache_unittest.cc
similarity index 90%
rename from chrome/browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc
rename to chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache_unittest.cc
index 9ad9a23..d2a3b5c 100644
--- a/chrome/browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc
+++ b/chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache_unittest.cc
@@ -1,8 +1,8 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h"
+#include "chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache.h"
 
 #include <stddef.h>
 
@@ -84,7 +84,7 @@
   EXPECT_EQ(0u, cache.size());
 
   for (unsigned int i = 0; i < MAX_CACHE_SIZE + 1; i++) {
-    EXPECT_EQ(NULL, cache.Get(i));
+    EXPECT_EQ(nullptr, cache.Get(i));
   }
 }
 
@@ -103,22 +103,22 @@
   EXPECT_EQ(GenerateValue(next_key), cache.Get(next_key)->value());
 
   // The first inserted entry should have been evicted.
-  EXPECT_EQ(NULL, cache.Get(0));
+  EXPECT_EQ(nullptr, cache.Get(0));
 
   // The rest of the content should be present.
   for (unsigned int i = 1; i < MAX_CACHE_SIZE; i++) {
-    EXPECT_TRUE(cache.Get(i) != NULL);
+    EXPECT_TRUE(cache.Get(i) != nullptr);
   }
 
   next_key++;
 
   // The first candidate to be evicted is the head of the iterator.
   unsigned int head_key = cache.begin()->first;
-  EXPECT_TRUE(cache.Get(head_key) != NULL);
+  EXPECT_TRUE(cache.Get(head_key) != nullptr);
   cache.Put(next_key, MockObject::Create(next_key));
 
   EXPECT_NE(cache.begin()->first, head_key);
-  EXPECT_EQ(NULL, cache.Get(head_key));
+  EXPECT_EQ(nullptr, cache.Get(head_key));
 }
 
 TEST_F(ScopedPtrExpiringCacheTest, RetainedEntry) {
@@ -129,7 +129,7 @@
 
   // Add (cache size - 1)-entries.
   for (unsigned int i = 0; i < MAX_CACHE_SIZE; i++) {
-    EXPECT_TRUE(cache.Get(i) != NULL);
+    EXPECT_TRUE(cache.Get(i) != nullptr);
   }
 
   for (unsigned int i = MAX_CACHE_SIZE; i < 2 * MAX_CACHE_SIZE - 1; i++) {
@@ -139,12 +139,12 @@
   EXPECT_EQ(MAX_CACHE_SIZE, cache.size());
 
   for (unsigned int i = 0; i < MAX_CACHE_SIZE - 1; i++) {
-    EXPECT_EQ(NULL, cache.Get(i));
+    EXPECT_EQ(nullptr, cache.Get(i));
   }
 
   // The only retained entry (from the first round of insertion) is the last to
   // be inserted.
-  EXPECT_TRUE(cache.Get(MAX_CACHE_SIZE - 1) != NULL);
+  EXPECT_TRUE(cache.Get(MAX_CACHE_SIZE - 1) != nullptr);
 }
 
 // Test that the iterator order is the insertion order.  The first element of
diff --git a/chrome/browser/android/thumbnail/thumbnail.cc b/chrome/browser/thumbnail/cc/thumbnail.cc
similarity index 96%
rename from chrome/browser/android/thumbnail/thumbnail.cc
rename to chrome/browser/thumbnail/cc/thumbnail.cc
index 3ead7a3..256ef57 100644
--- a/chrome/browser/android/thumbnail/thumbnail.cc
+++ b/chrome/browser/thumbnail/cc/thumbnail.cc
@@ -1,8 +1,8 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/thumbnail/thumbnail.h"
+#include "chrome/browser/thumbnail/cc/thumbnail.h"
 
 #include "base/bind.h"
 #include "base/location.h"
diff --git a/chrome/browser/android/thumbnail/thumbnail.h b/chrome/browser/thumbnail/cc/thumbnail.h
similarity index 90%
rename from chrome/browser/android/thumbnail/thumbnail.h
rename to chrome/browser/thumbnail/cc/thumbnail.h
index b7c2c27..743586b 100644
--- a/chrome/browser/android/thumbnail/thumbnail.h
+++ b/chrome/browser/thumbnail/cc/thumbnail.h
@@ -1,9 +1,9 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_THUMBNAIL_THUMBNAIL_H_
-#define CHROME_BROWSER_ANDROID_THUMBNAIL_THUMBNAIL_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_CC_THUMBNAIL_H_
+#define CHROME_BROWSER_THUMBNAIL_CC_THUMBNAIL_H_
 
 #include "base/macros.h"
 #include "base/memory/weak_ptr.h"
@@ -90,4 +90,4 @@
   DISALLOW_COPY_AND_ASSIGN(Thumbnail);
 };
 
-#endif  // CHROME_BROWSER_ANDROID_THUMBNAIL_THUMBNAIL_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_CC_THUMBNAIL_H_
diff --git a/chrome/browser/android/thumbnail/thumbnail_cache.cc b/chrome/browser/thumbnail/cc/thumbnail_cache.cc
similarity index 87%
rename from chrome/browser/android/thumbnail/thumbnail_cache.cc
rename to chrome/browser/thumbnail/cc/thumbnail_cache.cc
index 4f7e3e0..fda756f 100644
--- a/chrome/browser/android/thumbnail/thumbnail_cache.cc
+++ b/chrome/browser/thumbnail/cc/thumbnail_cache.cc
@@ -1,8 +1,8 @@
-// Copyright 2014 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/thumbnail/thumbnail_cache.h"
+#include "chrome/browser/thumbnail/cc/thumbnail_cache.h"
 
 #include <algorithm>
 #include <cmath>
@@ -20,7 +20,6 @@
 #include "base/task/post_task.h"
 #include "base/time/time.h"
 #include "build/build_config.h"
-#include "chrome/browser/flags/android/chrome_feature_list.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "gpu/config/gpu_finch_features.h"
@@ -79,7 +78,7 @@
                      RoundUpMod4(bitmap_size.height()));
 }
 
-template<typename T>
+template <typename T>
 bool ReadBigEndianFromFile(base::File& file, T* out) {
   char buffer[sizeof(T)];
   if (file.ReadAtCurrentPos(buffer, sizeof(T)) != sizeof(T))
@@ -88,7 +87,7 @@
   return true;
 }
 
-template<typename T>
+template <typename T>
 bool WriteBigEndianToFile(base::File& file, T val) {
   char buffer[sizeof(T)];
   base::WriteBigEndian(buffer, val);
@@ -133,9 +132,11 @@
                                size_t compression_queue_max_size,
                                size_t write_queue_max_size,
                                bool use_approximation_thumbnail,
-                               bool save_jpeg_thumbnails)
+                               bool save_jpeg_thumbnails,
+                               double jpeg_aspect_ratio)
     : file_sequenced_task_runner_(base::CreateSequencedTaskRunner(
           {base::ThreadPool(), base::MayBlock()})),
+      jpeg_aspect_ratio_(jpeg_aspect_ratio),
       compression_queue_max_size_(compression_queue_max_size),
       write_queue_max_size_(write_queue_max_size),
       use_approximation_thumbnail_(use_approximation_thumbnail),
@@ -351,8 +352,7 @@
 
 void ThumbnailCache::DecompressThumbnailFromFile(
     TabId tab_id,
-    const base::Callback<void(bool, SkBitmap)>&
-        post_decompress_callback) {
+    const base::Callback<void(bool, SkBitmap)>& post_decompress_callback) {
   base::Callback<void(bool, SkBitmap)> transcoding_callback =
       post_decompress_callback;
   if (save_jpeg_thumbnails_) {
@@ -428,18 +428,18 @@
       base::Bind(&ThumbnailCache::WriteJpegThumbnailIfNecessary,
                  weak_factory_.GetWeakPtr(), tab_id);
 
-  base::PostTask(FROM_HERE,
-                 {base::ThreadPool(), base::TaskPriority::BEST_EFFORT,
-                  base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
-                 base::BindOnce(&ThumbnailCache::JpegProcessingTask, bitmap,
-                                post_jpeg_compression_task));
+  base::PostTask(
+      FROM_HERE,
+      {base::ThreadPool(), base::TaskPriority::BEST_EFFORT,
+       base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN},
+      base::BindOnce(&ThumbnailCache::JpegProcessingTask, jpeg_aspect_ratio_,
+                     bitmap, post_jpeg_compression_task));
 }
 
-void ThumbnailCache::CompressThumbnailIfNecessary(
-    TabId tab_id,
-    const base::Time& time_stamp,
-    const SkBitmap& bitmap,
-    float scale) {
+void ThumbnailCache::CompressThumbnailIfNecessary(TabId tab_id,
+                                                  const base::Time& time_stamp,
+                                                  const SkBitmap& bitmap,
+                                                  float scale) {
   if (compression_tasks_count_ >= compression_queue_max_size_) {
     RemoveOnMatchedTimeStamp(tab_id, time_stamp);
     return;
@@ -448,11 +448,9 @@
   compression_tasks_count_++;
 
   base::Callback<void(sk_sp<SkPixelRef>, const gfx::Size&)>
-      post_compression_task = base::Bind(&ThumbnailCache::PostCompressionTask,
-                                         weak_factory_.GetWeakPtr(),
-                                         tab_id,
-                                         time_stamp,
-                                         scale);
+      post_compression_task =
+          base::Bind(&ThumbnailCache::PostCompressionTask,
+                     weak_factory_.GetWeakPtr(), tab_id, time_stamp, scale);
 
   gfx::Size raw_data_size(bitmap.width(), bitmap.height());
   gfx::Size encoded_size = GetEncodedSize(
@@ -477,8 +475,8 @@
   read_in_progress_ = true;
 
   base::Callback<void(sk_sp<SkPixelRef>, float, const gfx::Size&)>
-      post_read_task = base::Bind(
-          &ThumbnailCache::PostReadTask, weak_factory_.GetWeakPtr(), tab_id);
+      post_read_task = base::Bind(&ThumbnailCache::PostReadTask,
+                                  weak_factory_.GetWeakPtr(), tab_id);
 
   file_sequenced_task_runner_->PostTask(
       FROM_HERE,
@@ -506,8 +504,7 @@
   if (!found_key_to_remove) {
     // 2. Find the least important id we can remove.
     for (TabIdList::reverse_iterator riter = visible_ids_.rbegin();
-         riter != visible_ids_.rend();
-         riter++) {
+         riter != visible_ids_.rend(); riter++) {
       if (cache_.Get(*riter)) {
         key_to_remove = *riter;
         found_key_to_remove = true;
@@ -598,8 +595,7 @@
 
   int data_size = etc1_get_encoded_data_size(width, height);
   int pixel_bytes_written = file.WriteAtCurrentPos(
-      reinterpret_cast<char*>(compressed_data->pixels()),
-      data_size);
+      reinterpret_cast<char*>(compressed_data->pixels()), data_size);
   if (pixel_bytes_written != data_size)
     return false;
 
@@ -626,10 +622,7 @@
   base::File file(file_path,
                   base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_WRITE);
 
-  bool success = WriteToFile(file,
-                             content_size,
-                             scale,
-                             compressed_data);
+  bool success = WriteToFile(file, content_size, scale, compressed_data);
 
   file.Close();
 
@@ -685,23 +678,18 @@
 
     size_t encoded_bytes =
         etc1_get_encoded_data_size(encoded_size.width(), encoded_size.height());
-    SkImageInfo info = SkImageInfo::Make(encoded_size.width(),
-                                         encoded_size.height(),
-                                         kUnknown_SkColorType,
-                                         kUnpremul_SkAlphaType);
+    SkImageInfo info =
+        SkImageInfo::Make(encoded_size.width(), encoded_size.height(),
+                          kUnknown_SkColorType, kUnpremul_SkAlphaType);
     sk_sp<SkData> etc1_pixel_data(SkData::MakeUninitialized(encoded_bytes));
     sk_sp<SkPixelRef> etc1_pixel_ref(
         SkMallocPixelRef::MakeWithData(info, 0, std::move(etc1_pixel_data)));
 
     bool success = etc1_encode_image(
         reinterpret_cast<unsigned char*>(raw_data.getPixels()),
-        raw_data_size.width(),
-        raw_data_size.height(),
-        pixel_size,
-        stride,
+        raw_data_size.width(), raw_data_size.height(), pixel_size, stride,
         reinterpret_cast<unsigned char*>(etc1_pixel_ref->pixels()),
-        encoded_size.width(),
-        encoded_size.height());
+        encoded_size.width(), encoded_size.height());
     etc1_pixel_ref->setImmutable();
 
     if (success) {
@@ -716,6 +704,7 @@
 }
 
 void ThumbnailCache::JpegProcessingTask(
+    double jpeg_aspect_ratio,
     SkBitmap bitmap,
     const base::Callback<void(std::vector<uint8_t>)>& post_processing_task) {
   // In portrait mode, we want to show thumbnails in squares.
@@ -725,9 +714,7 @@
   // It's fine to horizontally center-align thumbnail saved in landscape
   // mode.
   int scale = 2;
-  double aspect_ratio = base::GetFieldTrialParamByFeatureAsDouble(
-      chrome::android::kTabGridLayoutAndroid, "thumbnail_aspect_ratio", 1.0);
-  aspect_ratio = clampAspectRatio(aspect_ratio, 0.5, 2.0);
+  double aspect_ratio = clampAspectRatio(jpeg_aspect_ratio, 0.5, 2.0);
   SkIRect dest_subset = {
       0, 0, bitmap.width() / scale,
       std::min(bitmap.height() / scale,
@@ -746,12 +733,11 @@
                  base::BindOnce(post_processing_task, std::move(data)));
 }
 
-void ThumbnailCache::PostCompressionTask(
-    TabId tab_id,
-    const base::Time& time_stamp,
-    float scale,
-    sk_sp<SkPixelRef> compressed_data,
-    const gfx::Size& content_size) {
+void ThumbnailCache::PostCompressionTask(TabId tab_id,
+                                         const base::Time& time_stamp,
+                                         float scale,
+                                         sk_sp<SkPixelRef> compressed_data,
+                                         const gfx::Size& content_size) {
   compression_tasks_count_--;
   if (!compressed_data) {
     RemoveOnMatchedTimeStamp(tab_id, time_stamp);
@@ -804,8 +790,7 @@
   int header_bytes_read = 0;
   unsigned char etc1_buffer[ETC_PKM_HEADER_SIZE];
   header_bytes_read = file.ReadAtCurrentPos(
-      reinterpret_cast<char*>(etc1_buffer),
-      ETC_PKM_HEADER_SIZE);
+      reinterpret_cast<char*>(etc1_buffer), ETC_PKM_HEADER_SIZE);
   if (header_bytes_read != ETC_PKM_HEADER_SIZE)
     return false;
 
@@ -829,10 +814,9 @@
       display::Screen::GetScreen()->GetPrimaryDisplay().GetSizeInPixel();
   int max_dimension = std::max(display_size.width(), display_size.height());
 
-  if (content_width > max_dimension
-      || content_height > max_dimension
-      || static_cast<size_t>(raw_width) > NextPowerOfTwo(max_dimension)
-      || static_cast<size_t>(raw_height) > NextPowerOfTwo(max_dimension)) {
+  if (content_width > max_dimension || content_height > max_dimension ||
+      static_cast<size_t>(raw_width) > NextPowerOfTwo(max_dimension) ||
+      static_cast<size_t>(raw_height) > NextPowerOfTwo(max_dimension)) {
     return false;
   }
 
@@ -840,16 +824,13 @@
   sk_sp<SkData> etc1_pixel_data(SkData::MakeUninitialized(data_size));
 
   int pixel_bytes_read = file.ReadAtCurrentPos(
-      reinterpret_cast<char*>(etc1_pixel_data->writable_data()),
-      data_size);
+      reinterpret_cast<char*>(etc1_pixel_data->writable_data()), data_size);
 
   if (pixel_bytes_read != data_size)
     return false;
 
-  SkImageInfo info = SkImageInfo::Make(raw_width,
-                                       raw_height,
-                                       kUnknown_SkColorType,
-                                       kUnpremul_SkAlphaType);
+  SkImageInfo info = SkImageInfo::Make(
+      raw_width, raw_height, kUnknown_SkColorType, kUnpremul_SkAlphaType);
 
   *out_pixels =
       SkMallocPixelRef::MakeWithData(info, 0, std::move(etc1_pixel_data));
@@ -872,13 +853,12 @@
   return true;
 }
 
-}// anonymous namespace
+}  // anonymous namespace
 
 void ThumbnailCache::ReadTask(
     bool decompress,
     TabId tab_id,
-    const base::Callback<
-        void(sk_sp<SkPixelRef>, float, const gfx::Size&)>&
+    const base::Callback<void(sk_sp<SkPixelRef>, float, const gfx::Size&)>&
         post_read_task) {
   gfx::Size content_size;
   float scale = 0.f;
@@ -888,18 +868,15 @@
   if (base::PathExists(file_path)) {
     base::File file(file_path, base::File::FLAG_OPEN | base::File::FLAG_READ);
 
-
-    bool valid_contents = ReadFromFile(file,
-                                       &content_size,
-                                       &scale,
-                                       &compressed_data);
+    bool valid_contents =
+        ReadFromFile(file, &content_size, &scale, &compressed_data);
     file.Close();
 
     if (!valid_contents) {
       content_size.SetSize(0, 0);
-            scale = 0.f;
-            compressed_data.reset();
-            base::DeleteFile(file_path, false);
+      scale = 0.f;
+      compressed_data.reset();
+      base::DeleteFile(file_path, false);
     }
   }
 
@@ -938,8 +915,7 @@
     MakeSpaceForNewItemIfNecessary(tab_id);
     std::unique_ptr<Thumbnail> thumbnail = Thumbnail::Create(
         tab_id, time_stamp, scale, ui_resource_provider_, this);
-    thumbnail->SetCompressedBitmap(std::move(compressed_data),
-                                   content_size);
+    thumbnail->SetCompressedBitmap(std::move(compressed_data), content_size);
     if (kPreferCPUMemory)
       thumbnail->CreateUIResource();
 
@@ -967,8 +943,7 @@
 }
 
 void ThumbnailCache::DecompressionTask(
-    const base::Callback<void(bool, SkBitmap)>&
-        post_decompression_callback,
+    const base::Callback<void(bool, SkBitmap)>& post_decompression_callback,
     sk_sp<SkPixelRef> compressed_data,
     float scale,
     const gfx::Size& content_size) {
@@ -980,16 +955,13 @@
         gfx::Size(compressed_data->width(), compressed_data->height());
 
     SkBitmap raw_data;
-    raw_data.allocPixels(SkImageInfo::Make(buffer_size.width(),
-                                           buffer_size.height(),
-                                           kRGBA_8888_SkColorType,
-                                           kOpaque_SkAlphaType));
+    raw_data.allocPixels(
+        SkImageInfo::Make(buffer_size.width(), buffer_size.height(),
+                          kRGBA_8888_SkColorType, kOpaque_SkAlphaType));
     success = etc1_decode_image(
         reinterpret_cast<unsigned char*>(compressed_data->pixels()),
         reinterpret_cast<unsigned char*>(raw_data.getPixels()),
-        buffer_size.width(),
-        buffer_size.height(),
-        raw_data.bytesPerPixel(),
+        buffer_size.width(), buffer_size.height(), raw_data.bytesPerPixel(),
         raw_data.rowBytes());
     raw_data.setImmutable();
 
@@ -1001,10 +973,9 @@
     } else {
       // The content size is smaller than the buffer size (likely because of
       // a power-of-two rounding), so deep copy the bitmap.
-      raw_data_small.allocPixels(SkImageInfo::Make(content_size.width(),
-                                                   content_size.height(),
-                                                   kRGBA_8888_SkColorType,
-                                                   kOpaque_SkAlphaType));
+      raw_data_small.allocPixels(
+          SkImageInfo::Make(content_size.width(), content_size.height(),
+                            kRGBA_8888_SkColorType, kOpaque_SkAlphaType));
       SkCanvas small_canvas(raw_data_small);
       small_canvas.drawBitmap(raw_data, 0, 0);
       raw_data_small.setImmutable();
@@ -1031,8 +1002,7 @@
   gfx::Size dst_size = gfx::ScaleToFlooredSize(
       gfx::Size(bitmap.width(), bitmap.height()), new_scale);
   SkBitmap dst_bitmap;
-  dst_bitmap.allocPixels(SkImageInfo::Make(dst_size.width(),
-                                           dst_size.height(),
+  dst_bitmap.allocPixels(SkImageInfo::Make(dst_size.width(), dst_size.height(),
                                            bitmap.info().colorType(),
                                            bitmap.info().alphaType()));
   dst_bitmap.eraseColor(0);
diff --git a/chrome/browser/android/thumbnail/thumbnail_cache.h b/chrome/browser/thumbnail/cc/thumbnail_cache.h
similarity index 88%
rename from chrome/browser/android/thumbnail/thumbnail_cache.h
rename to chrome/browser/thumbnail/cc/thumbnail_cache.h
index 343c2d9..d5b8174 100644
--- a/chrome/browser/android/thumbnail/thumbnail_cache.h
+++ b/chrome/browser/thumbnail/cc/thumbnail_cache.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_THUMBNAIL_THUMBNAIL_CACHE_H_
-#define CHROME_BROWSER_ANDROID_THUMBNAIL_THUMBNAIL_CACHE_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_CC_THUMBNAIL_CACHE_H_
+#define CHROME_BROWSER_THUMBNAIL_CC_THUMBNAIL_CACHE_H_
 
 #include <stddef.h>
 
@@ -21,8 +21,8 @@
 #include "base/sequence_checker.h"
 #include "base/sequenced_task_runner.h"
 #include "base/time/time.h"
-#include "chrome/browser/android/thumbnail/scoped_ptr_expiring_cache.h"
-#include "chrome/browser/android/thumbnail/thumbnail.h"
+#include "chrome/browser/thumbnail/cc/scoped_ptr_expiring_cache.h"
+#include "chrome/browser/thumbnail/cc/thumbnail.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 #include "ui/android/resources/ui_resource_provider.h"
@@ -49,15 +49,15 @@
                  size_t compression_queue_max_size,
                  size_t write_queue_max_size,
                  bool use_approximation_thumbnail,
-                 bool save_jpeg_thumbnails);
+                 bool save_jpeg_thumbnails,
+                 double jpeg_aspect_ratio);
 
   ~ThumbnailCache() override;
 
   void SetUIResourceProvider(ui::UIResourceProvider* ui_resource_provider);
 
   void AddThumbnailCacheObserver(ThumbnailCacheObserver* observer);
-  void RemoveThumbnailCacheObserver(
-      ThumbnailCacheObserver* observer);
+  void RemoveThumbnailCacheObserver(ThumbnailCacheObserver* observer);
 
   void Put(TabId tab_id, const SkBitmap& bitmap, float thumbnail_scale);
   void Remove(TabId tab_id);
@@ -68,8 +68,7 @@
   void UpdateVisibleIds(const TabIdList& priority, TabId primary_tab_id);
   void DecompressThumbnailFromFile(
       TabId tab_id,
-      const base::Callback<void(bool, SkBitmap)>&
-          post_decompress_callback);
+      const base::Callback<void(bool, SkBitmap)>& post_decompress_callback);
 
   // Called when resident textures were evicted, which requires paging
   // in bitmaps.
@@ -135,6 +134,7 @@
       const base::Callback<void(sk_sp<SkPixelRef>, const gfx::Size&)>&
           post_compression_task);
   static void JpegProcessingTask(
+      double jpeg_aspect_ratio,
       SkBitmap bitmap,
       const base::Callback<void(std::vector<uint8_t>)>& post_processing_task);
   void PostCompressionTask(TabId tab_id,
@@ -143,16 +143,14 @@
                            sk_sp<SkPixelRef> compressed_data,
                            const gfx::Size& content_size);
   static void DecompressionTask(
-      const base::Callback<void(bool, SkBitmap)>&
-          post_decompress_callback,
-          sk_sp<SkPixelRef> compressed_data,
-          float scale,
-          const gfx::Size& encoded_size);
+      const base::Callback<void(bool, SkBitmap)>& post_decompress_callback,
+      sk_sp<SkPixelRef> compressed_data,
+      float scale,
+      const gfx::Size& encoded_size);
   static void ReadTask(
       bool decompress,
       TabId tab_id,
-      const base::Callback<
-          void(sk_sp<SkPixelRef>, float, const gfx::Size&)>&
+      const base::Callback<void(sk_sp<SkPixelRef>, float, const gfx::Size&)>&
           post_read_task);
   void PostReadTask(TabId tab_id,
                     sk_sp<SkPixelRef> compressed_data,
@@ -168,6 +166,8 @@
 
   const scoped_refptr<base::SequencedTaskRunner> file_sequenced_task_runner_;
 
+  const double jpeg_aspect_ratio_;
+
   const size_t compression_queue_max_size_;
   const size_t write_queue_max_size_;
   const bool use_approximation_thumbnail_;
@@ -195,4 +195,4 @@
   DISALLOW_COPY_AND_ASSIGN(ThumbnailCache);
 };
 
-#endif  // CHROME_BROWSER_ANDROID_THUMBNAIL_THUMBNAIL_CACHE_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_CC_THUMBNAIL_CACHE_H_
diff --git a/chrome/browser/thumbnail/generator/BUILD.gn b/chrome/browser/thumbnail/generator/BUILD.gn
new file mode 100644
index 0000000..70eefc2
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/BUILD.gn
@@ -0,0 +1,163 @@
+# Copyright 2019 The Chromium Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style license that can be
+# found in the LICENSE file.
+
+if (is_android) {
+  import("//build/config/android/config.gni")
+  import("//build/config/android/rules.gni")
+  import("//third_party/protobuf/proto_library.gni")
+}
+
+source_set("generator") {
+  deps = [
+    "//base",
+    "//cc",
+    "//chrome/browser/image_decoder",
+    "//chrome/common",
+    "//chrome/services/media_gallery_util/public/cpp",
+    "//chrome/services/media_gallery_util/public/mojom",
+    "//content/public/browser",
+    "//media",
+    "//mojo/public/cpp/bindings",
+    "//skia",
+    "//ui/gfx",
+  ]
+
+  sources = [
+    "image_thumbnail_request.cc",
+    "image_thumbnail_request.h",
+    "thumbnail_util.cc",
+    "thumbnail_util.h",
+  ]
+
+  if (is_android) {
+    sources += [
+      "android/local_media_data_source_factory.cc",
+      "android/local_media_data_source_factory.h",
+      "android/stats.cc",
+      "android/stats.h",
+      "android/thumbnail_generator.cc",
+      "android/thumbnail_generator.h",
+      "android/thumbnail_media_parser.cc",
+      "android/thumbnail_media_parser.h",
+    ]
+
+    deps += [
+      ":jni_headers",
+      "//third_party/android_opengl/etc1",
+    ]
+  }
+}
+
+if (is_android) {
+  android_library("java") {
+    deps = [
+      ":jni_headers",
+      ":proto_java",
+      "//base:base_java",
+      "//base:jni_java",
+      "//chrome/browser/util:java",
+      "//content/public/android:content_java",
+      "//third_party/android_deps:android_support_v4_java",
+      "//third_party/android_deps:androidx_annotation_annotation_java",
+      "//third_party/android_deps:com_android_support_collections_java",
+      "//third_party/android_deps:com_google_protobuf_protobuf_lite_java",
+    ]
+
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGenerator.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGeneratorCallback.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProvider.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImpl.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailStorageDelegate.java",
+    ]
+
+    annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+  }
+
+  generate_jni("jni_headers") {
+    visibility = [ ":*" ]
+
+    sources = [ "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGenerator.java" ]
+  }
+
+  proto_java_library("proto_java") {
+    proto_path =
+        "android/java/src/org/chromium/chrome/browser/thumbnail/generator"
+    sources = [ "$proto_path/thumbnail_cache_entry.proto" ]
+  }
+
+  android_library("javatests") {
+    testonly = true
+
+    deps = [
+      ":generator_java_test_support",
+      ":java",
+      "//base:base_java",
+      "//base:base_java_test_support",
+      "//chrome/android:chrome_android_java_switches",
+      "//chrome/browser/util:java",
+      "//chrome/test/android:chrome_java_test_support",
+      "//content/public/android:content_java",
+      "//content/public/test/android:content_java_test_support",
+      "//third_party/android_deps:android_support_v4_java",
+      "//third_party/android_support_test_runner:runner_java",
+      "//third_party/junit",
+      "//ui/android:ui_java_test_support",
+    ]
+
+    data = [ "//chrome/browser/thumbnail/generator/test/data/android/" ]
+
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserTest.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImplTest.java",
+    ]
+  }
+
+  generate_jni("test_support_jni_headers") {
+    testonly = true
+
+    visibility = [ ":*" ]
+
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaData.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserBridge.java",
+    ]
+  }
+
+  android_library("generator_java_test_support") {
+    testonly = true
+
+    sources = [
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaData.java",
+      "android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserBridge.java",
+    ]
+
+    deps = [
+      ":test_support_jni_headers",
+      "//base:base_java",
+      "//base:jni_java",
+    ]
+
+    annotation_processor_deps = [ "//base/android/jni_generator:jni_processor" ]
+  }
+
+  source_set("test_support") {
+    testonly = true
+
+    deps = [
+      ":generator",
+      ":test_support_jni_headers",
+      "//base",
+      "//skia",
+      "//ui/gfx",
+    ]
+
+    sources = [
+      "android/thumbnail_media_parser_bridge.cc",
+      "android/thumbnail_media_parser_bridge.h",
+    ]
+  }
+}
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorage.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java
similarity index 97%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorage.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java
index fddc7dc..29ed47a 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorage.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorage.java
@@ -1,8 +1,8 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -24,9 +24,9 @@
 import org.chromium.base.metrics.RecordHistogram;
 import org.chromium.base.task.AsyncTask;
 import org.chromium.base.task.BackgroundOnlyAsyncTask;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailCacheEntry.ContentId;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailCacheEntry.ThumbnailEntry;
 import org.chromium.chrome.browser.util.ConversionUtils;
-import org.chromium.chrome.browser.widget.ThumbnailCacheEntry.ContentId;
-import org.chromium.chrome.browser.widget.ThumbnailCacheEntry.ThumbnailEntry;
 
 import java.io.ByteArrayOutputStream;
 import java.io.File;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorageTest.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java
similarity index 98%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorageTest.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java
index 6f682d89..6866b6d9 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ThumbnailDiskStorageTest.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailDiskStorageTest.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -185,7 +185,7 @@
         retrieveThumbnailAndAssertRetrieved(request);
 
         // Ensure the thumbnail generator is not called.
-        Assert.assertEquals(mTestThumbnailGenerator.generateCount.get(), 0);
+        Assert.assertEquals(0, mTestThumbnailGenerator.generateCount.get());
         Assert.assertTrue(
                 mTestThumbnailDiskStorage.getFromDisk(CONTENT_ID1, ICON_WIDTH1).sameAs(BITMAP1));
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailGenerator.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGenerator.java
similarity index 96%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailGenerator.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGenerator.java
index 3a6d742..95e2f69 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailGenerator.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGenerator.java
@@ -1,8 +1,8 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 import android.text.TextUtils;
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailGeneratorCallback.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGeneratorCallback.java
similarity index 85%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailGeneratorCallback.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGeneratorCallback.java
index 59238fcb..38e892c 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailGeneratorCallback.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailGeneratorCallback.java
@@ -1,8 +1,8 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaData.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaData.java
similarity index 78%
rename from chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaData.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaData.java
index 8279c514..1db083b 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/download/DownloadMediaData.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaData.java
@@ -1,8 +1,8 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.download;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 
@@ -11,7 +11,7 @@
 /**
  * Contains local media metadata and thumbnails.
  */
-public class DownloadMediaData {
+public class ThumbnailMediaData {
     /**
      * The duration of the media file in seconds. Or -1 if no duration in the metadata.
      */
@@ -34,7 +34,7 @@
     public final Bitmap thumbnail;
 
     @CalledByNative
-    private DownloadMediaData(double duration, String title, String artist, Bitmap thumbnail) {
+    private ThumbnailMediaData(double duration, String title, String artist, Bitmap thumbnail) {
         this.duration = duration;
         this.title = title;
         this.artist = artist;
diff --git a/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserBridge.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserBridge.java
new file mode 100644
index 0000000..3a1f09d
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserBridge.java
@@ -0,0 +1,57 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+package org.chromium.chrome.browser.thumbnail.generator;
+
+import org.chromium.base.Callback;
+import org.chromium.base.annotations.NativeMethods;
+
+/**
+ * A JNI bridge that owns a native side ThumbnailMediaParser, which parses media file safely in an
+ * utility process.
+ */
+public class ThumbnailMediaParserBridge {
+    private long mNativeThumbnailMediaParserBridge;
+
+    /**
+     * Creates a media parser to analyze media metadata and retrieve thumbnails.
+     * @param mimeType The mime type of the media file.
+     * @param filePath The absolute path of the media file.
+     * @param totalSize Total size of the media file.
+     * @param callback Callback to get the result.
+     */
+    public ThumbnailMediaParserBridge(
+            String mimeType, String filePath, Callback<ThumbnailMediaData> callback) {
+        mNativeThumbnailMediaParserBridge = ThumbnailMediaParserBridgeJni.get().init(
+                ThumbnailMediaParserBridge.this, mimeType, filePath, callback);
+    }
+
+    /**
+     * Destroys the native object of ThumbnailMediaParser. This will result in the utility process
+     * being destroyed.
+     */
+    public void destroy() {
+        ThumbnailMediaParserBridgeJni.get().destroy(
+                mNativeThumbnailMediaParserBridge, ThumbnailMediaParserBridge.this);
+        mNativeThumbnailMediaParserBridge = 0;
+    }
+
+    /**
+     * Starts to parse a media file to retrieve media metadata and video thumbnail.
+     */
+    public void start() {
+        if (mNativeThumbnailMediaParserBridge != 0) {
+            ThumbnailMediaParserBridgeJni.get().start(
+                    mNativeThumbnailMediaParserBridge, ThumbnailMediaParserBridge.this);
+        }
+    }
+
+    @NativeMethods
+    interface Natives {
+        long init(ThumbnailMediaParserBridge caller, String mimeType, String filePath,
+                Callback<ThumbnailMediaData> callback);
+        void destroy(long nativeThumbnailMediaParserBridge, ThumbnailMediaParserBridge caller);
+        void start(long nativeThumbnailMediaParserBridge, ThumbnailMediaParserBridge caller);
+    }
+}
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserTest.java
similarity index 87%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserTest.java
index 3fb17fe..ea7f239 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/download/DownloadMediaParserTest.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailMediaParserTest.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.download;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.os.Build;
 import android.support.test.filters.LargeTest;
@@ -27,17 +27,17 @@
 import java.io.File;
 
 /**
- * Tests to verify DownloadMediaParser, which retrieves media metadata and thumbnails.
+ * Tests to verify ThumbnailMediaParser, which retrieves media metadata and thumbnails.
  *
  * Most of the work is done in utility process and GPU process.
  *
- * All download media parser usage must be called on UI thread in this test to get message loop and
+ * All  media parser usage must be called on UI thread in this test to get message loop and
  * threading contexts in native.
  *
  * Because each media parser call may perform multiple process and thread hops, it can be slow.
  */
 @RunWith(ChromeJUnit4ClassRunner.class)
-public class DownloadMediaParserTest {
+public class ThumbnailMediaParserTest {
     private static final long MAX_MEDIA_PARSER_POLL_TIME_MS = 10000;
     private static final long MEDIA_PARSER_POLL_INTERVAL_MS = 1000;
 
@@ -45,11 +45,11 @@
     public ChromeBrowserTestRule mTestRule = new ChromeBrowserTestRule();
 
     /**
-     * Wraps result from download media parser.
+     * Wraps result from  media parser.
      */
     public static class MediaParserResult {
         public boolean done;
-        public DownloadMediaData mediaData;
+        public ThumbnailMediaData mediaData;
     }
 
     @Before
@@ -63,10 +63,10 @@
         boolean done = false;
         MediaParserResult result = new MediaParserResult();
 
-        // The native DownloadMediaParser needs to be created on UI thread.
+        // The native MediaParser needs to be created on UI thread.
         TestThreadUtils.runOnUiThreadBlocking(() -> {
-            DownloadMediaParserBridge parser = new DownloadMediaParserBridge(
-                    mimeType, filePath, (DownloadMediaData mediaData) -> {
+            ThumbnailMediaParserBridge parser = new ThumbnailMediaParserBridge(
+                    mimeType, filePath, (ThumbnailMediaData mediaData) -> {
                         result.mediaData = mediaData;
                         result.done = true;
                     });
@@ -84,7 +84,7 @@
 
     @Test
     @LargeTest
-    @Feature({"Download"})
+    @Feature({"MediaParser"})
     /**
      * Verify that the metadata from audio file can be retrieved correctly.
      * @throws InterruptedException
@@ -97,7 +97,7 @@
 
     @Test
     @LargeTest
-    @Feature({"Download"})
+    @Feature({"MediaParser"})
     @MinAndroidSdkLevel(Build.VERSION_CODES.LOLLIPOP)
     @Restriction(UiRestriction.RESTRICTION_TYPE_PHONE)
     /**
@@ -116,7 +116,7 @@
 
     @Test
     @LargeTest
-    @Feature({"Download"})
+    @Feature({"MediaParser"})
     /**
      * Verify metadata and thumbnail can be retrieved correctly from vp8 video file.
      * @throws InterruptedException
@@ -133,7 +133,7 @@
 
     @Test
     @LargeTest
-    @Feature({"Download"})
+    @Feature({"MediaParser"})
     /**
      * Verify metadata and thumbnail can be retrieved correctly from vp8 video file with alpha
      * plane.
@@ -151,7 +151,7 @@
 
     @Test
     @LargeTest
-    @Feature({"Download"})
+    @Feature({"MediaParser"})
     /**
      * Verify graceful failure on parsing invalid video file.
      * @throws InterruptedException
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailProvider.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProvider.java
similarity index 86%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailProvider.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProvider.java
index 35e7d59..3f698c875 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailProvider.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProvider.java
@@ -1,8 +1,8 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 
@@ -32,8 +32,10 @@
         /** Called when a requested thumbnail is ready. */
         void onThumbnailRetrieved(@NonNull String contentId, @Nullable Bitmap thumbnail);
 
-        /** The requested size (maximum dimension (pixel) of the smaller side) of the thumbnail to
-         * be retrieved. */
+        /**
+         * The requested size (maximum dimension (pixel) of the smaller side) of the thumbnail to
+         * be retrieved.
+         */
         int getIconSize();
 
         /**
@@ -46,10 +48,9 @@
          * @param callback The callback to be invoked after getting the thumbnail.
          * @return True, if the request can directly provide the thumbnail, false otherwise.
          */
-        default boolean
-            getThumbnail(Callback<Bitmap> callback) {
-                return false;
-            }
+        default boolean getThumbnail(Callback<Bitmap> callback) {
+            return false;
+        }
     }
 
     /** Destroys the class. */
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailProviderImpl.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImpl.java
similarity index 98%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailProviderImpl.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImpl.java
index 3684948..6f48e47 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailProviderImpl.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImpl.java
@@ -1,8 +1,8 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 import android.support.v4.util.LruCache;
diff --git a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ThumbnailProviderImplTest.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImplTest.java
similarity index 96%
rename from chrome/android/javatests/src/org/chromium/chrome/browser/widget/ThumbnailProviderImplTest.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImplTest.java
index 7dff010f..c4841c2 100644
--- a/chrome/android/javatests/src/org/chromium/chrome/browser/widget/ThumbnailProviderImplTest.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailProviderImplTest.java
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 import android.support.test.filters.MediumTest;
@@ -24,7 +24,7 @@
 import org.chromium.base.test.util.Feature;
 import org.chromium.base.test.util.UrlUtils;
 import org.chromium.chrome.browser.ChromeSwitches;
-import org.chromium.chrome.browser.widget.ThumbnailProvider.ThumbnailRequest;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider.ThumbnailRequest;
 import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
 import org.chromium.chrome.test.ChromeTabbedActivityTestRule;
 import org.chromium.content_public.browser.UiThreadTaskTraits;
@@ -35,7 +35,8 @@
 @RunWith(ChromeJUnit4ClassRunner.class)
 @CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
 public class ThumbnailProviderImplTest {
-    private static final String TEST_DIRECTORY = "chrome/test/data/android/thumbnail_provider/";
+    private static final String TEST_DIRECTORY =
+            "chrome/browser/thumbnail/generator/test/data/android/";
     @Rule
     public ChromeTabbedActivityTestRule mActivityTestRule = new ChromeTabbedActivityTestRule();
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailStorageDelegate.java b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailStorageDelegate.java
similarity index 82%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailStorageDelegate.java
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailStorageDelegate.java
index 897b45b..2f200e2 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/ThumbnailStorageDelegate.java
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/ThumbnailStorageDelegate.java
@@ -1,8 +1,8 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
 import android.graphics.Bitmap;
 
diff --git a/chrome/android/java/src/org/chromium/chrome/browser/widget/thumbnail_cache_entry.proto b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/thumbnail_cache_entry.proto
similarity index 78%
rename from chrome/android/java/src/org/chromium/chrome/browser/widget/thumbnail_cache_entry.proto
rename to chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/thumbnail_cache_entry.proto
index 96e4979..40daf50 100644
--- a/chrome/android/java/src/org/chromium/chrome/browser/widget/thumbnail_cache_entry.proto
+++ b/chrome/browser/thumbnail/generator/android/java/src/org/chromium/chrome/browser/thumbnail/generator/thumbnail_cache_entry.proto
@@ -1,4 +1,4 @@
-// Copyright 2017 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 //
@@ -7,9 +7,9 @@
 
 syntax = "proto2";
 
-package org.chromium.chrome.browser.widget;
+package org.chromium.chrome.browser.thumbnail.generator;
 
-option java_package = "org.chromium.chrome.browser.widget";
+option java_package = "org.chromium.chrome.browser.thumbnail.generator";
 
 // TODO(jkrcal): Remove when protobuf 4.0 is out, https://crbug.com/800281.
 option optimize_for = LITE_RUNTIME;
diff --git a/chrome/browser/download/android/local_media_data_source_factory.cc b/chrome/browser/thumbnail/generator/android/local_media_data_source_factory.cc
similarity index 96%
rename from chrome/browser/download/android/local_media_data_source_factory.cc
rename to chrome/browser/thumbnail/generator/android/local_media_data_source_factory.cc
index 21381ef7..577cbc8 100644
--- a/chrome/browser/download/android/local_media_data_source_factory.cc
+++ b/chrome/browser/thumbnail/generator/android/local_media_data_source_factory.cc
@@ -1,8 +1,8 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/download/android/local_media_data_source_factory.h"
+#include "chrome/browser/thumbnail/generator/android/local_media_data_source_factory.h"
 
 #include <vector>
 
diff --git a/chrome/browser/download/android/local_media_data_source_factory.h b/chrome/browser/thumbnail/generator/android/local_media_data_source_factory.h
similarity index 84%
rename from chrome/browser/download/android/local_media_data_source_factory.h
rename to chrome/browser/thumbnail/generator/android/local_media_data_source_factory.h
index 624b9bf9..6c4fe78 100644
--- a/chrome/browser/download/android/local_media_data_source_factory.h
+++ b/chrome/browser/thumbnail/generator/android/local_media_data_source_factory.h
@@ -2,8 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_DOWNLOAD_ANDROID_LOCAL_MEDIA_DATA_SOURCE_FACTORY_H_
-#define CHROME_BROWSER_DOWNLOAD_ANDROID_LOCAL_MEDIA_DATA_SOURCE_FACTORY_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_LOCAL_MEDIA_DATA_SOURCE_FACTORY_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_LOCAL_MEDIA_DATA_SOURCE_FACTORY_H_
 
 #include <memory>
 
@@ -40,4 +40,4 @@
   DISALLOW_COPY_AND_ASSIGN(LocalMediaDataSourceFactory);
 };
 
-#endif  // CHROME_BROWSER_DOWNLOAD_ANDROID_LOCAL_MEDIA_DATA_SOURCE_FACTORY_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_LOCAL_MEDIA_DATA_SOURCE_FACTORY_H_
diff --git a/chrome/browser/thumbnail/generator/android/stats.cc b/chrome/browser/thumbnail/generator/android/stats.cc
new file mode 100644
index 0000000..e18396c
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/stats.cc
@@ -0,0 +1,22 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "chrome/browser/thumbnail/generator/android/stats.h"
+
+#include "base/metrics/histogram_macros.h"
+
+void RecordMediaParserEvent(MediaParserEvent event) {
+  UMA_HISTOGRAM_ENUMERATION("Download.MediaParser.Event", event,
+                            MediaParserEvent::kCount);
+}
+
+void RecordMediaMetadataEvent(MediaMetadataEvent event) {
+  UMA_HISTOGRAM_ENUMERATION("Download.MediaMetadata.Event", event,
+                            MediaMetadataEvent::kCount);
+}
+
+void RecordVideoThumbnailEvent(VideoThumbnailEvent event) {
+  UMA_HISTOGRAM_ENUMERATION("Download.VideoThumbnail.Event", event,
+                            VideoThumbnailEvent::kCount);
+}
diff --git a/chrome/browser/thumbnail/generator/android/stats.h b/chrome/browser/thumbnail/generator/android/stats.h
new file mode 100644
index 0000000..ed602917
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/stats.h
@@ -0,0 +1,71 @@
+// Copyright 2019 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_STATS_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_STATS_H_
+
+#include "build/build_config.h"
+
+// Tracks media parser events. Each media parser hubs IPC channels for local
+// media analysis tasks. Used in UMA, do not remove, change or reuse existing
+// entries.
+enum class MediaParserEvent {
+  // Started to initialize the media parser.
+  kInitialize = 0,
+  // The mime type is not supported by the media parser.
+  kUnsupportedMimeType = 1,
+  // Failed to read the local media file.
+  kReadFileError = 2,
+  // Utility process connection error.
+  kUtilityConnectionError = 3,
+  // GPU process connection error.
+  kGpuConnectionError = 4,
+  // Failed to parse metadata.
+  kMetadataFailed = 5,
+  // Failed to retrieve video thumbnail.
+  kVideoThumbnailFailed = 6,
+  // Failed to parse media file, aggregation of all failure reasons.
+  kFailure = 7,
+  // Media file successfully parsed.
+  kSuccess = 8,
+  // Time out and failed.
+  kTimeout = 9,
+  kCount
+};
+
+// Tracks local media metadata requests. Used in UMA, do not remove, change or
+// reuse existing entries.
+enum class MediaMetadataEvent {
+  // Started to retrieve metadata.
+  kMetadataStart = 0,
+  // Failed to retrieve metadata.
+  kMetadataFailed = 1,
+  // Completed to retrieve metadata.
+  kMetadataComplete = 2,
+  kCount
+};
+
+// Tracks video thumbnail requests. Used in UMA, do not remove, change or
+// reuse existing entries.
+enum class VideoThumbnailEvent {
+  kVideoThumbnailStart = 0,
+  // Failed to extract video frame.
+  kVideoFrameExtractionFailed = 1,
+  // Failed to decode video frame.
+  kVideoDecodeFailed = 2,
+  // Completed to retrieve video thumbnail.
+  kVideoThumbnailComplete = 3,
+  kCount
+};
+
+// Records download media parser event.
+void RecordMediaParserEvent(MediaParserEvent event);
+
+// Records media metadata parsing events.
+void RecordMediaMetadataEvent(MediaMetadataEvent event);
+
+// Records video thumbnail retrieval events.
+void RecordVideoThumbnailEvent(VideoThumbnailEvent event);
+
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_STATS_H_
diff --git a/chrome/browser/android/widget/thumbnail_generator.cc b/chrome/browser/thumbnail/generator/android/thumbnail_generator.cc
similarity index 87%
rename from chrome/browser/android/widget/thumbnail_generator.cc
rename to chrome/browser/thumbnail/generator/android/thumbnail_generator.cc
index c5772ad..e9e9959 100644
--- a/chrome/browser/android/widget/thumbnail_generator.cc
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_generator.cc
@@ -1,17 +1,17 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/android/widget/thumbnail_generator.h"
+#include "chrome/browser/thumbnail/generator/android/thumbnail_generator.h"
 
 #include <memory>
 
 #include "base/android/jni_string.h"
 #include "base/bind.h"
 #include "base/threading/thread_restrictions.h"
-#include "chrome/android/chrome_jni_headers/ThumbnailGenerator_jni.h"
-#include "chrome/browser/download/android/download_media_parser.h"
-#include "chrome/browser/download/thumbnail_util.h"
+#include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h"
+#include "chrome/browser/thumbnail/generator/jni_headers/ThumbnailGenerator_jni.h"
+#include "chrome/browser/thumbnail/generator/thumbnail_util.h"
 #include "content/public/browser/browser_thread.h"
 #include "ui/gfx/android/java_bitmap.h"
 
@@ -31,7 +31,7 @@
   JNIEnv* env = base::android::AttachCurrentThread();
   Java_ThumbnailGenerator_onThumbnailRetrieved(
       env, java_delegate, content_id, icon_size,
-      thumbnail.drawsNothing() ? NULL : gfx::ConvertToJavaBitmap(&thumbnail),
+      thumbnail.drawsNothing() ? nullptr : gfx::ConvertToJavaBitmap(&thumbnail),
       callback);
 }
 
@@ -68,7 +68,7 @@
 void ThumbnailGenerator::OnVideoThumbnailRetrieved(
     base::OnceCallback<void(SkBitmap)> java_callback,
     int icon_size,
-    std::unique_ptr<DownloadMediaParser> parser,
+    std::unique_ptr<ThumbnailMediaParser> parser,
     bool success,
     chrome::mojom::MediaMetadataPtr media_metadata,
     SkBitmap thumbnail) {
@@ -106,7 +106,7 @@
   // Retrieve video thumbnail.
   if (base::StartsWith(mime_type, "video/",
                        base::CompareCase::INSENSITIVE_ASCII)) {
-    auto parser = std::make_unique<DownloadMediaParser>(mime_type, file_path);
+    auto parser = std::make_unique<ThumbnailMediaParser>(mime_type, file_path);
     parser->Start(base::BindOnce(&ThumbnailGenerator::OnVideoThumbnailRetrieved,
                                  weak_factory_.GetWeakPtr(),
                                  std::move(java_callback), icon_size,
diff --git a/chrome/browser/android/widget/thumbnail_generator.h b/chrome/browser/thumbnail/generator/android/thumbnail_generator.h
similarity index 83%
rename from chrome/browser/android/widget/thumbnail_generator.h
rename to chrome/browser/thumbnail/generator/android/thumbnail_generator.h
index 54f60ba..d3f3383 100644
--- a/chrome/browser/android/widget/thumbnail_generator.h
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_generator.h
@@ -1,19 +1,19 @@
-// Copyright 2016 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_
-#define CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_GENERATOR_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_GENERATOR_H_
 
 #include <memory>
 #include <string>
 
 #include "base/android/jni_android.h"
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/download/image_thumbnail_request.h"
+#include "chrome/browser/thumbnail/generator/image_thumbnail_request.h"
 #include "chrome/services/media_gallery_util/public/mojom/media_parser.mojom.h"
 
-class DownloadMediaParser;
+class ThumbnailMediaParser;
 
 // Kicks off asynchronous pipelines for creating thumbnails for local files.
 // The native-side ThumbnailGenerator is owned by the Java-side and can be
@@ -53,7 +53,7 @@
   void OnVideoThumbnailRetrieved(
       base::OnceCallback<void(SkBitmap)> java_callback,
       int icon_size,
-      std::unique_ptr<DownloadMediaParser> parser,
+      std::unique_ptr<ThumbnailMediaParser> parser,
       bool success,
       chrome::mojom::MediaMetadataPtr media_metadata,
       SkBitmap thumbnail);
@@ -65,4 +65,4 @@
   DISALLOW_COPY_AND_ASSIGN(ThumbnailGenerator);
 };
 
-#endif  // CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_GENERATOR_H_
diff --git a/chrome/browser/download/android/download_media_parser.cc b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.cc
similarity index 81%
rename from chrome/browser/download/android/download_media_parser.cc
rename to chrome/browser/thumbnail/generator/android/thumbnail_media_parser.cc
index 5481fc0..48a3bf2 100644
--- a/chrome/browser/download/android/download_media_parser.cc
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.cc
@@ -1,8 +1,8 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/download/android/download_media_parser.h"
+#include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h"
 
 #include "base/bind.h"
 #include "base/files/file.h"
@@ -12,7 +12,7 @@
 #include "base/task/task_traits.h"
 #include "base/task_runner_util.h"
 #include "cc/paint/skia_paint_canvas.h"
-#include "chrome/browser/download/android/local_media_data_source_factory.h"
+#include "chrome/browser/thumbnail/generator/android/local_media_data_source_factory.h"
 #include "content/public/browser/android/gpu_video_accelerator_factories_provider.h"
 #include "content/public/browser/media_service.h"
 #include "media/base/overlay_info.h"
@@ -55,22 +55,22 @@
 
 }  // namespace
 
-DownloadMediaParser::DownloadMediaParser(const std::string& mime_type,
-                                         const base::FilePath& file_path)
+ThumbnailMediaParser::ThumbnailMediaParser(const std::string& mime_type,
+                                           const base::FilePath& file_path)
     : mime_type_(mime_type),
       file_path_(file_path),
       file_task_runner_(base::CreateSingleThreadTaskRunner(
           {base::ThreadPool(), base::MayBlock()})),
       decode_done_(false) {}
 
-DownloadMediaParser::~DownloadMediaParser() = default;
+ThumbnailMediaParser::~ThumbnailMediaParser() = default;
 
-void DownloadMediaParser::Start(ParseCompleteCB parse_complete_cb) {
+void ThumbnailMediaParser::Start(ParseCompleteCB parse_complete_cb) {
   RecordMediaParserEvent(MediaParserEvent::kInitialize);
   parse_complete_cb_ = std::move(parse_complete_cb);
   timer_.Start(
       FROM_HERE, kTimeOut,
-      base::BindOnce(&DownloadMediaParser::OnError, weak_factory_.GetWeakPtr(),
+      base::BindOnce(&ThumbnailMediaParser::OnError, weak_factory_.GetWeakPtr(),
                      MediaParserEvent::kTimeout));
 
   // Only process media mime types.
@@ -83,11 +83,11 @@
   base::PostTaskAndReplyWithResult(
       file_task_runner_.get(), FROM_HERE,
       base::BindOnce(&GetFileSize, file_path_),
-      base::BindOnce(&DownloadMediaParser::OnReadFileSize,
+      base::BindOnce(&ThumbnailMediaParser::OnReadFileSize,
                      weak_factory_.GetWeakPtr()));
 }
 
-void DownloadMediaParser::OnReadFileSize(int64_t file_size) {
+void ThumbnailMediaParser::OnReadFileSize(int64_t file_size) {
   if (file_size < 0) {
     OnError(MediaParserEvent::kReadFileError);
     return;
@@ -97,27 +97,27 @@
   RetrieveMediaParser();
 }
 
-void DownloadMediaParser::OnMediaParserCreated() {
+void ThumbnailMediaParser::OnMediaParserCreated() {
   auto media_source_factory = std::make_unique<LocalMediaDataSourceFactory>(
       file_path_, file_task_runner_);
   mojo::PendingRemote<chrome::mojom::MediaDataSource> source;
   media_data_source_ = media_source_factory->CreateMediaDataSource(
       source.InitWithNewPipeAndPassReceiver(),
-      base::BindRepeating(&DownloadMediaParser::OnMediaDataReady,
+      base::BindRepeating(&ThumbnailMediaParser::OnMediaDataReady,
                           weak_factory_.GetWeakPtr()));
 
   RecordMediaMetadataEvent(MediaMetadataEvent::kMetadataStart);
   media_parser()->ParseMediaMetadata(
       mime_type_, size_, false /* get_attached_images */, std::move(source),
-      base::BindOnce(&DownloadMediaParser::OnMediaMetadataParsed,
+      base::BindOnce(&ThumbnailMediaParser::OnMediaMetadataParsed,
                      weak_factory_.GetWeakPtr()));
 }
 
-void DownloadMediaParser::OnConnectionError() {
+void ThumbnailMediaParser::OnConnectionError() {
   OnError(MediaParserEvent::kUtilityConnectionError);
 }
 
-void DownloadMediaParser::OnMediaMetadataParsed(
+void ThumbnailMediaParser::OnMediaMetadataParsed(
     bool parse_success,
     chrome::mojom::MediaMetadataPtr metadata,
     const std::vector<metadata::AttachedImage>& attached_images) {
@@ -142,11 +142,12 @@
 
   // Start to retrieve video thumbnail.
   base::ThreadTaskRunnerHandle::Get()->PostTask(
-      FROM_HERE, base::BindOnce(&DownloadMediaParser::RetrieveEncodedVideoFrame,
-                                weak_factory_.GetWeakPtr()));
+      FROM_HERE,
+      base::BindOnce(&ThumbnailMediaParser::RetrieveEncodedVideoFrame,
+                     weak_factory_.GetWeakPtr()));
 }
 
-void DownloadMediaParser::RetrieveEncodedVideoFrame() {
+void ThumbnailMediaParser::RetrieveEncodedVideoFrame() {
   RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoThumbnailStart);
   media_data_source_.reset();
 
@@ -155,16 +156,16 @@
   mojo::PendingRemote<chrome::mojom::MediaDataSource> source;
   media_data_source_ = media_source_factory->CreateMediaDataSource(
       source.InitWithNewPipeAndPassReceiver(),
-      base::BindRepeating(&DownloadMediaParser::OnMediaDataReady,
+      base::BindRepeating(&ThumbnailMediaParser::OnMediaDataReady,
                           weak_factory_.GetWeakPtr()));
 
   media_parser()->ExtractVideoFrame(
       mime_type_, base::saturated_cast<uint32_t>(size_), std::move(source),
-      base::BindOnce(&DownloadMediaParser::OnVideoFrameRetrieved,
+      base::BindOnce(&ThumbnailMediaParser::OnVideoFrameRetrieved,
                      weak_factory_.GetWeakPtr()));
 }
 
-void DownloadMediaParser::OnVideoFrameRetrieved(
+void ThumbnailMediaParser::OnVideoFrameRetrieved(
     bool success,
     chrome::mojom::VideoFrameDataPtr video_frame_data,
     const base::Optional<media::VideoDecoderConfig>& config) {
@@ -197,17 +198,17 @@
 
   // Starts to decode with MojoVideoDecoder.
   content::CreateGpuVideoAcceleratorFactories(base::BindRepeating(
-      &DownloadMediaParser::OnGpuVideoAcceleratorFactoriesReady,
+      &ThumbnailMediaParser::OnGpuVideoAcceleratorFactoriesReady,
       weak_factory_.GetWeakPtr()));
 }
 
-void DownloadMediaParser::OnGpuVideoAcceleratorFactoriesReady(
+void ThumbnailMediaParser::OnGpuVideoAcceleratorFactoriesReady(
     std::unique_ptr<media::GpuVideoAcceleratorFactories> factories) {
   gpu_factories_ = std::move(factories);
   DecodeVideoFrame();
 }
 
-void DownloadMediaParser::DecodeVideoFrame() {
+void ThumbnailMediaParser::DecodeVideoFrame() {
   mojo::PendingRemote<media::mojom::VideoDecoder> video_decoder_remote;
   GetMediaInterfaceFactory()->CreateVideoDecoder(
       video_decoder_remote.InitWithNewPipeAndPassReceiver());
@@ -224,12 +225,12 @@
       std::move(mojo_decoder), config_,
       std::move(video_frame_data_->get_encoded_data()));
 
-  decoder_->Start(base::BindOnce(&DownloadMediaParser::OnVideoFrameDecoded,
+  decoder_->Start(base::BindOnce(&ThumbnailMediaParser::OnVideoFrameDecoded,
                                  weak_factory_.GetWeakPtr()));
   video_frame_data_.reset();
 }
 
-void DownloadMediaParser::OnVideoFrameDecoded(
+void ThumbnailMediaParser::OnVideoFrameDecoded(
     scoped_refptr<media::VideoFrame> frame) {
   if (!frame) {
     RecordVideoThumbnailEvent(VideoThumbnailEvent::kVideoDecodeFailed);
@@ -243,7 +244,7 @@
   RenderVideoFrame(std::move(frame));
 }
 
-void DownloadMediaParser::RenderVideoFrame(
+void ThumbnailMediaParser::RenderVideoFrame(
     scoped_refptr<media::VideoFrame> video_frame) {
   auto context_provider =
       gpu_factories_ ? gpu_factories_->GetMediaContextProvider() : nullptr;
@@ -262,7 +263,7 @@
 }
 
 media::mojom::InterfaceFactory*
-DownloadMediaParser::GetMediaInterfaceFactory() {
+ThumbnailMediaParser::GetMediaInterfaceFactory() {
   if (!media_interface_factory_) {
     mojo::PendingRemote<service_manager::mojom::InterfaceProvider> interfaces;
     media_interface_provider_ = std::make_unique<media::MediaInterfaceProvider>(
@@ -271,18 +272,18 @@
         media_interface_factory_.BindNewPipeAndPassReceiver(),
         std::move(interfaces));
     media_interface_factory_.set_disconnect_handler(
-        base::BindOnce(&DownloadMediaParser::OnDecoderConnectionError,
+        base::BindOnce(&ThumbnailMediaParser::OnDecoderConnectionError,
                        base::Unretained(this)));
   }
 
   return media_interface_factory_.get();
 }
 
-void DownloadMediaParser::OnDecoderConnectionError() {
+void ThumbnailMediaParser::OnDecoderConnectionError() {
   OnError(MediaParserEvent::kGpuConnectionError);
 }
 
-void DownloadMediaParser::OnMediaDataReady(
+void ThumbnailMediaParser::OnMediaDataReady(
     chrome::mojom::MediaDataSource::ReadCallback callback,
     std::unique_ptr<std::string> data) {
   // TODO(xingliu): Change media_parser.mojom to move the data instead of copy.
@@ -290,7 +291,7 @@
     std::move(callback).Run(std::vector<uint8_t>(data->begin(), data->end()));
 }
 
-void DownloadMediaParser::NotifyComplete(SkBitmap bitmap) {
+void ThumbnailMediaParser::NotifyComplete(SkBitmap bitmap) {
   DCHECK(metadata_);
   DCHECK(parse_complete_cb_);
   RecordMediaParserEvent(MediaParserEvent::kSuccess);
@@ -298,7 +299,7 @@
       .Run(true, std::move(metadata_), std::move(bitmap));
 }
 
-void DownloadMediaParser::OnError(MediaParserEvent event) {
+void ThumbnailMediaParser::OnError(MediaParserEvent event) {
   DCHECK(parse_complete_cb_);
   RecordMediaParserEvent(MediaParserEvent::kFailure);
   RecordMediaParserEvent(event);
diff --git a/chrome/browser/download/android/download_media_parser.h b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h
similarity index 85%
rename from chrome/browser/download/android/download_media_parser.h
rename to chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h
index b3a0b9a..6d5a3283 100644
--- a/chrome/browser/download/android/download_media_parser.h
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h
@@ -1,9 +1,9 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MEDIA_PARSER_H_
-#define CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MEDIA_PARSER_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_H_
 
 #include <memory>
 #include <string>
@@ -17,7 +17,7 @@
 #include "base/optional.h"
 #include "base/sequenced_task_runner.h"
 #include "base/timer/timer.h"
-#include "chrome/browser/download/download_stats.h"
+#include "chrome/browser/thumbnail/generator/android/stats.h"
 #include "chrome/common/media_galleries/metadata_types.h"
 #include "chrome/services/media_gallery_util/public/cpp/media_parser_provider.h"
 #include "chrome/services/media_gallery_util/public/mojom/media_parser.mojom-forward.h"
@@ -41,16 +41,17 @@
 // For video file, the thumbnail will be the a video key frame. The frame
 // extraction always happens in utility process. The decoding may happen in
 // utility or GPU process based on video codec.
-class DownloadMediaParser : public MediaParserProvider, public media::MediaLog {
+class ThumbnailMediaParser : public MediaParserProvider,
+                             public media::MediaLog {
  public:
   using ParseCompleteCB =
       base::OnceCallback<void(bool success,
                               chrome::mojom::MediaMetadataPtr media_metadata,
                               SkBitmap bitmap)>;
 
-  DownloadMediaParser(const std::string& mime_type,
-                      const base::FilePath& file_path);
-  ~DownloadMediaParser() override;
+  ThumbnailMediaParser(const std::string& mime_type,
+                       const base::FilePath& file_path);
+  ~ThumbnailMediaParser() override;
 
   // Parse media metadata and thumbnail in a local file. All file IO will run on
   // |file_task_runner|. The metadata is parsed in an utility process safely.
@@ -129,9 +130,9 @@
   std::unique_ptr<media::GpuVideoAcceleratorFactories> gpu_factories_;
   bool decode_done_;
 
-  base::WeakPtrFactory<DownloadMediaParser> weak_factory_{this};
+  base::WeakPtrFactory<ThumbnailMediaParser> weak_factory_{this};
 
-  DISALLOW_COPY_AND_ASSIGN(DownloadMediaParser);
+  DISALLOW_COPY_AND_ASSIGN(ThumbnailMediaParser);
 };
 
-#endif  // CHROME_BROWSER_DOWNLOAD_ANDROID_DOWNLOAD_MEDIA_PARSER_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_H_
diff --git a/chrome/browser/download/android/download_media_parser_bridge.cc b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.cc
similarity index 70%
rename from chrome/browser/download/android/download_media_parser_bridge.cc
rename to chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.cc
index 6c95401ca..f0176e6 100644
--- a/chrome/browser/download/android/download_media_parser_bridge.cc
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.cc
@@ -1,16 +1,15 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/download/android/download_media_parser_bridge.h"
-
+#include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.h"
 #include "base/android/callback_android.h"
 #include "base/android/jni_string.h"
 #include "base/bind.h"
 #include "base/files/file_path.h"
 #include "base/task/post_task.h"
-#include "chrome/android/chrome_jni_headers/DownloadMediaData_jni.h"
-#include "chrome/android/chrome_jni_headers/DownloadMediaParserBridge_jni.h"
+#include "chrome/browser/thumbnail/generator/test_support_jni_headers/ThumbnailMediaData_jni.h"
+#include "chrome/browser/thumbnail/generator/test_support_jni_headers/ThumbnailMediaParserBridge_jni.h"
 #include "third_party/skia/include/core/SkBitmap.h"
 #include "ui/gfx/android/java_bitmap.h"
 
@@ -32,7 +31,7 @@
 
   base::android::ScopedJavaLocalRef<jobject> media_data;
   if (success) {
-    media_data = Java_DownloadMediaData_Constructor(
+    media_data = Java_ThumbnailMediaData_Constructor(
         env, metadata->duration, ConvertUTF8ToJavaString(env, metadata->title),
         ConvertUTF8ToJavaString(env, metadata->artist), std::move(java_bitmap));
   }
@@ -43,7 +42,7 @@
 }  // namespace
 
 // static
-jlong JNI_DownloadMediaParserBridge_Init(
+jlong JNI_ThumbnailMediaParserBridge_Init(
     JNIEnv* env,
     const base::android::JavaParamRef<jobject>& jcaller,
     const base::android::JavaParamRef<jstring>& jmime_type,
@@ -54,26 +53,26 @@
   std::string mime_type =
       base::android::ConvertJavaStringToUTF8(env, jmime_type);
 
-  auto* bridge = new DownloadMediaParserBridge(
+  auto* bridge = new ThumbnailMediaParserBridge(
       mime_type, file_path,
       base::BindOnce(&OnMediaParsed,
                      base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
   return reinterpret_cast<intptr_t>(bridge);
 }
 
-DownloadMediaParserBridge::DownloadMediaParserBridge(
+ThumbnailMediaParserBridge::ThumbnailMediaParserBridge(
     const std::string& mime_type,
     const base::FilePath& file_path,
-    DownloadMediaParser::ParseCompleteCB parse_complete_cb)
-    : parser_(std::make_unique<DownloadMediaParser>(mime_type, file_path)),
+    ThumbnailMediaParser::ParseCompleteCB parse_complete_cb)
+    : parser_(std::make_unique<ThumbnailMediaParser>(mime_type, file_path)),
       parse_complete_cb_(std::move(parse_complete_cb)) {}
 
-DownloadMediaParserBridge::~DownloadMediaParserBridge() = default;
+ThumbnailMediaParserBridge::~ThumbnailMediaParserBridge() = default;
 
-void DownloadMediaParserBridge::Destroy(JNIEnv* env, jobject obj) {
+void ThumbnailMediaParserBridge::Destroy(JNIEnv* env, jobject obj) {
   delete this;
 }
 
-void DownloadMediaParserBridge::Start(JNIEnv* env, jobject obj) {
+void ThumbnailMediaParserBridge::Start(JNIEnv* env, jobject obj) {
   parser_->Start(std::move(parse_complete_cb_));
 }
diff --git a/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.h b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.h
new file mode 100644
index 0000000..fa20270
--- /dev/null
+++ b/chrome/browser/thumbnail/generator/android/thumbnail_media_parser_bridge.h
@@ -0,0 +1,38 @@
+// Copyright 2018 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_BRIDGE_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_BRIDGE_H_
+
+#include <memory>
+
+#include "base/android/scoped_java_ref.h"
+#include "base/macros.h"
+#include "base/single_thread_task_runner.h"
+#include "chrome/browser/thumbnail/generator/android/thumbnail_media_parser.h"
+
+class ThumbnailMediaParser;
+
+// The JNI bridge that uses MediaParser to parse local media file. The
+// bridge is owned by the Java side.
+class ThumbnailMediaParserBridge {
+ public:
+  ThumbnailMediaParserBridge(
+      const std::string& mime_type,
+      const base::FilePath& file_path,
+      ThumbnailMediaParser::ParseCompleteCB parse_complete_cb);
+  ~ThumbnailMediaParserBridge();
+
+  void Destroy(JNIEnv* env, jobject obj);
+  void Start(JNIEnv* env, jobject obj);
+
+ private:
+  // The media parser that does actual jobs in a sandboxed process.
+  std::unique_ptr<ThumbnailMediaParser> parser_;
+  ThumbnailMediaParser::ParseCompleteCB parse_complete_cb_;
+
+  DISALLOW_COPY_AND_ASSIGN(ThumbnailMediaParserBridge);
+};
+
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_ANDROID_THUMBNAIL_MEDIA_PARSER_BRIDGE_H_
diff --git a/chrome/browser/download/image_thumbnail_request.cc b/chrome/browser/thumbnail/generator/image_thumbnail_request.cc
similarity index 94%
rename from chrome/browser/download/image_thumbnail_request.cc
rename to chrome/browser/thumbnail/generator/image_thumbnail_request.cc
index 8a373a3..35fb21cd 100644
--- a/chrome/browser/download/image_thumbnail_request.cc
+++ b/chrome/browser/thumbnail/generator/image_thumbnail_request.cc
@@ -1,8 +1,8 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/download/image_thumbnail_request.h"
+#include "chrome/browser/thumbnail/generator/image_thumbnail_request.h"
 
 #include <memory>
 #include <utility>
@@ -12,7 +12,7 @@
 #include "base/task/post_task.h"
 #include "base/threading/scoped_blocking_call.h"
 #include "build/build_config.h"
-#include "chrome/browser/download/thumbnail_util.h"
+#include "chrome/browser/thumbnail/generator/thumbnail_util.h"
 #include "content/public/browser/browser_task_traits.h"
 #include "content/public/browser/browser_thread.h"
 #include "skia/ext/image_operations.h"
diff --git a/chrome/browser/download/image_thumbnail_request.h b/chrome/browser/thumbnail/generator/image_thumbnail_request.h
similarity index 79%
rename from chrome/browser/download/image_thumbnail_request.h
rename to chrome/browser/thumbnail/generator/image_thumbnail_request.h
index 05c5e0f..35ca6c0 100644
--- a/chrome/browser/download/image_thumbnail_request.h
+++ b/chrome/browser/thumbnail/generator/image_thumbnail_request.h
@@ -1,14 +1,14 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_DOWNLOAD_IMAGE_THUMBNAIL_REQUEST_H_
-#define CHROME_BROWSER_DOWNLOAD_IMAGE_THUMBNAIL_REQUEST_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_IMAGE_THUMBNAIL_REQUEST_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_IMAGE_THUMBNAIL_REQUEST_H_
 
 #include <vector>
 
 #include "base/memory/weak_ptr.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 
 namespace base {
 class FilePath;
@@ -45,4 +45,4 @@
   DISALLOW_COPY_AND_ASSIGN(ImageThumbnailRequest);
 };
 
-#endif  // CHROME_BROWSER_DOWNLOAD_IMAGE_THUMBNAIL_REQUEST_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_IMAGE_THUMBNAIL_REQUEST_H_
diff --git a/chrome/test/data/android/thumbnail_provider/test_image_10x10.jpg b/chrome/browser/thumbnail/generator/test/data/android/test_image_10x10.jpg
similarity index 100%
rename from chrome/test/data/android/thumbnail_provider/test_image_10x10.jpg
rename to chrome/browser/thumbnail/generator/test/data/android/test_image_10x10.jpg
Binary files differ
diff --git a/chrome/test/data/android/thumbnail_provider/test_image_10x20.jpg b/chrome/browser/thumbnail/generator/test/data/android/test_image_10x20.jpg
similarity index 100%
rename from chrome/test/data/android/thumbnail_provider/test_image_10x20.jpg
rename to chrome/browser/thumbnail/generator/test/data/android/test_image_10x20.jpg
Binary files differ
diff --git a/chrome/test/data/android/thumbnail_provider/test_image_20x10.jpg b/chrome/browser/thumbnail/generator/test/data/android/test_image_20x10.jpg
similarity index 100%
rename from chrome/test/data/android/thumbnail_provider/test_image_20x10.jpg
rename to chrome/browser/thumbnail/generator/test/data/android/test_image_20x10.jpg
Binary files differ
diff --git a/chrome/test/data/android/thumbnail_provider/test_image_20x20.jpg b/chrome/browser/thumbnail/generator/test/data/android/test_image_20x20.jpg
similarity index 100%
rename from chrome/test/data/android/thumbnail_provider/test_image_20x20.jpg
rename to chrome/browser/thumbnail/generator/test/data/android/test_image_20x20.jpg
Binary files differ
diff --git a/chrome/browser/download/thumbnail_util.cc b/chrome/browser/thumbnail/generator/thumbnail_util.cc
similarity index 92%
rename from chrome/browser/download/thumbnail_util.cc
rename to chrome/browser/thumbnail/generator/thumbnail_util.cc
index da0304f..d96b746 100644
--- a/chrome/browser/download/thumbnail_util.cc
+++ b/chrome/browser/thumbnail/generator/thumbnail_util.cc
@@ -1,8 +1,8 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "chrome/browser/download/thumbnail_util.h"
+#include "chrome/browser/thumbnail/generator/thumbnail_util.h"
 
 #include "base/bind.h"
 #include "base/logging.h"
diff --git a/chrome/browser/download/thumbnail_util.h b/chrome/browser/thumbnail/generator/thumbnail_util.h
similarity index 65%
rename from chrome/browser/download/thumbnail_util.h
rename to chrome/browser/thumbnail/generator/thumbnail_util.h
index a337651..bb76162 100644
--- a/chrome/browser/download/thumbnail_util.h
+++ b/chrome/browser/thumbnail/generator/thumbnail_util.h
@@ -1,9 +1,9 @@
-// Copyright 2018 The Chromium Authors. All rights reserved.
+// Copyright 2019 The Chromium Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#ifndef CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
-#define CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
+#ifndef CHROME_BROWSER_THUMBNAIL_GENERATOR_THUMBNAIL_UTIL_H_
+#define CHROME_BROWSER_THUMBNAIL_GENERATOR_THUMBNAIL_UTIL_H_
 
 #include "base/callback.h"
 
@@ -16,4 +16,4 @@
                      const SkBitmap& bitmap,
                      base::OnceCallback<void(SkBitmap)> callback);
 
-#endif  // CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
+#endif  // CHROME_BROWSER_THUMBNAIL_GENERATOR_THUMBNAIL_UTIL_H_
diff --git a/chrome/browser/ui/BUILD.gn b/chrome/browser/ui/BUILD.gn
index f62642c1..2fc58b6 100644
--- a/chrome/browser/ui/BUILD.gn
+++ b/chrome/browser/ui/BUILD.gn
@@ -394,6 +394,7 @@
     "//chrome/browser:resource_prefetch_predictor_proto",
     "//chrome/browser/devtools",
     "//chrome/browser/engagement:mojo_bindings",
+    "//chrome/browser/image_decoder",
     "//chrome/browser/media:mojo_bindings",
     "//chrome/browser/notifications/scheduler/public",
     "//chrome/browser/profiling_host",
@@ -807,6 +808,7 @@
       "//chrome/android:jni_headers",
       "//chrome/android/features/dev_ui:buildflags",
       "//chrome/browser/android/thin_webview:thin_webview",
+      "//chrome/browser/image_decoder",
       "//chrome/browser/resources/webapks:webapks_ui_resources",
       "//components/app_modal/android:jni_headers",
       "//components/embedder_support/android:web_contents_delegate",
diff --git a/chrome/browser/ui/DEPS b/chrome/browser/ui/DEPS
index 52ec7c6..d8238e0 100644
--- a/chrome/browser/ui/DEPS
+++ b/chrome/browser/ui/DEPS
@@ -1,4 +1,5 @@
 include_rules = [
+  "+chrome/browser/image_decoder",
   "-chrome/browser/ui/views",
   "+components/page_load_metrics/browser",
   "+mash/public/mojom",
diff --git a/chrome/browser/ui/android/context_menu_helper.cc b/chrome/browser/ui/android/context_menu_helper.cc
index a854a3b..604951cd 100644
--- a/chrome/browser/ui/android/context_menu_helper.cc
+++ b/chrome/browser/ui/android/context_menu_helper.cc
@@ -16,7 +16,7 @@
 #include "chrome/android/chrome_jni_headers/ContextMenuHelper_jni.h"
 #include "chrome/android/chrome_jni_headers/ContextMenuParams_jni.h"
 #include "chrome/browser/download/android/download_controller_base.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/performance_hints/performance_hints_observer.h"
 #include "chrome/browser/ui/tab_contents/core_tab_helper.h"
 #include "chrome/browser/vr/vr_tab_helper.h"
diff --git a/chrome/browser/ui/app_list/arc/arc_app_icon.cc b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
index f2d1c16..b10f427 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_icon.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_icon.cc
@@ -17,7 +17,7 @@
 #include "base/macros.h"
 #include "base/metrics/histogram_functions.h"
 #include "base/task/post_task.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_utils.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_shelf_id.h"
diff --git a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
index 6135210..b4f336a 100644
--- a/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
+++ b/chrome/browser/ui/app_list/arc/arc_app_list_prefs.cc
@@ -24,7 +24,7 @@
 #include "chrome/browser/chromeos/arc/session/arc_session_manager.h"
 #include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
 #include "chrome/browser/chromeos/login/session/user_session_manager.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_list_prefs_factory.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_scoped_pref_update.h"
diff --git a/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc b/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc
index 2d63183f..1aebb5b 100644
--- a/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc
+++ b/chrome/browser/ui/app_list/crostini/crostini_app_icon.cc
@@ -19,7 +19,7 @@
 #include "chrome/browser/chromeos/crostini/crostini_registry_service.h"
 #include "chrome/browser/chromeos/crostini/crostini_registry_service_factory.h"
 #include "chrome/browser/chromeos/crostini/crostini_util.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/profiles/profile.h"
 #include "chrome/grit/chrome_unscaled_resources.h"
 #include "content/public/browser/browser_thread.h"
diff --git a/chrome/browser/ui/app_list/search/common/url_icon_source.h b/chrome/browser/ui/app_list/search/common/url_icon_source.h
index 153b92a..b4f51cae 100644
--- a/chrome/browser/ui/app_list/search/common/url_icon_source.h
+++ b/chrome/browser/ui/app_list/search/common/url_icon_source.h
@@ -11,7 +11,7 @@
 #include "base/callback.h"
 #include "base/macros.h"
 #include "base/memory/ref_counted.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "ui/gfx/image/image_skia.h"
 #include "ui/gfx/image/image_skia_source.h"
 #include "url/gurl.h"
diff --git a/chrome/browser/ui/ash/launcher/arc_app_window.h b/chrome/browser/ui/ash/launcher/arc_app_window.h
index e76c20b..e6f45468 100644
--- a/chrome/browser/ui/ash/launcher/arc_app_window.h
+++ b/chrome/browser/ui/ash/launcher/arc_app_window.h
@@ -11,7 +11,7 @@
 #include "ash/public/cpp/shelf_types.h"
 #include "base/macros.h"
 #include "base/timer/timer.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/ui/app_list/arc/arc_app_icon_loader.h"
 #include "chrome/browser/ui/ash/launcher/app_window_base.h"
 #include "chrome/browser/ui/ash/launcher/arc_app_shelf_id.h"
diff --git a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
index a3bb95d2..1be240f6 100644
--- a/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
+++ b/chrome/browser/ui/webui/settings/chromeos/change_picture_handler.h
@@ -9,7 +9,7 @@
 #include "base/memory/weak_ptr.h"
 #include "base/scoped_observer.h"
 #include "chrome/browser/chromeos/camera_presence_notifier.h"
-#include "chrome/browser/image_decoder.h"
+#include "chrome/browser/image_decoder/image_decoder.h"
 #include "chrome/browser/ui/webui/settings/settings_page_ui_handler.h"
 #include "components/user_manager/user_manager.h"
 #include "ui/gfx/image/image_skia.h"
diff --git a/chrome/test/BUILD.gn b/chrome/test/BUILD.gn
index faedbb40..8e78563 100644
--- a/chrome/test/BUILD.gn
+++ b/chrome/test/BUILD.gn
@@ -676,6 +676,7 @@
       "//chrome:strings",
       "//chrome/browser",
       "//chrome/browser/devtools:test_support",
+      "//chrome/browser/image_decoder:browser_tests",
       "//chrome/browser/metrics:test_support",
       "//chrome/browser/notifications/scheduler/test:test_support",
       "//chrome/browser/profiling_host:profiling_browsertests",
@@ -925,7 +926,6 @@
       "../browser/history/history_browsertest.cc",
       "../browser/history/redirect_browsertest.cc",
       "../browser/iframe_browsertest.cc",
-      "../browser/image_decoder_browsertest.cc",
       "../browser/image_fetcher/image_fetcher_impl_browsertest.cc",
       "../browser/importer/edge_importer_browsertest_win.cc",
       "../browser/importer/firefox_importer_browsertest.cc",
@@ -3024,7 +3024,6 @@
     "../browser/android/preferences/prefs_unittest.cc",
     "../browser/android/shortcut_info_unittest.cc",
     "../browser/android/signin/signin_manager_android_unittest.cc",
-    "../browser/android/thumbnail/scoped_ptr_expiring_cache_unittest.cc",
     "../browser/android/usage_stats/usage_stats_database_unittest.cc",
     "../browser/android/webapk/webapk_icon_hasher_unittest.cc",
     "../browser/android/webapk/webapk_installer_unittest.cc",
@@ -3804,6 +3803,7 @@
       "//chrome/android:native_j_unittests_jni_headers",
       "//chrome/android:native_java_unittests_java",
       "//chrome/android/features/media_router:java",
+      "//chrome/browser/thumbnail:unit_tests",
       "//chrome/browser/updates:unit_tests",
       "//chrome/services/media_gallery_util:unit_tests",
       "//components/download/internal/common:internal_java",
diff --git a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/SuggestionsDependenciesRule.java b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/SuggestionsDependenciesRule.java
index 7460e3c6..26ad9ca 100644
--- a/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/SuggestionsDependenciesRule.java
+++ b/chrome/test/android/javatests/src/org/chromium/chrome/test/util/browser/suggestions/SuggestionsDependenciesRule.java
@@ -16,7 +16,7 @@
 import org.chromium.chrome.browser.suggestions.SuggestionsDependencyFactory;
 import org.chromium.chrome.browser.suggestions.SuggestionsEventReporter;
 import org.chromium.chrome.browser.suggestions.mostvisited.MostVisitedSites;
-import org.chromium.chrome.browser.widget.ThumbnailProvider;
+import org.chromium.chrome.browser.thumbnail.generator.ThumbnailProvider;
 
 /**
  * Rule that allows mocking native dependencies of the suggestions package.