| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/thumbnails/simple_thumbnail_crop.h" | 5 #include "chrome/browser/thumbnails/simple_thumbnail_crop.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "content/public/browser/browser_thread.h" | 8 #include "content/public/browser/browser_thread.h" |
| 9 #include "skia/ext/platform_canvas.h" | 9 #include "skia/ext/platform_canvas.h" |
| 10 #include "ui/base/layout.h" |
| 10 #include "ui/gfx/color_utils.h" | 11 #include "ui/gfx/color_utils.h" |
| 11 #include "ui/gfx/geometry/size_conversions.h" | 12 #include "ui/gfx/geometry/size_conversions.h" |
| 12 #include "ui/gfx/image/image_skia.h" | 13 #include "ui/gfx/image/image_skia.h" |
| 13 #include "ui/gfx/screen.h" | 14 #include "ui/gfx/screen.h" |
| 14 #include "ui/gfx/scrollbar_size.h" | 15 #include "ui/gfx/scrollbar_size.h" |
| 15 #include "ui/gfx/skbitmap_operations.h" | 16 #include "ui/gfx/skbitmap_operations.h" |
| 16 | 17 |
| 17 namespace { | 18 namespace { |
| 18 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS"; | 19 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS"; |
| 19 } | 20 } |
| 20 | 21 |
| 21 namespace thumbnails { | 22 namespace thumbnails { |
| 22 | 23 |
| 23 SimpleThumbnailCrop::SimpleThumbnailCrop(const gfx::Size& target_size) | 24 SimpleThumbnailCrop::SimpleThumbnailCrop(const gfx::Size& target_size) |
| 24 : target_size_(target_size) { | 25 : target_size_(target_size) { |
| 25 DCHECK(!target_size.IsEmpty()); | 26 DCHECK(!target_size.IsEmpty()); |
| 26 } | 27 } |
| 27 | 28 |
| 28 ClipResult SimpleThumbnailCrop::GetCanvasCopyInfo( | 29 ClipResult SimpleThumbnailCrop::GetCanvasCopyInfo(const gfx::Size& source_size, |
| 29 const gfx::Size& source_size, | 30 ui::ScaleFactor scale_factor, |
| 30 ui::ScaleFactor scale_factor, | 31 gfx::Rect* clipping_rect, |
| 31 gfx::Rect* clipping_rect, | 32 gfx::Size* copy_size) const { |
| 32 gfx::Size* target_size) const { | |
| 33 DCHECK(!source_size.IsEmpty()); | 33 DCHECK(!source_size.IsEmpty()); |
| 34 ClipResult clip_result = thumbnails::CLIP_RESULT_NOT_CLIPPED; | 34 ClipResult clip_result = thumbnails::CLIP_RESULT_NOT_CLIPPED; |
| 35 *clipping_rect = GetClippingRect(source_size, target_size_, &clip_result); | 35 *clipping_rect = GetClippingRect(source_size, target_size_, &clip_result); |
| 36 *target_size = GetCopySizeForThumbnail(scale_factor, target_size_); | 36 *copy_size = GetCopySizeForThumbnail(scale_factor, target_size_); |
| 37 return clip_result; | 37 return clip_result; |
| 38 } | 38 } |
| 39 | 39 |
| 40 void SimpleThumbnailCrop::ProcessBitmap( | 40 void SimpleThumbnailCrop::ProcessBitmap( |
| 41 scoped_refptr<ThumbnailingContext> context, | 41 scoped_refptr<ThumbnailingContext> context, |
| 42 const ConsumerCallback& callback, | 42 const ConsumerCallback& callback, |
| 43 const SkBitmap& bitmap) { | 43 const SkBitmap& bitmap) { |
| 44 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); | 44 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); |
| 45 if (bitmap.isNull() || bitmap.empty()) | 45 if (bitmap.isNull() || bitmap.empty()) |
| 46 return; | 46 return; |
| (...skipping 20 matching lines...) Expand all Loading... |
| 67 GetClippingRect(gfx::Size(bitmap.width(), bitmap.height()), | 67 GetClippingRect(gfx::Size(bitmap.width(), bitmap.height()), |
| 68 gfx::Size(desired_width, desired_height), | 68 gfx::Size(desired_width, desired_height), |
| 69 clip_result); | 69 clip_result); |
| 70 SkIRect src_rect = { clipping_rect.x(), clipping_rect.y(), | 70 SkIRect src_rect = { clipping_rect.x(), clipping_rect.y(), |
| 71 clipping_rect.right(), clipping_rect.bottom() }; | 71 clipping_rect.right(), clipping_rect.bottom() }; |
| 72 SkBitmap clipped_bitmap; | 72 SkBitmap clipped_bitmap; |
| 73 bitmap.extractSubset(&clipped_bitmap, src_rect); | 73 bitmap.extractSubset(&clipped_bitmap, src_rect); |
| 74 return clipped_bitmap; | 74 return clipped_bitmap; |
| 75 } | 75 } |
| 76 | 76 |
| 77 // Returns the size used by RenderWidgetHost::CopyFromBackingStore. | 77 // RenderWidgetHost::CopyFromBackingStore can be costly especially when it is |
| 78 // | 78 // necessary to read back the web contents image data from GPU. As the cost is |
| 79 // The size is calculated in such a way that the copied size in pixel becomes | 79 // roughly proportional to the number of the copied pixels, the size of the |
| 80 // equal to (f * kThumbnailWidth, f * kThumbnailHeight), where f is the scale | 80 // copied pixels should be as small as possible. |
| 81 // of ui::SCALE_FACTOR_200P. Since RenderWidgetHost::CopyFromBackingStore takes | |
| 82 // the size in DIP, we need to adjust the size based on |view|'s device scale | |
| 83 // factor in order to copy the pixels with the size above. | |
| 84 // | |
| 85 // The copied size was chosen for the following reasons. | |
| 86 // | |
| 87 // 1. When the scale factor of the primary monitor is ui::SCALE_FACTOR_200P, the | |
| 88 // generated thumbnail size is (f * kThumbnailWidth, f * kThumbnailHeight). | |
| 89 // In order to avoid degrading the image quality by magnification, the size | |
| 90 // of the copied pixels should be equal to or larger than this thumbnail size. | |
| 91 // | |
| 92 // 2. RenderWidgetHost::CopyFromBackingStore can be costly especially when | |
| 93 // it is necessary to read back the web contents image data from GPU. As the | |
| 94 // cost is roughly propotional to the number of the copied pixels, the size of | |
| 95 // the copied pixels should be as small as possible. | |
| 96 // | |
| 97 // When the scale factor of the primary monitor is ui::SCALE_FACTOR_100P, | |
| 98 // we still copy the pixels with the same size as ui::SCALE_FACTOR_200P (2.0f) | |
| 99 // because the resampling method used in RenderWidgetHost::CopyFromBackingStore | |
| 100 // is not good enough for the resampled image to be used directly for the | |
| 101 // thumbnail (http://crbug.com/141235). We assume this is not an issue in case o
f | |
| 102 // ui::SCALE_FACTOR_200P because the high resolution thumbnail on high density | |
| 103 // display alleviates the aliasing. | |
| 104 // TODO(mazda): Copy the pixels with the smaller size in the case of | |
| 105 // ui::SCALE_FACTOR_100P once the resampling method has been improved. | |
| 106 // static | 81 // static |
| 107 gfx::Size SimpleThumbnailCrop::GetCopySizeForThumbnail( | 82 gfx::Size SimpleThumbnailCrop::GetCopySizeForThumbnail( |
| 108 ui::ScaleFactor scale_factor, | 83 ui::ScaleFactor scale_factor, |
| 109 const gfx::Size& thumbnail_size) { | 84 const gfx::Size& thumbnail_size) { |
| 110 gfx::Size copy_size(thumbnail_size); | 85 // The copy size returned is the pixel equivalent of |thumbnail_size|, which |
| 111 switch (scale_factor) { | 86 // is in DIPs. |
| 112 case ui::SCALE_FACTOR_100P: | 87 if (scale_factor == ui::SCALE_FACTOR_100P) { |
| 113 copy_size = gfx::ToFlooredSize(gfx::ScaleSize(copy_size, 2.0f)); | 88 // In the case of 1x devices, we get a thumbnail twice as big and reduce |
| 114 break; | 89 // it at serve time to improve quality. |
| 115 case ui::SCALE_FACTOR_200P: | 90 scale_factor = ui::SCALE_FACTOR_200P; |
| 116 // Use the size as-is. | |
| 117 break; | |
| 118 default: | |
| 119 DLOG(WARNING) << "Unsupported scale factor. Use the same copy size as " | |
| 120 << "ui::SCALE_FACTOR_100P"; | |
| 121 copy_size = gfx::ToFlooredSize(gfx::ScaleSize( | |
| 122 copy_size, gfx::ImageSkia::GetMaxSupportedScale())); | |
| 123 break; | |
| 124 } | 91 } |
| 125 return copy_size; | 92 float scale = GetScaleForScaleFactor(scale_factor); |
| 93 return gfx::ToFlooredSize(gfx::ScaleSize(thumbnail_size, scale)); |
| 126 } | 94 } |
| 127 | 95 |
| 128 gfx::Rect SimpleThumbnailCrop::GetClippingRect(const gfx::Size& source_size, | 96 gfx::Rect SimpleThumbnailCrop::GetClippingRect(const gfx::Size& source_size, |
| 129 const gfx::Size& desired_size, | 97 const gfx::Size& desired_size, |
| 130 ClipResult* clip_result) { | 98 ClipResult* clip_result) { |
| 131 DCHECK(clip_result); | 99 DCHECK(clip_result); |
| 132 | 100 |
| 133 float desired_aspect = | 101 float desired_aspect = |
| 134 static_cast<float>(desired_size.width()) / desired_size.height(); | 102 static_cast<float>(desired_size.width()) / desired_size.height(); |
| 135 | 103 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 226 clipped_bitmap.height() == result.height()) | 194 clipped_bitmap.height() == result.height()) |
| 227 clipped_bitmap.copyTo(&result, kN32_SkColorType); | 195 clipped_bitmap.copyTo(&result, kN32_SkColorType); |
| 228 #endif | 196 #endif |
| 229 | 197 |
| 230 LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName, | 198 LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName, |
| 231 base::TimeTicks::Now() - begin_compute_thumbnail); | 199 base::TimeTicks::Now() - begin_compute_thumbnail); |
| 232 return result; | 200 return result; |
| 233 } | 201 } |
| 234 | 202 |
| 235 } // namespace thumbnails | 203 } // namespace thumbnails |
| OLD | NEW |