Commit 25a3837e authored by Xing Liu's avatar Xing Liu Committed by Commit Bot

Android Video Thumbnail: Hook video thumbnail backend to UI.

This CL hooks the video thumbnail backend to the UI layer of new
download home.

Bug: 826021
Change-Id: I190ad09e8231d94d7546128bd1d22dc39f4d5f35
Reviewed-on: https://chromium-review.googlesource.com/1247529
Commit-Queue: Xing Liu <xingliu@chromium.org>
Reviewed-by: default avatarDavid Trainor <dtrainor@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595706}
parent 39b15590
......@@ -19,7 +19,7 @@
android:id="@+id/thumbnail"
android:layout_width="match_parent"
android:layout_height="200dp"
android:scaleType="centerInside"
android:scaleType="centerCrop"
android:adjustViewBounds="true"
app:layout_column="0"
app:layout_row="0"
......
......@@ -19,9 +19,9 @@ public class DownloadMediaParserBridge {
* @param totalSize Total size of the media file.
* @param callback Callback to get the result.
*/
public DownloadMediaParserBridge(String mimeType, String filePath, long totalSize,
Callback<DownloadMediaData> callback) {
mNativeDownloadMediaParserBridge = nativeInit(mimeType, filePath, totalSize, callback);
public DownloadMediaParserBridge(
String mimeType, String filePath, Callback<DownloadMediaData> callback) {
mNativeDownloadMediaParserBridge = nativeInit(mimeType, filePath, callback);
}
/**
......@@ -43,7 +43,7 @@ public class DownloadMediaParserBridge {
}
private native long nativeInit(
String mimeType, String filePath, long totalSize, Callback<DownloadMediaData> callback);
String mimeType, String filePath, Callback<DownloadMediaData> callback);
private native void nativeDestory(long nativeDownloadMediaParserBridge);
private native void nativeStart(long nativeDownloadMediaParserBridge);
}
......@@ -7,14 +7,17 @@ package org.chromium.chrome.browser.download.home.glue;
import android.graphics.Bitmap;
import org.chromium.base.Callback;
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.components.offline_items_collection.OfflineContentProvider;
import org.chromium.components.offline_items_collection.OfflineItem;
import org.chromium.components.offline_items_collection.OfflineItemVisuals;
import org.chromium.components.offline_items_collection.VisualsCallback;
/**
* Glue class responsible for connecting the current downloads and {@link OfflineContentProvider}
* thumbnail work to the {@link ThumbnailProvider} via a custon {@link ThumbnailProviderImpl}.
* thumbnail work to the {@link ThumbnailProvider} via a custom {@link ThumbnailProviderImpl}.
*/
public class ThumbnailRequestGlue implements ThumbnailRequest {
private final OfflineContentProviderGlue mProvider;
......@@ -39,6 +42,11 @@ public class ThumbnailRequestGlue implements ThumbnailRequest {
return mItem.filePath;
}
@Override
public String getMimeType() {
return mItem.mimeType;
}
@Override
public String getContentId() {
return mItem.id.id;
......@@ -71,4 +79,4 @@ public class ThumbnailRequestGlue implements ThumbnailRequest {
}
});
}
}
\ No newline at end of file
}
......@@ -117,9 +117,7 @@ public final class UiUtils {
public static boolean canHaveThumbnails(OfflineItem item) {
switch (item.filter) {
case OfflineItemFilter.FILTER_PAGE:
// TODO(shaktisahu, xingliu): Remove this after video thumbnail generation pipeline is
// done.
// case OfflineItemFilter.FILTER_VIDEO:
case OfflineItemFilter.FILTER_VIDEO:
case OfflineItemFilter.FILTER_IMAGE:
return true;
default:
......
......@@ -178,6 +178,11 @@ public class DownloadItemView extends SelectableItemView<DownloadHistoryItemWrap
return mItem == null ? null : mItem.getFilePath();
}
@Override
public String getMimeType() {
return mItem == null ? null : mItem.getMimeType();
}
@Override
public @Nullable String getContentId() {
return mItem == null ? "" : mItem.getId();
......
......@@ -390,5 +390,10 @@ public class ImageFetcher {
public Promise<Bitmap> getPromise() {
return mThumbnailReceivedPromise;
}
@Override
public String getMimeType() {
return null;
}
}
}
......@@ -42,7 +42,7 @@ public class ThumbnailGenerator {
boolean hasFilePath = !TextUtils.isEmpty(request.getFilePath());
assert hasFilePath;
nativeRetrieveThumbnail(getNativeThumbnailGenerator(), request.getContentId(),
request.getFilePath(), request.getIconSize(), callback);
request.getFilePath(), request.getMimeType(), request.getIconSize(), callback);
}
/**
......@@ -80,5 +80,6 @@ public class ThumbnailGenerator {
private native long nativeInit();
private native void nativeDestroy(long nativeThumbnailGenerator);
private native void nativeRetrieveThumbnail(long nativeThumbnailGenerator, String contentId,
String filePath, int thumbnailSize, ThumbnailGeneratorCallback callback);
}
\ No newline at end of file
String filePath, String mimeType, int thumbnailSize,
ThumbnailGeneratorCallback callback);
}
......@@ -20,6 +20,10 @@ public interface ThumbnailProvider {
@Nullable
String getFilePath();
/** The mime type of the file. */
@Nullable
String getMimeType();
/** Content ID that uniquely identifies the file. */
@Nullable
String getContentId();
......
......@@ -63,7 +63,7 @@ public class DownloadMediaParserTest {
// The native DownloadMediaParser needs to be created on UI thread.
ThreadUtils.runOnUiThreadBlocking(() -> {
DownloadMediaParserBridge parser = new DownloadMediaParserBridge(
mimeType, filePath, mediaFile.length(), (DownloadMediaData mediaData) -> {
mimeType, filePath, (DownloadMediaData mediaData) -> {
result.mediaData = mediaData;
result.done = true;
});
......
......@@ -63,6 +63,11 @@ public class ThumbnailDiskStorageTest {
return null;
}
@Override
public String getMimeType() {
return null;
}
@Override
public String getContentId() {
return mContentId;
......
......@@ -188,6 +188,11 @@ public class ThumbnailProviderImplTest {
return mTestFilePath;
}
@Override
public String getMimeType() {
return null;
}
@Override
public @Nullable String getContentId() {
return "contentId"; // None-null value for ThumbnailProviderImpl to work
......
......@@ -455,6 +455,8 @@ jumbo_split_static_library("browser") {
"download/offline_item_utils.h",
"download/save_package_file_picker.cc",
"download/save_package_file_picker.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",
......
......@@ -6,9 +6,11 @@
#include "base/bind.h"
#include "base/files/file.h"
#include "base/files/file_util.h"
#include "base/numerics/safe_conversions.h"
#include "base/task/post_task.h"
#include "base/task/task_traits.h"
#include "base/task_runner_util.h"
#include "cc/paint/skia_paint_canvas.h"
#include "chrome/browser/android/download/local_media_data_source_factory.h"
#include "content/public/browser/android/gpu_video_accelerator_factories_provider.h"
......@@ -38,19 +40,23 @@ bool IsSupportedMediaMimeType(const std::string& mime_type) {
void OnRequestOverlayInfo(bool decoder_requires_restart_for_overlay,
const media::ProvideOverlayInfoCB& overlay_info_cb) {
// No android overlay associated with video thumbnail.
overlay_info_cb.Run(media::OverlayInfo());
if (overlay_info_cb)
overlay_info_cb.Run(media::OverlayInfo());
}
int64_t GetFileSize(const base::FilePath& file_path) {
int64_t size = 0;
if (!base::GetFileSize(file_path, &size))
return -1;
return size;
}
} // namespace
DownloadMediaParser::DownloadMediaParser(int64_t size,
const std::string& mime_type,
const base::FilePath& file_path,
ParseCompleteCB parse_complete_cb)
: size_(size),
mime_type_(mime_type),
DownloadMediaParser::DownloadMediaParser(const std::string& mime_type,
const base::FilePath& file_path)
: mime_type_(mime_type),
file_path_(file_path),
parse_complete_cb_(std::move(parse_complete_cb)),
file_task_runner_(
base::CreateSingleThreadTaskRunnerWithTraits({base::MayBlock()})),
decode_done_(false),
......@@ -58,13 +64,30 @@ DownloadMediaParser::DownloadMediaParser(int64_t size,
DownloadMediaParser::~DownloadMediaParser() = default;
void DownloadMediaParser::Start() {
void DownloadMediaParser::Start(ParseCompleteCB parse_complete_cb) {
parse_complete_cb_ = std::move(parse_complete_cb);
// Only process media mime types.
if (!IsSupportedMediaMimeType(mime_type_)) {
OnError();
return;
}
// Get the size of the file if needed.
base::PostTaskAndReplyWithResult(
file_task_runner_.get(), FROM_HERE,
base::BindOnce(&GetFileSize, file_path_),
base::BindOnce(&DownloadMediaParser::OnReadFileSize,
weak_factory_.GetWeakPtr()));
}
void DownloadMediaParser::OnReadFileSize(int64_t file_size) {
if (file_size < 0) {
OnError();
return;
}
size_ = file_size;
RetrieveMediaParser(
content::ServiceManagerConnection::GetForProcess()->GetConnector());
}
......@@ -188,6 +211,7 @@ void DownloadMediaParser::DecodeVideoFrame() {
decoder_->Start(base::BindOnce(&DownloadMediaParser::OnVideoFrameDecoded,
weak_factory_.GetWeakPtr()));
video_frame_data_.reset();
}
void DownloadMediaParser::OnVideoFrameDecoded(
......
......@@ -34,9 +34,9 @@ class SkBitmap;
// Parse local media files, including media metadata and thumbnails.
// Metadata is always parsed in utility process for both audio and video files.
//
// For video file, the thumbnail may be poster image in metadata or extracted
// video frame. The frame extraction always happens in utility process. The
// decoding may happen in utility or GPU process based on video codec.
// 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 {
public:
using ParseCompleteCB =
......@@ -44,19 +44,19 @@ class DownloadMediaParser : public MediaParserProvider, public media::MediaLog {
chrome::mojom::MediaMetadataPtr media_metadata,
SkBitmap bitmap)>;
DownloadMediaParser(int64_t size,
const std::string& mime_type,
const base::FilePath& file_path,
ParseCompleteCB parse_complete_cb);
DownloadMediaParser(const std::string& mime_type,
const base::FilePath& file_path);
~DownloadMediaParser() override;
// Parse media metadata in a local file. All file IO will run on
// 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.
// The thumbnail is retrieved from GPU process or utility process based on
// different codec.
void Start();
void Start(ParseCompleteCB parse_complete_cb);
private:
void OnReadFileSize(int64_t file_size);
// MediaParserProvider implementation:
void OnMediaParserCreated() override;
void OnConnectionError() override;
......
......@@ -47,7 +47,6 @@ jlong JNI_DownloadMediaParserBridge_Init(
const base::android::JavaParamRef<jobject>& jcaller,
const base::android::JavaParamRef<jstring>& jmime_type,
const base::android::JavaParamRef<jstring>& jfile_path,
jlong jtotal_size,
const base::android::JavaParamRef<jobject>& jcallback) {
base::FilePath file_path(
base::android::ConvertJavaStringToUTF8(env, jfile_path));
......@@ -55,22 +54,18 @@ jlong JNI_DownloadMediaParserBridge_Init(
base::android::ConvertJavaStringToUTF8(env, jmime_type);
auto* bridge = new DownloadMediaParserBridge(
static_cast<int64_t>(jtotal_size), mime_type, file_path,
mime_type, file_path,
base::BindOnce(&OnMediaParsed,
base::android::ScopedJavaGlobalRef<jobject>(jcallback)));
return reinterpret_cast<intptr_t>(bridge);
}
DownloadMediaParserBridge::DownloadMediaParserBridge(
int64_t size,
const std::string& mime_type,
const base::FilePath& file_path,
DownloadMediaParser::ParseCompleteCB parse_complete_cb)
: parser_(std::make_unique<DownloadMediaParser>(
size,
mime_type,
file_path,
std::move(parse_complete_cb))) {}
: parser_(std::make_unique<DownloadMediaParser>(mime_type, file_path)),
parse_complete_cb_(std::move(parse_complete_cb)) {}
DownloadMediaParserBridge::~DownloadMediaParserBridge() = default;
......@@ -79,5 +74,5 @@ void DownloadMediaParserBridge::Destory(JNIEnv* env, jobject obj) {
}
void DownloadMediaParserBridge::Start(JNIEnv* env, jobject obj) {
parser_->Start();
parser_->Start(std::move(parse_complete_cb_));
}
......@@ -19,7 +19,6 @@ class DownloadMediaParser;
class DownloadMediaParserBridge {
public:
DownloadMediaParserBridge(
int64_t size,
const std::string& mime_type,
const base::FilePath& file_path,
DownloadMediaParser::ParseCompleteCB parse_complete_cb);
......@@ -31,6 +30,7 @@ class DownloadMediaParserBridge {
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);
};
......
......@@ -8,6 +8,8 @@
#include "base/android/jni_string.h"
#include "base/threading/thread_restrictions.h"
#include "chrome/browser/android/download/download_media_parser.h"
#include "chrome/browser/download/thumbnail_util.h"
#include "content/public/browser/browser_thread.h"
#include "jni/ThumbnailGenerator_jni.h"
#include "ui/gfx/android/java_bitmap.h"
......@@ -15,6 +17,30 @@
class SkBitmap;
using base::android::JavaParamRef;
using base::android::ScopedJavaGlobalRef;
namespace {
void ForwardJavaCallback(const ScopedJavaGlobalRef<jobject>& java_delegate,
const ScopedJavaGlobalRef<jstring>& content_id,
int icon_size,
const ScopedJavaGlobalRef<jobject>& callback,
SkBitmap thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
JNIEnv* env = base::android::AttachCurrentThread();
Java_ThumbnailGenerator_onThumbnailRetrieved(
env, java_delegate, content_id, icon_size,
thumbnail.drawsNothing() ? NULL : gfx::ConvertToJavaBitmap(&thumbnail),
callback);
}
void OnThumbnailScaled(base::OnceCallback<void(SkBitmap)> java_callback,
SkBitmap scaled_thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::move(java_callback).Run(std::move(scaled_thumbnail));
}
} // namespace
ThumbnailGenerator::ThumbnailGenerator(const JavaParamRef<jobject>& jobj)
: java_delegate_(jobj), weak_factory_(this) {
......@@ -29,19 +55,27 @@ void ThumbnailGenerator::Destroy(JNIEnv* env,
delete this;
}
void ThumbnailGenerator::OnThumbnailRetrieved(
const base::android::ScopedJavaGlobalRef<jstring>& content_id,
int icon_size,
const base::android::ScopedJavaGlobalRef<jobject>& callback,
void ThumbnailGenerator::OnImageThumbnailRetrieved(
base::OnceCallback<void(SkBitmap)> java_callback,
const SkBitmap& thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Send the bitmap back to Java-land.
JNIEnv* env = base::android::AttachCurrentThread();
Java_ThumbnailGenerator_onThumbnailRetrieved(
env, java_delegate_, content_id, icon_size,
thumbnail.drawsNothing() ? NULL : gfx::ConvertToJavaBitmap(&thumbnail),
callback);
std::move(java_callback).Run(std::move(thumbnail));
}
void ThumbnailGenerator::OnVideoThumbnailRetrieved(
base::OnceCallback<void(SkBitmap)> java_callback,
int icon_size,
std::unique_ptr<DownloadMediaParser> parser,
bool success,
chrome::mojom::MediaMetadataPtr media_metadata,
SkBitmap thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
// Scale the bitmap before sending back to Java.
ScaleDownBitmap(icon_size, std::move(thumbnail),
base::BindOnce(&OnThumbnailScaled, std::move(java_callback)));
}
void ThumbnailGenerator::RetrieveThumbnail(
......@@ -49,20 +83,42 @@ void ThumbnailGenerator::RetrieveThumbnail(
const JavaParamRef<jobject>& jobj,
const JavaParamRef<jstring>& jcontent_id,
const JavaParamRef<jstring>& jfile_path,
const JavaParamRef<jstring>& jmime_type,
jint icon_size,
const JavaParamRef<jobject>& callback) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
std::string file_path =
base::android::ConvertJavaStringToUTF8(env, jfile_path);
base::FilePath file_path = base::FilePath::FromUTF8Unsafe(
base::android::ConvertJavaStringToUTF8(env, jfile_path));
std::string mime_type =
jmime_type.is_null()
? ""
: base::android::ConvertJavaStringToUTF8(env, jmime_type);
// Bind everything passed back to Java.
auto java_callback =
base::BindOnce(&ForwardJavaCallback, java_delegate_,
ScopedJavaGlobalRef<jstring>(jcontent_id), icon_size,
ScopedJavaGlobalRef<jobject>(callback));
// Retrieve video thumbnail.
if (base::StartsWith(mime_type, "video/",
base::CompareCase::INSENSITIVE_ASCII)) {
auto parser = std::make_unique<DownloadMediaParser>(mime_type, file_path);
parser->Start(base::BindOnce(&ThumbnailGenerator::OnVideoThumbnailRetrieved,
weak_factory_.GetWeakPtr(),
std::move(java_callback), icon_size,
std::move(parser)));
return;
}
// Retrieve image thumbnail.
auto request = std::make_unique<ImageThumbnailRequest>(
icon_size,
base::BindOnce(
&ThumbnailGenerator::OnThumbnailRetrieved, weak_factory_.GetWeakPtr(),
base::android::ScopedJavaGlobalRef<jstring>(jcontent_id), icon_size,
base::android::ScopedJavaGlobalRef<jobject>(callback)));
request->Start(base::FilePath::FromUTF8Unsafe(file_path));
base::BindOnce(&ThumbnailGenerator::OnImageThumbnailRetrieved,
weak_factory_.GetWeakPtr(), std::move(java_callback)));
request->Start(file_path);
// Dropping ownership of |request| here because it will clean itself up once
// the started request finishes.
......
......@@ -5,11 +5,15 @@
#ifndef CHROME_BROWSER_ANDROID_WIDGET_THUMBNAIL_GENERATOR_H_
#define CHROME_BROWSER_ANDROID_WIDGET_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/services/media_gallery_util/public/mojom/media_parser.mojom.h"
class DownloadMediaParser;
// Kicks off asynchronous pipelines for creating thumbnails for local files.
// The native-side ThumbnailGenerator is owned by the Java-side and can be
......@@ -31,19 +35,29 @@ class ThumbnailGenerator {
const base::android::JavaParamRef<jobject>& jobj,
const base::android::JavaParamRef<jstring>& jcontent_id,
const base::android::JavaParamRef<jstring>& jfile_path,
const base::android::JavaParamRef<jstring>& jmime_type,
jint icon_size,
const base::android::JavaParamRef<jobject>& callback);
private:
~ThumbnailGenerator();
// Called when the thumbnail is ready. |thumbnail| will be empty on failure.
void OnThumbnailRetrieved(
const base::android::ScopedJavaGlobalRef<jstring>& content_id,
int icon_size,
const base::android::ScopedJavaGlobalRef<jobject>& callback,
// Called when the image thumbnail is ready. |thumbnail| will be empty on
// failure.
void OnImageThumbnailRetrieved(
base::OnceCallback<void(SkBitmap)> java_callback,
const SkBitmap& thumbnail);
// Called when the video thumbnail is ready. |thumbnail| will be empty on
// failure.
void OnVideoThumbnailRetrieved(
base::OnceCallback<void(SkBitmap)> java_callback,
int icon_size,
std::unique_ptr<DownloadMediaParser> parser,
bool success,
chrome::mojom::MediaMetadataPtr media_metadata,
SkBitmap thumbnail);
// This is a {@link ThumbnailGenerator} Java object.
base::android::ScopedJavaGlobalRef<jobject> java_delegate_;
base::WeakPtrFactory<ThumbnailGenerator> weak_factory_;
......
......@@ -9,6 +9,7 @@
#include "base/files/file_util.h"
#include "base/task/post_task.h"
#include "base/threading/scoped_blocking_call.h"
#include "chrome/browser/download/thumbnail_util.h"
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "skia/ext/image_operations.h"
......@@ -41,26 +42,6 @@ std::string LoadImageData(const base::FilePath& path) {
return data;
}
SkBitmap ScaleDownBitmap(int icon_size, const SkBitmap& decoded_image) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (decoded_image.drawsNothing())
return decoded_image;
// Shrink the image down so that its smallest dimension is equal to or
// smaller than the requested size.
int min_dimension = std::min(decoded_image.width(), decoded_image.height());
if (min_dimension <= icon_size)
return decoded_image;
uint64_t width = static_cast<uint64_t>(decoded_image.width());
uint64_t height = static_cast<uint64_t>(decoded_image.height());
return skia::ImageOperations::Resize(
decoded_image, skia::ImageOperations::RESIZE_BEST,
width * icon_size / min_dimension, height * icon_size / min_dimension);
}
} // namespace
ImageThumbnailRequest::ImageThumbnailRequest(
......@@ -87,11 +68,9 @@ void ImageThumbnailRequest::Start(const base::FilePath& path) {
void ImageThumbnailRequest::OnImageDecoded(const SkBitmap& decoded_image) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
base::BindOnce(&ScaleDownBitmap, icon_size_, decoded_image),
base::BindOnce(&ImageThumbnailRequest::FinishRequest,
weak_ptr_factory_.GetWeakPtr()));
ScaleDownBitmap(icon_size_, decoded_image,
base::BindOnce(&ImageThumbnailRequest::FinishRequest,
weak_ptr_factory_.GetWeakPtr()));
}
void ImageThumbnailRequest::OnDecodeImageFailed() {
......@@ -110,9 +89,10 @@ void ImageThumbnailRequest::OnLoadComplete(const std::string& data) {
ImageDecoder::Start(this, data);
}
void ImageThumbnailRequest::FinishRequest(const SkBitmap& thumbnail) {
void ImageThumbnailRequest::FinishRequest(SkBitmap thumbnail) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);
base::PostTaskWithTraits(FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(std::move(callback_), thumbnail));
base::PostTaskWithTraits(
FROM_HERE, {content::BrowserThread::UI},
base::BindOnce(std::move(callback_), std::move(thumbnail)));
delete this;
}
......@@ -33,7 +33,7 @@ class ImageThumbnailRequest : public ImageDecoder::ImageRequest {
void OnLoadComplete(const std::string& data);
void FinishRequest(const SkBitmap& thumbnail);
void FinishRequest(SkBitmap thumbnail);
const int icon_size_;
base::OnceCallback<void(const SkBitmap&)> callback_;
......
// 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.
#include "chrome/browser/download/thumbnail_util.h"
#include "base/logging.h"
#include "base/task/post_task.h"
#include "content/public/browser/browser_thread.h"
#include "skia/ext/image_operations.h"
namespace {
SkBitmap ScaleDownBitmapOnIOThread(int icon_size, SkBitmap bitmap) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
if (bitmap.drawsNothing())
return bitmap;
// Shrink the image down so that its smallest dimension is equal to or
// smaller than the requested size.
int min_dimension = std::min(bitmap.width(), bitmap.height());
if (min_dimension <= icon_size)
return bitmap;
uint64_t width = static_cast<uint64_t>(bitmap.width());
uint64_t height = static_cast<uint64_t>(bitmap.height());
return skia::ImageOperations::Resize(
bitmap, skia::ImageOperations::RESIZE_BEST,
width * icon_size / min_dimension, height * icon_size / min_dimension);
}
} // namespace
void ScaleDownBitmap(int icon_size,
const SkBitmap& bitmap,
base::OnceCallback<void(SkBitmap)> callback) {
DCHECK(callback);
DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
// Scale down bitmap on another thread.
base::PostTaskWithTraitsAndReplyWithResult(
FROM_HERE, {base::MayBlock(), base::TaskPriority::USER_BLOCKING},
base::BindOnce(&ScaleDownBitmapOnIOThread, icon_size, std::move(bitmap)),
std::move(callback));
}
// 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_THUMBNAIL_UTIL_H_
#define CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
#include "base/callback.h"
class SkBitmap;
// Scale down the bitmap. The result is returned in the |callback|. The aspect
// ratio is kept. The maximum size of the width or height will be no greater
// than |icon_size|.
void ScaleDownBitmap(int icon_size,
const SkBitmap& bitmap,
base::OnceCallback<void(SkBitmap)> callback);
#endif // CHROME_BROWSER_DOWNLOAD_THUMBNAIL_UTIL_H_
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment