Commit f7b6773a authored by ianwen's avatar ianwen Committed by Commit bot

Restrict salient image size before storing

It is a waste of storage to save images that are larger than device
display size. On tablet we should be even more aggressive about resizing
those images, because showing them won't take up the entire screen.

BUG=454623

Review URL: https://codereview.chromium.org/916783003

Cr-Commit-Position: refs/heads/master@{#317628}
parent 3ea2d120
...@@ -18,7 +18,10 @@ ...@@ -18,7 +18,10 @@
#include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents.h"
#include "content/public/common/referrer.h" #include "content/public/common/referrer.h"
#include "net/base/load_flags.h" #include "net/base/load_flags.h"
#include "skia/ext/image_operations.h"
#include "ui/base/device_form_factor.h"
#include "ui/base/resource/resource_bundle.h" #include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/android/device_display_info.h"
#include "ui/gfx/image/image_skia.h" #include "ui/gfx/image/image_skia.h"
using content::Referrer; using content::Referrer;
...@@ -33,6 +36,30 @@ BookmarkImageServiceAndroid::BookmarkImageServiceAndroid( ...@@ -33,6 +36,30 @@ BookmarkImageServiceAndroid::BookmarkImageServiceAndroid(
EnhancedBookmarkModelFactory::GetForBrowserContext(browserContext), EnhancedBookmarkModelFactory::GetForBrowserContext(browserContext),
make_scoped_refptr(content::BrowserThread::GetBlockingPool())), make_scoped_refptr(content::BrowserThread::GetBlockingPool())),
browser_context_(browserContext) { browser_context_(browserContext) {
// The images we're saving will be used locally. So it's wasteful to store
// images larger than the device resolution.
gfx::DeviceDisplayInfo display_info;
int max_length = std::min(display_info.GetPhysicalDisplayWidth(),
display_info.GetPhysicalDisplayHeight());
// GetPhysicalDisplay*() returns 0 for pre-JB MR1. If so, fall back to the
// second best option we have.
if (max_length == 0) {
max_length = std::min(display_info.GetDisplayWidth(),
display_info.GetDisplayHeight());
}
if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_TABLET) {
max_length = max_length / 2;
} else if (ui::GetDeviceFormFactor() == ui::DEVICE_FORM_FACTOR_PHONE) {
max_length = max_length * 3 / 4;
}
DCHECK(max_length > 0);
max_size_.set_height(max_length);
max_size_.set_width(max_length);
}
BookmarkImageServiceAndroid::~BookmarkImageServiceAndroid() {
} }
void BookmarkImageServiceAndroid::RetrieveSalientImage( void BookmarkImageServiceAndroid::RetrieveSalientImage(
...@@ -45,7 +72,7 @@ void BookmarkImageServiceAndroid::RetrieveSalientImage( ...@@ -45,7 +72,7 @@ void BookmarkImageServiceAndroid::RetrieveSalientImage(
enhanced_bookmark_model_->bookmark_model() enhanced_bookmark_model_->bookmark_model()
->GetMostRecentlyAddedUserNodeForURL(page_url); ->GetMostRecentlyAddedUserNodeForURL(page_url);
if (!bookmark || !image_url.is_valid()) { if (!bookmark || !image_url.is_valid()) {
ProcessNewImage(page_url, update_bookmark, gfx::Image(), image_url); ProcessNewImage(page_url, update_bookmark, image_url, gfx::Image());
return; return;
} }
...@@ -184,6 +211,28 @@ void BookmarkImageServiceAndroid::RetrieveSalientImageFromContextCallback( ...@@ -184,6 +211,28 @@ void BookmarkImageServiceAndroid::RetrieveSalientImageFromContextCallback(
referrer_policy, update_bookmark); referrer_policy, update_bookmark);
} }
gfx::Image BookmarkImageServiceAndroid::ResizeImage(gfx::Image image) {
DCHECK(!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
gfx::Image resized_image = image;
if (image.Width() > max_size_.width() &&
image.Height() > max_size_.height()) {
float resize_ratio = std::min(((float)max_size_.width()) / image.Width(),
((float)max_size_.height()) / image.Height());
// +0.5f is for correct rounding. Without it, it's possible that dest_width
// is smaller than max_size_.Width() by one.
int dest_width = static_cast<int>(resize_ratio * image.Width() + 0.5f);
int dest_height = static_cast<int>(resize_ratio * image.Height() + 0.5f);
resized_image =
gfx::Image::CreateFrom1xBitmap(skia::ImageOperations::Resize(
image.AsBitmap(), skia::ImageOperations::RESIZE_BEST, dest_width,
dest_height));
resized_image.AsImageSkia().MakeThreadSafe();
}
return resized_image;
}
void BookmarkImageServiceAndroid::BitmapFetcherHandler::Start( void BookmarkImageServiceAndroid::BitmapFetcherHandler::Start(
content::BrowserContext* browser_context, content::BrowserContext* browser_context,
const std::string& referrer, const std::string& referrer,
...@@ -209,7 +258,7 @@ void BookmarkImageServiceAndroid::BitmapFetcherHandler::OnFetchComplete( ...@@ -209,7 +258,7 @@ void BookmarkImageServiceAndroid::BitmapFetcherHandler::OnFetchComplete(
imageSkia.MakeThreadSafe(); imageSkia.MakeThreadSafe();
image = gfx::Image(imageSkia); image = gfx::Image(imageSkia);
} }
service_->ProcessNewImage(page_url_, update_bookmark_, image, url); service_->ProcessNewImage(page_url_, update_bookmark_, url, image);
delete this; delete this;
} }
......
...@@ -24,6 +24,8 @@ class BookmarkImageServiceAndroid : public BookmarkImageService { ...@@ -24,6 +24,8 @@ class BookmarkImageServiceAndroid : public BookmarkImageService {
public: public:
explicit BookmarkImageServiceAndroid(content::BrowserContext* browserContext); explicit BookmarkImageServiceAndroid(content::BrowserContext* browserContext);
~BookmarkImageServiceAndroid() override;
void RetrieveSalientImage(const GURL& page_url, void RetrieveSalientImage(const GURL& page_url,
const GURL& image_url, const GURL& image_url,
const std::string& referrer, const std::string& referrer,
...@@ -48,9 +50,14 @@ class BookmarkImageServiceAndroid : public BookmarkImageService { ...@@ -48,9 +50,14 @@ class BookmarkImageServiceAndroid : public BookmarkImageService {
bool update_bookmark, bool update_bookmark,
const base::Value* result); const base::Value* result);
gfx::Image ResizeImage(gfx::Image image) override;
content::BrowserContext* browser_context_; content::BrowserContext* browser_context_;
// The script injected in a page to extract image urls. // The script injected in a page to extract image urls.
base::string16 script_; base::string16 script_;
// Maximum size for retrieved salient images in pixels. This is used when
// resizing an image.
gfx::Size max_size_;
class BitmapFetcherHandler : private chrome::BitmapFetcherDelegate { class BitmapFetcherHandler : private chrome::BitmapFetcherDelegate {
public: public:
......
...@@ -190,8 +190,8 @@ void BookmarkImageService::SalientImageForUrl(const GURL& page_url, ...@@ -190,8 +190,8 @@ void BookmarkImageService::SalientImageForUrl(const GURL& page_url,
void BookmarkImageService::ProcessNewImage(const GURL& page_url, void BookmarkImageService::ProcessNewImage(const GURL& page_url,
bool update_bookmarks, bool update_bookmarks,
const gfx::Image& image, const GURL& image_url,
const GURL& image_url) { const gfx::Image& image) {
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
PostTaskToStoreImage(image, image_url, page_url); PostTaskToStoreImage(image, image_url, page_url);
if (update_bookmarks && image_url.is_valid()) { if (update_bookmarks && image_url.is_valid()) {
...@@ -212,12 +212,13 @@ bool BookmarkImageService::IsPageUrlInProgress(const GURL& page_url) { ...@@ -212,12 +212,13 @@ bool BookmarkImageService::IsPageUrlInProgress(const GURL& page_url) {
return in_progress_page_urls_.find(page_url) != in_progress_page_urls_.end(); return in_progress_page_urls_.find(page_url) != in_progress_page_urls_.end();
} }
ImageRecord BookmarkImageService::StoreImage(const gfx::Image& image, ImageRecord BookmarkImageService::ResizeAndStoreImage(const gfx::Image& image,
const GURL& image_url, const GURL& image_url,
const GURL& page_url) { const GURL& page_url) {
ImageRecord image_info(image, image_url, SK_ColorBLACK); gfx::Image resized_image = ResizeImage(image);
if (!image.IsEmpty()) { ImageRecord image_info(resized_image, image_url, SK_ColorBLACK);
image_info.dominant_color = DominantColorForImage(image); if (!resized_image.IsEmpty()) {
image_info.dominant_color = DominantColorForImage(resized_image);
// TODO(lpromero): this should be saved all the time, even when there is an // TODO(lpromero): this should be saved all the time, even when there is an
// empty image. http://crbug.com/451450 // empty image. http://crbug.com/451450
pool_->PostNamedSequencedWorkerTask( pool_->PostNamedSequencedWorkerTask(
...@@ -234,8 +235,8 @@ void BookmarkImageService::PostTaskToStoreImage(const gfx::Image& image, ...@@ -234,8 +235,8 @@ void BookmarkImageService::PostTaskToStoreImage(const gfx::Image& image,
DCHECK(CalledOnValidThread()); DCHECK(CalledOnValidThread());
base::Callback<ImageRecord(void)> task = base::Callback<ImageRecord(void)> task =
base::Bind(&BookmarkImageService::StoreImage, base::Unretained(this), base::Bind(&BookmarkImageService::ResizeAndStoreImage,
image, image_url, page_url); base::Unretained(this), image, image_url, page_url);
base::Callback<void(const ImageRecord&)> reply = base::Callback<void(const ImageRecord&)> reply =
base::Bind(&BookmarkImageService::OnStoreImagePosted, base::Bind(&BookmarkImageService::OnStoreImagePosted,
base::Unretained(this), page_url); base::Unretained(this), page_url);
......
...@@ -84,17 +84,20 @@ class BookmarkImageService : public KeyedService, ...@@ -84,17 +84,20 @@ class BookmarkImageService : public KeyedService,
// Returns true if the image for the page_url is currently being fetched. // Returns true if the image for the page_url is currently being fetched.
bool IsPageUrlInProgress(const GURL& page_url); bool IsPageUrlInProgress(const GURL& page_url);
// Stores the image to local storage. If update_bookmarks is true, relates the // Stores the new image to local storage. If update_bookmarks is true, relates
// corresponding bookmark to image_url. // the corresponding bookmark to image_url.
void ProcessNewImage(const GURL& page_url, void ProcessNewImage(const GURL& page_url,
bool update_bookmarks, bool update_bookmarks,
const gfx::Image& image, const GURL& image_url,
const GURL& image_url); const gfx::Image& image);
// Resizes large images to proper size that fits device display. This method
// should _not_ run on the UI thread.
virtual gfx::Image ResizeImage(gfx::Image image) = 0;
// Sets a new image for a bookmark. If the given page_url is bookmarked and // Sets a new image for a bookmark. If the given page_url is bookmarked and
// the image is retrieved from the image_url, then the image is locally // the image is retrieved from the image_url, then the image is locally
// stored. If update_bookmark is true the URL is also added to the bookmark. // stored. If update_bookmark is true the URL is also added to the bookmark.
// This is the only method subclass needs to implement.
virtual void RetrieveSalientImage( virtual void RetrieveSalientImage(
const GURL& page_url, const GURL& page_url,
const GURL& image_url, const GURL& image_url,
...@@ -122,12 +125,13 @@ class BookmarkImageService : public KeyedService, ...@@ -122,12 +125,13 @@ class BookmarkImageService : public KeyedService,
// Processes the requests that have been waiting on an image. // Processes the requests that have been waiting on an image.
void ProcessRequests(const GURL& page_url, const ImageRecord& image); void ProcessRequests(const GURL& page_url, const ImageRecord& image);
// Once an image is retrieved this method updates the store with it. Returns // Once an image is retrieved this method calls ResizeImage() and updates the
// the newly formed ImageRecord. This is typically called on |pool_|, the // store with the smaller image, then returns the newly formed ImageRecord.
// background sequenced worker pool for this object. // This is typically called on |pool_|, the background sequenced worker pool
ImageRecord StoreImage(const gfx::Image& image, // for this object.
const GURL& image_url, ImageRecord ResizeAndStoreImage(const gfx::Image& image,
const GURL& page_url); const GURL& image_url,
const GURL& page_url);
// Calls |StoreImage| in the background. This should only be called from the // Calls |StoreImage| in the background. This should only be called from the
// main thread. // main thread.
......
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