Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2512)

Unified Diff: chrome/browser/tab_contents/thumbnail_generator.cc

Issue 6246007: Generate thumbnails in the browser process. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 9 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: chrome/browser/tab_contents/thumbnail_generator.cc
diff --git a/chrome/browser/tab_contents/thumbnail_generator.cc b/chrome/browser/tab_contents/thumbnail_generator.cc
index a26bca08c39766143ca231983fa211eaaa5bd4ae..82766c3b7a3a36d73e7c3fea91186efb6c240755 100644
--- a/chrome/browser/tab_contents/thumbnail_generator.cc
+++ b/chrome/browser/tab_contents/thumbnail_generator.cc
@@ -17,8 +17,11 @@
#include "chrome/browser/tab_contents/tab_contents.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/property_bag.h"
+#include "gfx/color_utils.h"
#include "gfx/rect.h"
#include "gfx/skbitmap_operations.h"
+#include "skia/ext/bitmap_platform_device.h"
+#include "skia/ext/image_operations.h"
#include "skia/ext/platform_canvas.h"
#include "third_party/skia/include/core/SkBitmap.h"
@@ -97,11 +100,27 @@ WidgetThumbnail* GetDataForHost(RenderWidgetHost* host) {
return GetThumbnailAccessor()->GetProperty(host->property_bag());
}
+// Calculates how "boring" a thumbnail is. The boring score is the
+// 0,1 ranged percentage of pixels that are the most common
+// luma. Higher boring scores indicate that a higher percentage of a
+// bitmap are all the same brightness.
+static double CalculateBoringScore(SkBitmap* bitmap) {
+ int histogram[256] = {0};
+ color_utils::BuildLumaHistogram(bitmap, histogram);
+
+ int color_count = *std::max_element(histogram, histogram + 256);
+ int pixel_count = bitmap->width() * bitmap->height();
+ return static_cast<double>(color_count) / pixel_count;
+}
+
// Creates a downsampled thumbnail for the given backing store. The returned
// bitmap will be isNull if there was an error creating it.
-SkBitmap GetBitmapForBackingStore(BackingStore* backing_store,
- int desired_width,
- int desired_height) {
+SkBitmap GetBitmapForBackingStore(
+ BackingStore* backing_store,
+ int desired_width,
+ int desired_height,
+ int options,
+ ThumbnailGenerator::ThumbnailResult* thumbnail_result) {
base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
SkBitmap result;
@@ -115,20 +134,77 @@ SkBitmap GetBitmapForBackingStore(BackingStore* backing_store,
return result;
const SkBitmap& bmp = temp_canvas.getTopPlatformDevice().accessBitmap(false);
- // 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.
- result = SkBitmapOperations::DownsampleByTwoUntilSize(
- bmp, desired_width, desired_height);
-
- // This is a bit subtle. SkBitmaps are refcounted, but the magic
- // ones in PlatformCanvas can't be assigned to SkBitmap with proper
- // refcounting. If the bitmap doesn't change, then the downsampler
- // will return the input bitmap, which will be the reference to the
- // weird PlatformCanvas one insetad of a regular one. To get a
- // regular refcounted bitmap, we need to copy it.
- if (bmp.width() == result.width() &&
- bmp.height() == result.height())
- bmp.copyTo(&result, SkBitmap::kARGB_8888_Config);
+ // Check if a clipped thumbnail is requested.
+ if (options & ThumbnailGenerator::kClippedThumbnail) {
+ const SkRect dest_rect = { 0, 0,
+ SkIntToScalar(desired_width),
+ SkIntToScalar(desired_height) };
+ const float dest_aspect = dest_rect.width() / dest_rect.height();
+
+ // Get the src rect so that we can preserve the aspect ratio while filling
+ // the destination.
+ SkIRect src_rect;
+ if (bmp.width() < dest_rect.width() ||
+ bmp.height() < dest_rect.height()) {
+ // Source image is smaller: we clip the part of source image within the
+ // dest rect, and then stretch it to fill the dest rect. We don't respect
+ // the aspect ratio in this case.
+ src_rect.set(0, 0, static_cast<S16CPU>(dest_rect.width()),
+ static_cast<S16CPU>(dest_rect.height()));
+ if (thumbnail_result)
+ thumbnail_result->clip_result = ThumbnailGenerator::kSourceIsSmaller;
+ } else {
+ const float src_aspect =
+ static_cast<float>(bmp.width()) / bmp.height();
+ if (src_aspect > dest_aspect) {
+ // Wider than tall, clip horizontally: we center the smaller
+ // thumbnail in the wider screen.
+ S16CPU new_width = static_cast<S16CPU>(bmp.height() * dest_aspect);
+ S16CPU x_offset = (bmp.width() - new_width) / 2;
+ src_rect.set(x_offset, 0, new_width + x_offset, bmp.height());
+ if (thumbnail_result)
+ thumbnail_result->clip_result = ThumbnailGenerator::kWiderThanTall;
+ } else if (src_aspect < dest_aspect) {
+ src_rect.set(0, 0, bmp.width(),
+ static_cast<S16CPU>(bmp.width() / dest_aspect));
+ if (thumbnail_result)
+ thumbnail_result->clip_result = ThumbnailGenerator::kTallerThanWide;
+ } else {
+ src_rect.set(0, 0, bmp.width(), bmp.height());
+ if (thumbnail_result)
+ thumbnail_result->clip_result = ThumbnailGenerator::kNotClipped;
+ }
+ }
+
+ SkBitmap subset;
+ temp_canvas.getTopPlatformDevice().accessBitmap(false).
+ extractSubset(&subset, src_rect);
+
+ // 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.
+ result = SkBitmapOperations::DownsampleByTwoUntilSize(
+ subset, desired_width, desired_height);
+ } else {
+ // 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.
+ result = SkBitmapOperations::DownsampleByTwoUntilSize(
+ bmp, desired_width, desired_height);
+
+ // This is a bit subtle. SkBitmaps are refcounted, but the magic
+ // ones in PlatformCanvas can't be assigned to SkBitmap with proper
+ // refcounting. If the bitmap doesn't change, then the downsampler
+ // will return the input bitmap, which will be the reference to the
+ // weird PlatformCanvas one insetad of a regular one. To get a
+ // regular refcounted bitmap, we need to copy it.
+ if (bmp.width() == result.width() &&
+ bmp.height() == result.height())
+ bmp.copyTo(&result, SkBitmap::kARGB_8888_Config);
+ }
+
+ // Calculate the boring score if requested.
+ if (options & ThumbnailGenerator::kBoringScore && thumbnail_result) {
+ thumbnail_result->boring_score = CalculateBoringScore(&result);
+ }
HISTOGRAM_TIMES(kThumbnailHistogramName,
base::TimeTicks::Now() - begin_compute_thumbnail);
@@ -223,7 +299,9 @@ void ThumbnailGenerator::AskForSnapshot(RenderWidgetHost* renderer,
// we'll go with it.
SkBitmap first_try = GetBitmapForBackingStore(backing_store,
desired_size.width(),
- desired_size.height());
+ desired_size.height(),
+ kNone,
+ NULL);
callback->Run(first_try);
delete callback;
@@ -275,6 +353,13 @@ void ThumbnailGenerator::AskForSnapshot(RenderWidgetHost* renderer,
SkBitmap ThumbnailGenerator::GetThumbnailForRenderer(
RenderWidgetHost* renderer) const {
+ return GetThumbnailForRendererWithOptions(renderer, kNone, NULL);
+}
+
+SkBitmap ThumbnailGenerator::GetThumbnailForRendererWithOptions(
+ RenderWidgetHost* renderer,
+ int options,
+ ThumbnailResult* result) const {
WidgetThumbnail* wt = GetDataForHost(renderer);
BackingStore* backing_store = renderer->GetBackingStore(false);
@@ -299,7 +384,9 @@ SkBitmap ThumbnailGenerator::GetThumbnailForRenderer(
// invalidated on the next paint.
wt->thumbnail = GetBitmapForBackingStore(backing_store,
kThumbnailWidth,
- kThumbnailHeight);
+ kThumbnailHeight,
+ options,
+ result);
return wt->thumbnail;
}
@@ -320,7 +407,9 @@ void ThumbnailGenerator::WidgetWillDestroyBackingStore(
// an existing thumbnail.
SkBitmap new_thumbnail = GetBitmapForBackingStore(backing_store,
kThumbnailWidth,
- kThumbnailHeight);
+ kThumbnailHeight,
+ kNone,
+ NULL);
if (!new_thumbnail.isNull())
wt->thumbnail = new_thumbnail;
}

Powered by Google App Engine
This is Rietveld 408576698