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

Unified Diff: chrome/browser/thumbnails/thumbnail_tab_helper.cc

Issue 11985003: Refactored-out the code of thumbnaling algorithm from thumbnail_tab_helper. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Another round of updates from OWNER's review. Created 7 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/thumbnails/thumbnail_tab_helper.cc
diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
index 64837767c74ea7a67d31279d301d89bf38a5d5bf..40f8d8e998e92c571f48fbb2104d5a4b62a9b2c8 100644
--- a/chrome/browser/thumbnails/thumbnail_tab_helper.cc
+++ b/chrome/browser/thumbnails/thumbnail_tab_helper.cc
@@ -4,12 +4,13 @@
#include "chrome/browser/thumbnails/thumbnail_tab_helper.h"
-#include "base/metrics/histogram.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/thumbnails/render_widget_snapshot_taker.h"
#include "chrome/browser/thumbnails/thumbnail_service.h"
#include "chrome/browser/thumbnails/thumbnail_service_factory.h"
+#include "chrome/browser/thumbnails/thumbnailing_algorithm.h"
+#include "chrome/browser/thumbnails/thumbnailing_context.h"
#include "content/public/browser/notification_details.h"
#include "content/public/browser/notification_source.h"
#include "content/public/browser/notification_types.h"
@@ -45,191 +46,85 @@ using content::RenderViewHost;
using content::RenderWidgetHost;
using content::WebContents;
-namespace {
-
-// The thumbnail size in DIP.
-static const int kThumbnailWidth = 212;
-static const int kThumbnailHeight = 132;
+using thumbnails::ClipResult;
+using thumbnails::ThumbnailingContext;
+using thumbnails::ThumbnailingAlgorithm;
-static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS";
+namespace {
-// Returns the size used by RenderWidgetHost::CopyFromBackingStore.
-//
-// The size is calculated in such a way that the copied size in pixel becomes
-// equal to (f * kThumbnailWidth, f * kThumbnailHeight), where f is the scale
-// of ui::SCALE_FACTOR_200P. Since RenderWidgetHost::CopyFromBackingStore takes
-// the size in DIP, we need to adjust the size based on |view|'s device scale
-// factor in order to copy the pixels with the size above.
-//
-// The copied size was chosen for the following reasons.
-//
-// 1. When the scale factor of the primary monitor is ui::SCALE_FACTOR_200P, the
-// generated thumbnail size is (f * kThumbnailWidth, f * kThumbnailHeight).
-// 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 = gfx::ToFlooredSize(gfx::ScaleSize(
- copy_size, 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 = gfx::ToFlooredSize(gfx::ScaleSize(
- copy_size, ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P)));
- break;
- }
- return copy_size;
+// Feed the constructed thumbnail to the thumbnail service.
+void UpdateThumbnail(const ThumbnailingContext& context,
+ const SkBitmap& thumbnail) {
+ gfx::Image image(thumbnail);
+ context.service->SetPageThumbnail(context, image);
+ VLOG(1) << "Thumbnail taken for " << context.url << ": "
+ << context.score.ToString();
}
-// 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 maximum scale
- // factor.
- // TODO(mazda|oshima): Update thumbnail when the max scale factor changes.
- // crbug.com/159157.
- float max_scale_factor =
- ui::GetScaleFactorScale(ui::GetMaxScaleFactor());
- return gfx::ToFlooredSize(gfx::ScaleSize(thumbnail_size, max_scale_factor));
-}
+void ProcessCanvas(ThumbnailingContext* context,
+ ThumbnailingAlgorithm* algorithm,
+ skia::PlatformBitmap* temp_bitmap,
+ bool succeeded) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ if (!succeeded)
+ return;
-// Returns the clipping rectangle that is used for creating a thumbnail with
-// the size of |desired_size| from the bitmap with the size of |source_size|.
-// The type of clipping that needs to be done is assigned to |clip_result|.
-gfx::Rect GetClippingRect(const gfx::Size& source_size,
- const gfx::Size& desired_size,
- ThumbnailTabHelper::ClipResult* clip_result) {
- DCHECK(clip_result);
-
- float desired_aspect =
- static_cast<float>(desired_size.width()) / desired_size.height();
-
- // Get the clipping rect so that we can preserve the aspect ratio while
- // filling the destination.
- gfx::Rect clipping_rect;
- if (source_size.width() < desired_size.width() ||
- source_size.height() < desired_size.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.
- clipping_rect = gfx::Rect(desired_size);
- *clip_result = ThumbnailTabHelper::kSourceIsSmaller;
- } else {
- float src_aspect =
- static_cast<float>(source_size.width()) / source_size.height();
- if (src_aspect > desired_aspect) {
- // Wider than tall, clip horizontally: we center the smaller
- // thumbnail in the wider screen.
- int new_width = static_cast<int>(source_size.height() * desired_aspect);
- int x_offset = (source_size.width() - new_width) / 2;
- clipping_rect.SetRect(x_offset, 0, new_width, source_size.height());
- *clip_result = (src_aspect >= ThumbnailScore::kTooWideAspectRatio) ?
- ThumbnailTabHelper::kTooWiderThanTall :
- ThumbnailTabHelper::kWiderThanTall;
- } else if (src_aspect < desired_aspect) {
- clipping_rect =
- gfx::Rect(source_size.width(), source_size.width() / desired_aspect);
- *clip_result = ThumbnailTabHelper::kTallerThanWide;
- } else {
- clipping_rect = gfx::Rect(source_size);
- *clip_result = ThumbnailTabHelper::kNotClipped;
- }
- }
- return clipping_rect;
+ SkBitmap bitmap = temp_bitmap->GetBitmap();
+ algorithm->ProcessBitmap(context, base::Bind(&UpdateThumbnail), bitmap);
}
-// Creates a downsampled thumbnail from the given bitmap.
-// store. The returned bitmap will be isNull if there was an error creating it.
-SkBitmap CreateThumbnail(
- const SkBitmap& bitmap,
- const gfx::Size& desired_size,
- ThumbnailTabHelper::ClipResult* clip_result) {
- base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
-
- SkBitmap clipped_bitmap;
- if (*clip_result == ThumbnailTabHelper::kUnprocessed) {
- // Clip the pixels that will commonly hold a scrollbar, which looks bad in
- // thumbnails.
- int scrollbar_size = gfx::scrollbar_size();
- SkIRect scrollbarless_rect =
- { 0, 0,
- std::max(1, bitmap.width() - scrollbar_size),
- std::max(1, bitmap.height() - scrollbar_size) };
- SkBitmap bmp;
- bitmap.extractSubset(&bmp, scrollbarless_rect);
-
- clipped_bitmap = ThumbnailTabHelper::GetClippedBitmap(
- bmp, desired_size.width(), desired_size.height(), clip_result);
- } else {
- clipped_bitmap = bitmap;
+void AsyncProcessThumbnail(content::WebContents* web_contents,
+ scoped_refptr<ThumbnailingContext> context,
+ scoped_refptr<ThumbnailingAlgorithm> algorithm) {
+ DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
+ RenderWidgetHost* render_widget_host = web_contents->GetRenderViewHost();
+ content::RenderWidgetHostView* view = render_widget_host->GetView();
+ if (!view)
+ return;
+ if (!view->IsSurfaceAvailableForCopy()) {
+#if defined(OS_WIN)
+ // On Windows XP, neither the backing store nor the compositing surface is
+ // available in the browser when accelerated compositing is active, so ask
+ // the renderer to send a snapshot for creating the thumbnail.
+ if (base::win::GetVersion() < base::win::VERSION_VISTA) {
+ gfx::Size view_size =
+ render_widget_host->GetView()->GetViewBounds().size();
+ g_browser_process->GetRenderWidgetSnapshotTaker()->AskForSnapshot(
+ render_widget_host,
+ base::Bind(&ThumbnailingAlgorithm::ProcessBitmap,
+ algorithm, context, base::Bind(&UpdateThumbnail)),
+ view_size,
+ view_size);
+ }
+#endif
+ return;
}
- // 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.
- SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize(
- clipped_bitmap, desired_size.width(), desired_size.height());
-#if !defined(USE_AURA)
- // 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.
- //
- // On Aura, the PlatformCanvas is platform-independent and does not have
- // any native platform resources that can't be refounted, so this issue does
- // not occur.
- //
- // Note that GetClippedBitmap() does extractSubset() but it won't copy
- // the pixels, hence we check result size == clipped_bitmap size here.
- if (clipped_bitmap.width() == result.width() &&
- clipped_bitmap.height() == result.height())
- clipped_bitmap.copyTo(&result, SkBitmap::kARGB_8888_Config);
-#endif
+ gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
+ // Clip the pixels that will commonly hold a scrollbar, which looks bad in
+ // thumbnails.
+ int scrollbar_size = gfx::scrollbar_size();
+ gfx::Size copy_size;
+ copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size);
- HISTOGRAM_TIMES(kThumbnailHistogramName,
- base::TimeTicks::Now() - begin_compute_thumbnail);
- return result;
-}
+ if (copy_rect.IsEmpty())
+ return;
-} // namespace
+ context->clip_result = algorithm->GetCanvasCopyInfo(
+ copy_rect.size(),
+ ui::GetScaleFactorForNativeView(view->GetNativeView()),
+ &copy_rect,
+ &copy_size);
-ThumbnailTabHelper::ThumbnailingContext::ThumbnailingContext(
- content::WebContents* web_contents,
- bool load_interrupted)
- : browser_context(web_contents->GetBrowserContext()),
- url(web_contents->GetURL()),
- clip_result(kUnprocessed) {
- score.at_top =
- (web_contents->GetRenderViewHost()->GetLastScrollOffset().y() == 0);
- score.load_completed = !web_contents->IsLoading() && !load_interrupted;
+ skia::PlatformBitmap* temp_bitmap = new skia::PlatformBitmap;
+ render_widget_host->CopyFromBackingStore(
+ copy_rect,
+ copy_size,
+ base::Bind(&ProcessCanvas, context, algorithm, base::Owned(temp_bitmap)),
+ temp_bitmap);
}
-ThumbnailTabHelper::ThumbnailingContext::~ThumbnailingContext() {
-}
+} // namespace
ThumbnailTabHelper::ThumbnailTabHelper(content::WebContents* contents)
: content::WebContentsObserver(contents),
@@ -310,32 +205,6 @@ void ThumbnailTabHelper::RenderViewHostDeleted(
content::Source<RenderViewHost>(renderer));
}
-double ThumbnailTabHelper::CalculateBoringScore(const SkBitmap& bitmap) {
- if (bitmap.isNull() || bitmap.empty())
- return 1.0;
- 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;
-}
-
-SkBitmap ThumbnailTabHelper::GetClippedBitmap(const SkBitmap& bitmap,
- int desired_width,
- int desired_height,
- ClipResult* clip_result) {
- gfx::Rect clipping_rect =
- GetClippingRect(gfx::Size(bitmap.width(), bitmap.height()),
- gfx::Size(desired_width, desired_height),
- clip_result);
- SkIRect src_rect = { clipping_rect.x(), clipping_rect.y(),
- clipping_rect.right(), clipping_rect.bottom() };
- SkBitmap clipped_bitmap;
- bitmap.extractSubset(&clipped_bitmap, src_rect);
- return clipped_bitmap;
-}
-
void ThumbnailTabHelper::UpdateThumbnailIfNecessary(
WebContents* web_contents) {
// Destroying a WebContents may trigger it to be hidden, prompting a snapshot
@@ -360,107 +229,14 @@ void ThumbnailTabHelper::UpdateThumbnailIfNecessary(
return;
}
- AsyncUpdateThumbnail(web_contents);
-}
-
-void ThumbnailTabHelper::UpdateThumbnail(
- ThumbnailingContext* context,
- const SkBitmap& thumbnail) {
- Profile* profile =
- Profile::FromBrowserContext(context->browser_context);
- scoped_refptr<thumbnails::ThumbnailService> thumbnail_service =
- ThumbnailServiceFactory::GetForProfile(profile);
-
- if (!thumbnail_service)
- return;
-
- context->score.boring_score = CalculateBoringScore(thumbnail);
- context->score.good_clipping =
- (context->clip_result == ThumbnailTabHelper::kWiderThanTall ||
- context->clip_result == ThumbnailTabHelper::kTallerThanWide ||
- context->clip_result == ThumbnailTabHelper::kNotClipped);
-
- gfx::Image image(thumbnail);
- thumbnail_service->SetPageThumbnail(context->url, image, context->score);
- VLOG(1) << "Thumbnail taken for " << context->url << ": "
- << context->score.ToString();
-}
-
-void ThumbnailTabHelper::AsyncUpdateThumbnail(
- WebContents* web_contents) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- RenderWidgetHost* render_widget_host = web_contents->GetRenderViewHost();
- content::RenderWidgetHostView* view = render_widget_host->GetView();
- if (!view)
- return;
- if (!view->IsSurfaceAvailableForCopy()) {
-#if defined(OS_WIN)
- // On Windows XP, neither the backing store nor the compositing surface is
- // available in the browser when accelerated compositing is active, so ask
- // the renderer to send a snapshot for creating the thumbnail.
- if (base::win::GetVersion() < base::win::VERSION_VISTA) {
- scoped_refptr<ThumbnailingContext> context(
- new ThumbnailingContext(web_contents, load_interrupted_));
- gfx::Size view_size =
- render_widget_host->GetView()->GetViewBounds().size();
- g_browser_process->GetRenderWidgetSnapshotTaker()->AskForSnapshot(
- render_widget_host,
- base::Bind(&ThumbnailTabHelper::UpdateThumbnailWithBitmap,
- context),
- view_size,
- view_size);
- }
-#endif
- return;
- }
-
- gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
- // Clip the pixels that will commonly hold a scrollbar, which looks bad in
- // thumbnails.
- int scrollbar_size = gfx::scrollbar_size();
- copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size);
+ scoped_refptr<thumbnails::ThumbnailingAlgorithm> algorithm(
+ thumbnail_service->GetThumbnailingAlgorithm());
scoped_refptr<ThumbnailingContext> context(
- new ThumbnailingContext(web_contents, load_interrupted_));
- copy_rect = GetClippingRect(copy_rect.size(),
- gfx::Size(kThumbnailWidth, kThumbnailHeight),
- &context->clip_result);
-
- gfx::Size copy_size = GetCopySizeForThumbnail(view);
- skia::PlatformBitmap* temp_bitmap = new skia::PlatformBitmap;
- render_widget_host->CopyFromBackingStore(
- copy_rect,
- copy_size,
- base::Bind(&ThumbnailTabHelper::UpdateThumbnailWithCanvas,
- context,
- base::Owned(temp_bitmap)),
- temp_bitmap);
-}
-
-void ThumbnailTabHelper::UpdateThumbnailWithBitmap(
- ThumbnailingContext* context,
- const SkBitmap& bitmap) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (bitmap.isNull() || bitmap.empty())
- return;
-
- SkBitmap thumbnail = CreateThumbnail(bitmap,
- GetThumbnailSizeInPixel(),
- &context->clip_result);
-
- UpdateThumbnail(context, thumbnail);
-}
-
-void ThumbnailTabHelper::UpdateThumbnailWithCanvas(
- ThumbnailingContext* context,
- skia::PlatformBitmap* temp_bitmap,
- bool succeeded) {
- DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
- if (!succeeded)
- return;
-
- SkBitmap bitmap = temp_bitmap->GetBitmap();
- UpdateThumbnailWithBitmap(context, bitmap);
+ new ThumbnailingContext(web_contents,
+ thumbnail_service,
+ load_interrupted_));
+ AsyncProcessThumbnail(web_contents, context, algorithm);
}
void ThumbnailTabHelper::DidStartLoading(
« no previous file with comments | « chrome/browser/thumbnails/thumbnail_tab_helper.h ('k') | chrome/browser/thumbnails/thumbnail_tab_helper_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698