Commit 0574dc18 authored by mazda@chromium.org's avatar mazda@chromium.org

Make ThumbnailGenerator support high DPI.

- Store 2x thumbnail when the primary monitor has ui::SCALE_FACTOR_200P.
- Copy the constant size of pixels from RWHV regardless of the view's device scale factor.

BUG=125043


Review URL: https://chromiumcodereview.appspot.com/10831207

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@152450 0039d316-1c4b-4281-b951-d872f2087c98
parent fb513d1e
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "ui/base/layout.h" #include "ui/base/layout.h"
#include "ui/gfx/color_utils.h" #include "ui/gfx/color_utils.h"
#include "ui/gfx/rect.h" #include "ui/gfx/rect.h"
#include "ui/gfx/screen.h"
#include "ui/gfx/scrollbar_size.h" #include "ui/gfx/scrollbar_size.h"
#include "ui/gfx/skbitmap_operations.h" #include "ui/gfx/skbitmap_operations.h"
...@@ -65,32 +66,70 @@ using content::WebContents; ...@@ -65,32 +66,70 @@ using content::WebContents;
namespace { namespace {
// The thumbnail size in DIP.
static const int kThumbnailWidth = 212; static const int kThumbnailWidth = 212;
static const int kThumbnailHeight = 132; static const int kThumbnailHeight = 132;
// This factor determines the number of pixels to be copied by
// RenderWidgetHost::CopyFromBackingStore for generating thumbnail.
// Smaller scale is good for performance, but too small scale causes aliasing
// because the resampling method is not good enough to retain the image quality.
// TODO(mazda): the Improve resampling method and use a smaller scale
// (http://crbug.com/118571).
static const double kThumbnailCopyScale = 2.0;
static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS"; static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS";
// Calculates the size used by RenderWidgetHost::CopyFromBackingStore. // Returns the size used by RenderWidgetHost::CopyFromBackingStore.
// The result is computed as the minimum size that satisfies the following //
// conditions. // The size is calculated in such a way that the copied size in pixel becomes
// result.width : result.height == view_size.width : view_size.height // equal to (f * kThumbnailWidth, f * kThumbnailHeight), where f is the scale
// result.width >= kThumbnailCopyScale * desired_size.width // of ui::SCALE_FACTOR_200P. Since RenderWidgetHost::CopyFromBackingStore takes
// result.height >= kThumbnailCopyScale * desired_size.height // the size in DIP, we need to adjust the size based on |view|'s device scale
gfx::Size GetCopySizeForThumbnail(const gfx::Size& view_size, // factor in order to copy the pixels with the size above.
const gfx::Size& desired_size) { //
const double scale = kThumbnailCopyScale * // The copied size was chosen for the following reasons.
std::max(static_cast<double>(desired_size.width()) / view_size.width(), //
static_cast<double>(desired_size.height()) / view_size.height()); // 1. When the scale factor of the primary monitor is ui::SCALE_FACTOR_200P, the
return gfx::Size(static_cast<int>(scale * view_size.width()), // generated thumbnail size is (f * kThumbnailWidth, f * kThumbnailHeight).
static_cast<int>(scale * view_size.height())); // In order to avoid degrading the image quality by magnification, the size
// of the copied pixels should be equal to or larger than this thumbnail size.
//
// 2. RenderWidgetHost::CopyFromBackingStore can be costly especially when
// it is necessary to read back the web contents image data from GPU. As the
// cost is roughly propotional to the number of the copied pixels, the size of
// the copied pixels should be as small as possible.
//
// When the scale factor of the primary monitor is ui::SCALE_FACTOR_100P,
// we still copy the pixels with the same size as ui::SCALE_FACTOR_200P because
// the resampling method used in RenderWidgetHost::CopyFromBackingStore is not
// good enough for the resampled image to be used directly for the thumbnail
// (http://crbug.com/141235). We assume this is not an issue in case of
// ui::SCALE_FACTOR_200P because the high resolution thumbnail on high density
// display alleviates the aliasing.
// TODO(mazda): Copy the pixels with the smaller size in the case of
// ui::SCALE_FACTOR_100P once the resampling method has been improved.
gfx::Size GetCopySizeForThumbnail(content::RenderWidgetHostView* view) {
gfx::Size copy_size(kThumbnailWidth, kThumbnailHeight);
ui::ScaleFactor scale_factor =
ui::GetScaleFactorForNativeView(view->GetNativeView());
switch (scale_factor) {
case ui::SCALE_FACTOR_100P:
copy_size =
copy_size.Scale(ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P));
break;
case ui::SCALE_FACTOR_200P:
// Use the size as-is.
break;
default:
DLOG(WARNING) << "Unsupported scale factor. Use the same copy size as "
<< "ui::SCALE_FACTOR_100P";
copy_size =
copy_size.Scale(ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P));
break;
}
return copy_size;
}
// Returns the size of the thumbnail stored in the database in pixel.
gfx::Size GetThumbnailSizeInPixel() {
gfx::Size thumbnail_size(kThumbnailWidth, kThumbnailHeight);
// Determine the resolution of the thumbnail based on the primary monitor.
// TODO(oshima): Use device's default scale factor.
gfx::Display primary_display = gfx::Screen::GetPrimaryDisplay();
return thumbnail_size.Scale(primary_display.device_scale_factor());
} }
// Returns the clipping rectangle that is used for creating a thumbnail with // Returns the clipping rectangle that is used for creating a thumbnail with
...@@ -142,8 +181,7 @@ gfx::Rect GetClippingRect(const gfx::Size& source_size, ...@@ -142,8 +181,7 @@ gfx::Rect GetClippingRect(const gfx::Size& source_size,
// store. The returned bitmap will be isNull if there was an error creating it. // store. The returned bitmap will be isNull if there was an error creating it.
SkBitmap CreateThumbnail( SkBitmap CreateThumbnail(
const SkBitmap& bitmap, const SkBitmap& bitmap,
int desired_width, const gfx::Size& desired_size,
int desired_height,
ThumbnailGenerator::ClipResult* clip_result) { ThumbnailGenerator::ClipResult* clip_result) {
base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
...@@ -160,7 +198,7 @@ SkBitmap CreateThumbnail( ...@@ -160,7 +198,7 @@ SkBitmap CreateThumbnail(
bitmap.extractSubset(&bmp, scrollbarless_rect); bitmap.extractSubset(&bmp, scrollbarless_rect);
clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( clipped_bitmap = ThumbnailGenerator::GetClippedBitmap(
bmp, desired_width, desired_height, clip_result); bmp, desired_size.width(), desired_size.height(), clip_result);
} else { } else {
clipped_bitmap = bitmap; clipped_bitmap = bitmap;
} }
...@@ -168,7 +206,7 @@ SkBitmap CreateThumbnail( ...@@ -168,7 +206,7 @@ SkBitmap CreateThumbnail(
// Need to resize it to the size we want, so downsample until it's // Need to resize it to the size we want, so downsample until it's
// close, and let the caller make it the exact size if desired. // close, and let the caller make it the exact size if desired.
SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize( SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize(
clipped_bitmap, desired_width, desired_height); clipped_bitmap, desired_size.width(), desired_size.height());
#if !defined(USE_AURA) #if !defined(USE_AURA)
// This is a bit subtle. SkBitmaps are refcounted, but the magic // This is a bit subtle. SkBitmaps are refcounted, but the magic
// ones in PlatformCanvas can't be assigned to SkBitmap with proper // ones in PlatformCanvas can't be assigned to SkBitmap with proper
...@@ -523,8 +561,7 @@ void ThumbnailGenerator::AsyncUpdateThumbnail( ...@@ -523,8 +561,7 @@ void ThumbnailGenerator::AsyncUpdateThumbnail(
copy_rect = GetClippingRect(copy_rect.size(), copy_rect = GetClippingRect(copy_rect.size(),
gfx::Size(kThumbnailWidth, kThumbnailHeight), gfx::Size(kThumbnailWidth, kThumbnailHeight),
&clip_result); &clip_result);
gfx::Size copy_size = gfx::Size copy_size = GetCopySizeForThumbnail(view);
gfx::Size(kThumbnailWidth, kThumbnailHeight).Scale(kThumbnailCopyScale);
skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas; skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas;
render_widget_host->CopyFromBackingStore( render_widget_host->CopyFromBackingStore(
copy_rect, copy_rect,
...@@ -546,8 +583,7 @@ void ThumbnailGenerator::UpdateThumbnailWithBitmap( ...@@ -546,8 +583,7 @@ void ThumbnailGenerator::UpdateThumbnailWithBitmap(
return; return;
SkBitmap thumbnail = CreateThumbnail(bitmap, SkBitmap thumbnail = CreateThumbnail(bitmap,
kThumbnailWidth, GetThumbnailSizeInPixel(),
kThumbnailHeight,
&clip_result); &clip_result);
UpdateThumbnail(web_contents, thumbnail, clip_result); UpdateThumbnail(web_contents, thumbnail, clip_result);
} }
......
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