Commit 1db8d661 authored by Brandon Wylie's avatar Brandon Wylie Committed by Commit Bot

[IC] Transcode images once they've been downloaded

Bug: 872342
Change-Id: Iaa017e045effcac0f593f79b304f1413350c494c
Reviewed-on: https://chromium-review.googlesource.com/1243829Reviewed-by: default avatarScott Violet <sky@chromium.org>
Reviewed-by: default avatarFilip Gorski <fgorski@chromium.org>
Reviewed-by: default avatarSky Malice <skym@chromium.org>
Commit-Queue: Brandon Wylie <wylieb@chromium.org>
Cr-Commit-Position: refs/heads/master@{#595232}
parent 20ce2984
include_rules = [ include_rules = [
"+components/leveldb_proto", "+components/leveldb_proto",
"+components/prefs", "+components/prefs",
"+ui/gfx/codec",
"+ui/gfx/geomtery",
"+ui/gfx/image",
] ]
...@@ -10,24 +10,45 @@ ...@@ -10,24 +10,45 @@
#include "components/image_fetcher/core/image_decoder.h" #include "components/image_fetcher/core/image_decoder.h"
#include "components/image_fetcher/core/request_metadata.h" #include "components/image_fetcher/core/request_metadata.h"
#include "components/image_fetcher/core/storage/image_cache.h" #include "components/image_fetcher/core/storage/image_cache.h"
#include "ui/gfx/codec/png_codec.h"
#include "ui/gfx/geometry/size.h" #include "ui/gfx/geometry/size.h"
#include "ui/gfx/image/image.h" #include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia.h"
namespace image_fetcher { namespace image_fetcher {
namespace { namespace {
// Wrapper to check if callbacks can be called. void DataCallbackIfPresent(ImageDataFetcherCallback data_callback,
void CallbackIfPresent(ImageDataFetcherCallback data_callback, const std::string& image_data,
ImageFetcherCallback image_callback, const image_fetcher::RequestMetadata& metadata) {
const std::string& id, if (data_callback.is_null()) {
const std::string& image_data, return;
const gfx::Image& image, }
const image_fetcher::RequestMetadata& metadata) { std::move(data_callback).Run(image_data, metadata);
if (!data_callback.is_null()) }
std::move(data_callback).Run(image_data, metadata);
if (!image_callback.is_null()) void ImageCallbackIfPresent(ImageFetcherCallback image_callback,
std::move(image_callback).Run(id, image, metadata); const std::string& id,
const gfx::Image& image,
const image_fetcher::RequestMetadata& metadata) {
if (image_callback.is_null()) {
return;
}
std::move(image_callback).Run(id, image, metadata);
}
bool EncodeSkBitmapToPNG(const SkBitmap& bitmap,
std::vector<unsigned char>* dest) {
if (!bitmap.readyToDraw() || bitmap.isNull()) {
return false;
}
return gfx::PNGCodec::Encode(
static_cast<const unsigned char*>(bitmap.getPixels()),
gfx::PNGCodec::FORMAT_RGBA, gfx::Size(bitmap.width(), bitmap.height()),
static_cast<int>(bitmap.rowBytes()), /* discard_transparency */ false,
std::vector<gfx::PNGCodec::Comment>(), dest);
} }
} // namespace } // namespace
...@@ -51,6 +72,7 @@ void CachedImageFetcher::SetDataUseServiceName( ...@@ -51,6 +72,7 @@ void CachedImageFetcher::SetDataUseServiceName(
void CachedImageFetcher::SetDesiredImageFrameSize(const gfx::Size& size) { void CachedImageFetcher::SetDesiredImageFrameSize(const gfx::Size& size) {
image_fetcher_->SetDesiredImageFrameSize(size); image_fetcher_->SetDesiredImageFrameSize(size);
desired_image_frame_size_ = size;
} }
void CachedImageFetcher::SetImageDownloadLimit( void CachedImageFetcher::SetImageDownloadLimit(
...@@ -89,8 +111,9 @@ void CachedImageFetcher::OnImageFetchedFromCache( ...@@ -89,8 +111,9 @@ void CachedImageFetcher::OnImageFetchedFromCache(
FetchImageFromNetwork(id, image_url, std::move(data_callback), FetchImageFromNetwork(id, image_url, std::move(data_callback),
std::move(image_callback), traffic_annotation); std::move(image_callback), traffic_annotation);
} else { } else {
// TODO(wylieb): On Android, do this in-process.
GetImageDecoder()->DecodeImage( GetImageDecoder()->DecodeImage(
image_data, gfx::Size(), image_data, desired_image_frame_size_,
base::BindRepeating(&CachedImageFetcher::OnImageDecodedFromCache, base::BindRepeating(&CachedImageFetcher::OnImageDecodedFromCache,
weak_ptr_factory_.GetWeakPtr(), id, image_url, weak_ptr_factory_.GetWeakPtr(), id, image_url,
base::Passed(std::move(data_callback)), base::Passed(std::move(data_callback)),
...@@ -110,10 +133,13 @@ void CachedImageFetcher::OnImageDecodedFromCache( ...@@ -110,10 +133,13 @@ void CachedImageFetcher::OnImageDecodedFromCache(
if (image.IsEmpty()) { if (image.IsEmpty()) {
FetchImageFromNetwork(id, image_url, std::move(data_callback), FetchImageFromNetwork(id, image_url, std::move(data_callback),
std::move(image_callback), traffic_annotation); std::move(image_callback), traffic_annotation);
// Decoding error, delete image from cache.
image_cache_->DeleteImage(image_url.spec()); image_cache_->DeleteImage(image_url.spec());
} else { } else {
CallbackIfPresent(std::move(data_callback), std::move(image_callback), id, DataCallbackIfPresent(std::move(data_callback), image_data,
image_data, image, RequestMetadata()); RequestMetadata());
ImageCallbackIfPresent(std::move(image_callback), id, image,
RequestMetadata());
} }
} }
...@@ -123,58 +149,50 @@ void CachedImageFetcher::FetchImageFromNetwork( ...@@ -123,58 +149,50 @@ void CachedImageFetcher::FetchImageFromNetwork(
ImageDataFetcherCallback data_callback, ImageDataFetcherCallback data_callback,
ImageFetcherCallback image_callback, ImageFetcherCallback image_callback,
const net::NetworkTrafficAnnotationTag& traffic_annotation) { const net::NetworkTrafficAnnotationTag& traffic_annotation) {
if (!image_url.is_valid()) { // Fetch image data and the image itself. The image data will be stored in
// URL is invalid, return empty image/data. // the image cache, and the image will be returned to the caller.
CallbackIfPresent(std::move(data_callback), std::move(image_callback), id, image_fetcher_->FetchImageAndData(
std::string(), gfx::Image(), RequestMetadata());
return;
}
image_fetcher_->FetchImageData(
id, image_url, id, image_url,
base::BindOnce(&CachedImageFetcher::OnImageDataFetchedFromNetwork,
weak_ptr_factory_.GetWeakPtr(), std::move(data_callback),
image_url),
base::BindOnce(&CachedImageFetcher::OnImageFetchedFromNetwork, base::BindOnce(&CachedImageFetcher::OnImageFetchedFromNetwork,
weak_ptr_factory_.GetWeakPtr(), id, image_url, weak_ptr_factory_.GetWeakPtr(), std::move(image_callback)),
std::move(data_callback), std::move(image_callback)),
traffic_annotation); traffic_annotation);
} }
void CachedImageFetcher::OnImageFetchedFromNetwork( void CachedImageFetcher::OnImageFetchedFromNetwork(
const std::string& id,
const GURL& image_url,
ImageDataFetcherCallback data_callback,
ImageFetcherCallback image_callback, ImageFetcherCallback image_callback,
const std::string& image_data, const std::string& id,
const gfx::Image& image,
const RequestMetadata& request_metadata) { const RequestMetadata& request_metadata) {
if (image_data.empty()) { // The image has been deocded by the fetcher already, return straight to the
// Fetching image failed, return empty image/data. // caller.
CallbackIfPresent(std::move(data_callback), std::move(image_callback), id, ImageCallbackIfPresent(std::move(image_callback), id, image,
image_data, gfx::Image(), request_metadata); request_metadata);
return;
}
image_fetcher_->GetImageDecoder()->DecodeImage(
image_data, gfx::Size(),
base::BindRepeating(&CachedImageFetcher::OnImageDecodedFromNetwork,
weak_ptr_factory_.GetWeakPtr(), id, image_url,
base::Passed(std::move(data_callback)),
base::Passed(std::move(image_callback)), image_data,
request_metadata));
} }
void CachedImageFetcher::OnImageDecodedFromNetwork( void CachedImageFetcher::OnImageDataFetchedFromNetwork(
const std::string& id,
const GURL& image_url,
ImageDataFetcherCallback data_callback, ImageDataFetcherCallback data_callback,
ImageFetcherCallback image_callback, const GURL& image_url,
const std::string& image_data, const std::string& image_data,
const RequestMetadata& request_metadata, const RequestMetadata& request_metadata) {
const gfx::Image& image) { DataCallbackIfPresent(std::move(data_callback), image_data, request_metadata);
CallbackIfPresent(std::move(data_callback), std::move(image_callback), id, GetImageDecoder()->DecodeImage(
image_data, image, request_metadata); image_data, /* Decoding for cache shouldn't specify size */ gfx::Size(),
base::BindRepeating(&CachedImageFetcher::OnImageDecodedFromNetwork,
weak_ptr_factory_.GetWeakPtr(), image_url));
}
if (!image.IsEmpty()) { void CachedImageFetcher::OnImageDecodedFromNetwork(const GURL& image_url,
image_cache_->SaveImage(image_url.spec(), image_data); const gfx::Image& image) {
std::vector<unsigned char> encoded_data;
if (!EncodeSkBitmapToPNG(*image.ToSkBitmap(), &encoded_data)) {
return;
} }
image_cache_->SaveImage(
image_url.spec(), std::string(encoded_data.begin(), encoded_data.end()));
} }
} // namespace image_fetcher } // namespace image_fetcher
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
namespace gfx { namespace gfx {
class Image; class Image;
class Size;
} // namespace gfx } // namespace gfx
namespace image_fetcher { namespace image_fetcher {
...@@ -76,23 +77,23 @@ class CachedImageFetcher : public ImageFetcher { ...@@ -76,23 +77,23 @@ class CachedImageFetcher : public ImageFetcher {
ImageDataFetcherCallback image_data_callback, ImageDataFetcherCallback image_data_callback,
ImageFetcherCallback image_callback, ImageFetcherCallback image_callback,
const net::NetworkTrafficAnnotationTag& traffic_annotation); const net::NetworkTrafficAnnotationTag& traffic_annotation);
void OnImageFetchedFromNetwork(const std::string& id, void OnImageFetchedFromNetwork(ImageFetcherCallback image_callback,
const GURL& image_url, const std::string& id,
ImageDataFetcherCallback image_data_callback, const gfx::Image& image,
ImageFetcherCallback image_callback,
const std::string& image_data,
const RequestMetadata& request_metadata); const RequestMetadata& request_metadata);
void OnImageDecodedFromNetwork(const std::string& id, void OnImageDataFetchedFromNetwork(
const GURL& image_url, ImageDataFetcherCallback image_data_callback,
ImageDataFetcherCallback image_data_callback, const GURL& image_url,
ImageFetcherCallback image_callback, const std::string& image_data,
const std::string& image_data, const RequestMetadata& request_metadata);
const RequestMetadata& request_metadata, void OnImageDecodedFromNetwork(const GURL& image_url,
const gfx::Image& image); const gfx::Image& image);
std::unique_ptr<ImageFetcher> image_fetcher_; std::unique_ptr<ImageFetcher> image_fetcher_;
std::unique_ptr<ImageCache> image_cache_; std::unique_ptr<ImageCache> image_cache_;
gfx::Size desired_image_frame_size_;
base::WeakPtrFactory<CachedImageFetcher> weak_ptr_factory_; base::WeakPtrFactory<CachedImageFetcher> weak_ptr_factory_;
DISALLOW_COPY_AND_ASSIGN(CachedImageFetcher); DISALLOW_COPY_AND_ASSIGN(CachedImageFetcher);
......
...@@ -137,23 +137,12 @@ MATCHER(NonEmptyImage, "") { ...@@ -137,23 +137,12 @@ MATCHER(NonEmptyImage, "") {
return !arg.IsEmpty(); return !arg.IsEmpty();
} }
// TODO(wylieb): Rename these tests CachedImageFetcherTest* when ntp_snippets/- MATCHER(NonEmptyString, "") {
// remote/cached_image_fetcher has been migrated. return !arg.empty();
TEST_F(ComponentizedCachedImageFetcherTest, FetchEmptyUrl) {
base::MockCallback<ImageDataFetcherCallback> data_callback;
base::MockCallback<ImageFetcherCallback> image_callback;
GURL empty_url = GURL(std::string());
// Make sure an empty image passed to callback.
EXPECT_CALL(data_callback, Run(std::string(), _));
EXPECT_CALL(image_callback, Run(std::string(), EmptyImage(), _));
cached_image_fetcher()->FetchImageAndData(
empty_url.spec(), empty_url, data_callback.Get(), image_callback.Get(),
TRAFFIC_ANNOTATION_FOR_TESTS);
RunUntilIdle();
} }
// TODO(wylieb): Rename these tests CachedImageFetcherTest* when ntp_snippets/-
// remote/cached_image_fetcher has been migrated.
TEST_F(ComponentizedCachedImageFetcherTest, FetchImageFromCache) { TEST_F(ComponentizedCachedImageFetcherTest, FetchImageFromCache) {
// Save the image in the database. // Save the image in the database.
image_cache()->SaveImage(kImageUrl.spec(), kImageData); image_cache()->SaveImage(kImageUrl.spec(), kImageData);
...@@ -179,7 +168,7 @@ TEST_F(ComponentizedCachedImageFetcherTest, FetchImagePopulatesCache) { ...@@ -179,7 +168,7 @@ TEST_F(ComponentizedCachedImageFetcherTest, FetchImagePopulatesCache) {
base::MockCallback<ImageDataFetcherCallback> data_callback; base::MockCallback<ImageDataFetcherCallback> data_callback;
base::MockCallback<ImageFetcherCallback> image_callback; base::MockCallback<ImageFetcherCallback> image_callback;
EXPECT_CALL(data_callback, Run(kImageData, _)); EXPECT_CALL(data_callback, Run(NonEmptyString(), _));
EXPECT_CALL(image_callback, Run(kImageUrl.spec(), NonEmptyImage(), _)); EXPECT_CALL(image_callback, Run(kImageUrl.spec(), NonEmptyImage(), _));
cached_image_fetcher()->FetchImageAndData( cached_image_fetcher()->FetchImageAndData(
kImageUrl.spec(), kImageUrl, data_callback.Get(), image_callback.Get(), kImageUrl.spec(), kImageUrl, data_callback.Get(), image_callback.Get(),
...@@ -189,7 +178,7 @@ TEST_F(ComponentizedCachedImageFetcherTest, FetchImagePopulatesCache) { ...@@ -189,7 +178,7 @@ TEST_F(ComponentizedCachedImageFetcherTest, FetchImagePopulatesCache) {
} }
// Make sure the image data is in the database. // Make sure the image data is in the database.
{ {
EXPECT_CALL(*this, OnImageLoaded(kImageData)); EXPECT_CALL(*this, OnImageLoaded(NonEmptyString()));
image_cache()->LoadImage( image_cache()->LoadImage(
kImageUrl.spec(), kImageUrl.spec(),
base::BindOnce(&ComponentizedCachedImageFetcherTest::OnImageLoaded, base::BindOnce(&ComponentizedCachedImageFetcherTest::OnImageLoaded,
...@@ -203,7 +192,7 @@ TEST_F(ComponentizedCachedImageFetcherTest, FetchImagePopulatesCache) { ...@@ -203,7 +192,7 @@ TEST_F(ComponentizedCachedImageFetcherTest, FetchImagePopulatesCache) {
base::MockCallback<ImageDataFetcherCallback> data_callback; base::MockCallback<ImageDataFetcherCallback> data_callback;
base::MockCallback<ImageFetcherCallback> image_callback; base::MockCallback<ImageFetcherCallback> image_callback;
EXPECT_CALL(data_callback, Run(kImageData, _)); EXPECT_CALL(data_callback, Run(NonEmptyString(), _));
EXPECT_CALL(image_callback, Run(kImageUrl.spec(), NonEmptyImage(), _)); EXPECT_CALL(image_callback, Run(kImageUrl.spec(), NonEmptyImage(), _));
cached_image_fetcher()->FetchImageAndData( cached_image_fetcher()->FetchImageAndData(
kImageUrl.spec(), kImageUrl, data_callback.Get(), image_callback.Get(), kImageUrl.spec(), kImageUrl, data_callback.Get(), image_callback.Get(),
......
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