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

Side by Side Diff: chrome/browser/tab_contents/thumbnail_generator.cc

Issue 10831063: Clip the bitmap for creating the thumbnail on GPU when accelerated compositing is active. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 4 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/tab_contents/thumbnail_generator.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 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/tab_contents/thumbnail_generator.h" 5 #include "chrome/browser/tab_contents/thumbnail_generator.h"
6 6
7 #include <algorithm> 7 #include <algorithm>
8 #include <map> 8 #include <map>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 47 matching lines...) Expand 10 before | Expand all | Expand 10 after
58 // service generates. 58 // service generates.
59 59
60 using content::RenderViewHost; 60 using content::RenderViewHost;
61 using content::RenderWidgetHost; 61 using content::RenderWidgetHost;
62 using content::WebContents; 62 using content::WebContents;
63 63
64 namespace { 64 namespace {
65 65
66 static const int kThumbnailWidth = 212; 66 static const int kThumbnailWidth = 212;
67 static const int kThumbnailHeight = 132; 67 static const int kThumbnailHeight = 132;
68 static const int kScrollbarThickness = 15;
brettw 2012/08/05 05:38:39 I wonder, can we get the actual value from the the
mazda 2012/08/06 17:22:16 I found a function to get scrollbar size in ui/gfx
68 69
69 // This factor determines the number of pixels to be copied by 70 // This factor determines the number of pixels to be copied by
70 // RenderWidgetHost::CopyFromBackingStore for generating thumbnail. 71 // RenderWidgetHost::CopyFromBackingStore for generating thumbnail.
71 // Smaller scale is good for performance, but too small scale causes aliasing 72 // Smaller scale is good for performance, but too small scale causes aliasing
72 // because the resampling method is not good enough to retain the image quality. 73 // because the resampling method is not good enough to retain the image quality.
73 // TODO(mazda): the Improve resampling method and use a smaller scale 74 // TODO(mazda): the Improve resampling method and use a smaller scale
74 // (http://crbug.com/118571). 75 // (http://crbug.com/118571).
75 static const double kThumbnailCopyScale = 2.0; 76 static const double kThumbnailCopyScale = 2.0;
76 77
77 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS"; 78 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS";
78 79
79 // Calculates the size used by RenderWidgetHost::CopyFromBackingStore. 80 // Calculates the size used by RenderWidgetHost::CopyFromBackingStore.
80 // The result is computed as the minimum size that satisfies the following 81 // The result is computed as the minimum size that satisfies the following
81 // conditions. 82 // conditions.
82 // result.width : result.height == view_size.width : view_size.height 83 // result.width : result.height == view_size.width : view_size.height
83 // result.width >= kThumbnailCopyScale * desired_size.width 84 // result.width >= kThumbnailCopyScale * desired_size.width
84 // result.height >= kThumbnailCopyScale * desired_size.height 85 // result.height >= kThumbnailCopyScale * desired_size.height
85 gfx::Size GetCopySizeForThumbnail(const gfx::Size& view_size, 86 gfx::Size GetCopySizeForThumbnail(const gfx::Size& view_size,
86 const gfx::Size& desired_size) { 87 const gfx::Size& desired_size) {
87 const double scale = kThumbnailCopyScale * 88 const double scale = kThumbnailCopyScale *
88 std::max(static_cast<double>(desired_size.width()) / view_size.width(), 89 std::max(static_cast<double>(desired_size.width()) / view_size.width(),
89 static_cast<double>(desired_size.height()) / view_size.height()); 90 static_cast<double>(desired_size.height()) / view_size.height());
90 return gfx::Size(static_cast<int>(scale * view_size.width()), 91 return gfx::Size(static_cast<int>(scale * view_size.width()),
91 static_cast<int>(scale * view_size.height())); 92 static_cast<int>(scale * view_size.height()));
92 } 93 }
93 94
95 // Returns the clipping rectangle that is used for creating a thumbnail with
96 // the size of |desired_size| from the bitmap with the size of |source_size|.
97 // The type of clipping that needs to be done is assigned to |clip_result|.
98 gfx::Rect GetClippingRect(const gfx::Size& source_size,
99 const gfx::Size& desired_size,
100 ThumbnailGenerator::ClipResult* clip_result) {
101 DCHECK(clip_result);
102
103 const float desired_aspect =
brettw 2012/08/05 05:38:39 Optional: IMO const in this case just adds noise (
mazda 2012/08/06 17:22:16 Removed const.
104 static_cast<float>(desired_size.width()) / desired_size.height();
105
106 // Get the clipping rect so that we can preserve the aspect ratio while
107 // filling the destination.
108 gfx::Rect clipping_rect;
109 if (source_size.width() < desired_size.width() ||
110 source_size.height() < desired_size.height()) {
111 // Source image is smaller: we clip the part of source image within the
112 // dest rect, and then stretch it to fill the dest rect. We don't respect
113 // the aspect ratio in this case.
114 clipping_rect = gfx::Rect(desired_size);
115 *clip_result = ThumbnailGenerator::kSourceIsSmaller;
116 } else {
117 const float src_aspect =
118 static_cast<float>(source_size.width()) / source_size.height();
119 if (src_aspect > desired_aspect) {
120 // Wider than tall, clip horizontally: we center the smaller
121 // thumbnail in the wider screen.
122 int new_width = static_cast<int>(source_size.height() * desired_aspect);
123 int x_offset = (source_size.width() - new_width) / 2;
124 clipping_rect.SetRect(x_offset, 0, new_width, source_size.height());
125 *clip_result = (src_aspect >= ThumbnailScore::kTooWideAspectRatio) ?
126 ThumbnailGenerator::kTooWiderThanTall :
127 ThumbnailGenerator::kWiderThanTall;
128 } else if (src_aspect < desired_aspect) {
129 clipping_rect =
130 gfx::Rect(source_size.width(), source_size.width() / desired_aspect);
131 *clip_result = ThumbnailGenerator::kTallerThanWide;
132 } else {
133 clipping_rect = gfx::Rect(source_size);
134 *clip_result = ThumbnailGenerator::kNotClipped;
135 }
136 }
137 return clipping_rect;
138 }
139
94 // Creates a downsampled thumbnail from the given bitmap. 140 // Creates a downsampled thumbnail from the given bitmap.
95 // store. The returned bitmap will be isNull if there was an error creating it. 141 // store. The returned bitmap will be isNull if there was an error creating it.
96 SkBitmap CreateThumbnail( 142 SkBitmap CreateThumbnail(
97 const SkBitmap& bmp_with_scrollbars, 143 const SkBitmap& bitmap,
98 int desired_width, 144 int desired_width,
99 int desired_height, 145 int desired_height,
100 ThumbnailGenerator::ClipResult* clip_result) { 146 ThumbnailGenerator::ClipResult* clip_result) {
101 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); 147 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
102 148
103 // Clip the edgemost 15 pixels as that will commonly hold a scrollbar, which 149 SkBitmap clipped_bitmap;
104 // looks bad in thumbnails. 150 if (*clip_result == ThumbnailGenerator::kUnprocessed) {
105 SkIRect scrollbarless_rect = 151 // Clip the edgemost 15 pixels as that will commonly hold a scrollbar, which
brettw 2012/08/05 05:38:39 I'd remove the 15 pixel comment here since the act
mazda 2012/08/06 17:22:16 Removed the magic number (15) from the comment.
106 { 0, 0, 152 // looks bad in thumbnails.
107 std::max(1, bmp_with_scrollbars.width() - 15), 153 SkIRect scrollbarless_rect =
108 std::max(1, bmp_with_scrollbars.height() - 15) }; 154 { 0, 0,
109 SkBitmap bmp; 155 std::max(1, bitmap.width() - kScrollbarThickness),
110 bmp_with_scrollbars.extractSubset(&bmp, scrollbarless_rect); 156 std::max(1, bitmap.height() - kScrollbarThickness) };
157 SkBitmap bmp;
158 bitmap.extractSubset(&bmp, scrollbarless_rect);
111 159
112 SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( 160 clipped_bitmap = ThumbnailGenerator::GetClippedBitmap(
113 bmp, desired_width, desired_height, clip_result); 161 bmp, desired_width, desired_height, clip_result);
162 } else {
163 clipped_bitmap = bitmap;
164 }
114 165
115 // Need to resize it to the size we want, so downsample until it's 166 // Need to resize it to the size we want, so downsample until it's
116 // close, and let the caller make it the exact size if desired. 167 // close, and let the caller make it the exact size if desired.
117 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize( 168 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize(
118 clipped_bitmap, desired_width, desired_height); 169 clipped_bitmap, desired_width, desired_height);
119 #if !defined(USE_AURA) 170 #if !defined(USE_AURA)
120 // This is a bit subtle. SkBitmaps are refcounted, but the magic 171 // This is a bit subtle. SkBitmaps are refcounted, but the magic
121 // ones in PlatformCanvas can't be assigned to SkBitmap with proper 172 // ones in PlatformCanvas can't be assigned to SkBitmap with proper
122 // refcounting. If the bitmap doesn't change, then the downsampler 173 // refcounting. If the bitmap doesn't change, then the downsampler
123 // will return the input bitmap, which will be the reference to the 174 // will return the input bitmap, which will be the reference to the
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after
369 420
370 int color_count = *std::max_element(histogram, histogram + 256); 421 int color_count = *std::max_element(histogram, histogram + 256);
371 int pixel_count = bitmap.width() * bitmap.height(); 422 int pixel_count = bitmap.width() * bitmap.height();
372 return static_cast<double>(color_count) / pixel_count; 423 return static_cast<double>(color_count) / pixel_count;
373 } 424 }
374 425
375 SkBitmap ThumbnailGenerator::GetClippedBitmap(const SkBitmap& bitmap, 426 SkBitmap ThumbnailGenerator::GetClippedBitmap(const SkBitmap& bitmap,
376 int desired_width, 427 int desired_width,
377 int desired_height, 428 int desired_height,
378 ClipResult* clip_result) { 429 ClipResult* clip_result) {
379 const SkRect dest_rect = { 0, 0, 430 gfx::Rect clipping_rect =
380 SkIntToScalar(desired_width), 431 GetClippingRect(gfx::Size(bitmap.width(), bitmap.height()),
381 SkIntToScalar(desired_height) }; 432 gfx::Size(desired_width, desired_height),
382 const float dest_aspect = dest_rect.width() / dest_rect.height(); 433 clip_result);
383 434 SkIRect src_rect = { clipping_rect.x(), clipping_rect.y(),
384 // Get the src rect so that we can preserve the aspect ratio while filling 435 clipping_rect.right(), clipping_rect.bottom() };
385 // the destination.
386 SkIRect src_rect;
387 if (bitmap.width() < dest_rect.width() ||
388 bitmap.height() < dest_rect.height()) {
389 // Source image is smaller: we clip the part of source image within the
390 // dest rect, and then stretch it to fill the dest rect. We don't respect
391 // the aspect ratio in this case.
392 src_rect.set(0, 0, static_cast<S16CPU>(dest_rect.width()),
393 static_cast<S16CPU>(dest_rect.height()));
394 if (clip_result)
395 *clip_result = ThumbnailGenerator::kSourceIsSmaller;
396 } else {
397 const float src_aspect =
398 static_cast<float>(bitmap.width()) / bitmap.height();
399 if (src_aspect > dest_aspect) {
400 // Wider than tall, clip horizontally: we center the smaller
401 // thumbnail in the wider screen.
402 S16CPU new_width = static_cast<S16CPU>(bitmap.height() * dest_aspect);
403 S16CPU x_offset = (bitmap.width() - new_width) / 2;
404 src_rect.set(x_offset, 0, new_width + x_offset, bitmap.height());
405 if (clip_result) {
406 *clip_result = (src_aspect >= ThumbnailScore::kTooWideAspectRatio) ?
407 ThumbnailGenerator::kTooWiderThanTall :
408 ThumbnailGenerator::kWiderThanTall;
409 }
410 } else if (src_aspect < dest_aspect) {
411 src_rect.set(0, 0, bitmap.width(),
412 static_cast<S16CPU>(bitmap.width() / dest_aspect));
413 if (clip_result)
414 *clip_result = ThumbnailGenerator::kTallerThanWide;
415 } else {
416 src_rect.set(0, 0, bitmap.width(), bitmap.height());
417 if (clip_result)
418 *clip_result = ThumbnailGenerator::kNotClipped;
419 }
420 }
421
422 SkBitmap clipped_bitmap; 436 SkBitmap clipped_bitmap;
423 bitmap.extractSubset(&clipped_bitmap, src_rect); 437 bitmap.extractSubset(&clipped_bitmap, src_rect);
424 return clipped_bitmap; 438 return clipped_bitmap;
425 } 439 }
426 440
427 void ThumbnailGenerator::UpdateThumbnailIfNecessary( 441 void ThumbnailGenerator::UpdateThumbnailIfNecessary(
428 WebContents* web_contents) { 442 WebContents* web_contents) {
429 // Skip if a pending entry exists. WidgetHidden can be called while navigaing 443 // Skip if a pending entry exists. WidgetHidden can be called while navigaing
430 // pages and this is not a timing when thumbnails should be generated. 444 // pages and this is not a timing when thumbnails should be generated.
431 if (web_contents->GetController().GetPendingEntry()) 445 if (web_contents->GetController().GetPendingEntry())
432 return; 446 return;
433 const GURL& url = web_contents->GetURL(); 447 const GURL& url = web_contents->GetURL();
434 Profile* profile = 448 Profile* profile =
435 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 449 Profile::FromBrowserContext(web_contents->GetBrowserContext());
436 history::TopSites* top_sites = profile->GetTopSites(); 450 history::TopSites* top_sites = profile->GetTopSites();
437 // Skip if we don't need to update the thumbnail. 451 // Skip if we don't need to update the thumbnail.
438 if (!ShouldUpdateThumbnail(profile, top_sites, url)) 452 if (!ShouldUpdateThumbnail(profile, top_sites, url))
439 return; 453 return;
440 454
441 AsyncUpdateThumbnail(web_contents); 455 AsyncUpdateThumbnail(web_contents);
442 } 456 }
443 457
444 void ThumbnailGenerator::UpdateThumbnail( 458 void ThumbnailGenerator::UpdateThumbnail(
445 WebContents* web_contents, const SkBitmap& thumbnail, 459 WebContents* web_contents, const SkBitmap& thumbnail,
446 const ThumbnailGenerator::ClipResult& clip_result) { 460 const ClipResult& clip_result) {
447 461
448 Profile* profile = 462 Profile* profile =
449 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 463 Profile::FromBrowserContext(web_contents->GetBrowserContext());
450 history::TopSites* top_sites = profile->GetTopSites(); 464 history::TopSites* top_sites = profile->GetTopSites();
451 if (!top_sites) 465 if (!top_sites)
452 return; 466 return;
453 467
454 // Compute the thumbnail score. 468 // Compute the thumbnail score.
455 ThumbnailScore score; 469 ThumbnailScore score;
456 score.at_top = 470 score.at_top =
(...skipping 22 matching lines...) Expand all
479 #if defined(OS_WIN) 493 #if defined(OS_WIN)
480 // On Windows XP, neither the backing store nor the compositing surface is 494 // On Windows XP, neither the backing store nor the compositing surface is
481 // available in the browser when accelerated compositing is active, so ask 495 // available in the browser when accelerated compositing is active, so ask
482 // the renderer to send a snapshot for creating the thumbnail. 496 // the renderer to send a snapshot for creating the thumbnail.
483 if (base::win::GetVersion() < base::win::VERSION_VISTA) { 497 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
484 gfx::Size view_size = 498 gfx::Size view_size =
485 render_widget_host->GetView()->GetViewBounds().size(); 499 render_widget_host->GetView()->GetViewBounds().size();
486 AskForSnapshot(render_widget_host, 500 AskForSnapshot(render_widget_host,
487 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithBitmap, 501 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithBitmap,
488 weak_factory_.GetWeakPtr(), 502 weak_factory_.GetWeakPtr(),
489 web_contents), 503 web_contents,
504 ThumbnailGenerator::kUnprocessed),
490 view_size, 505 view_size,
491 view_size); 506 view_size);
492 } 507 }
493 #endif 508 #endif
494 return; 509 return;
495 } 510 }
496 511
512 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
513 // Clip the edgemost 15 pixels as that will commonly hold a scrollbar, which
brettw 2012/08/05 05:38:39 Ditto w/ "15 pixels."
mazda 2012/08/06 17:22:16 Done.
514 // looks bad in thumbnails.
515 copy_rect.Inset(0, 0, kScrollbarThickness, kScrollbarThickness);
516 ClipResult clip_result = ThumbnailGenerator::kUnprocessed;
517 copy_rect = GetClippingRect(copy_rect.size(),
518 gfx::Size(kThumbnailWidth, kThumbnailHeight),
519 &clip_result);
497 gfx::Size copy_size = 520 gfx::Size copy_size =
498 GetCopySizeForThumbnail(view->GetViewBounds().size(), 521 gfx::Size(kThumbnailWidth, kThumbnailHeight).Scale(kThumbnailCopyScale);
499 gfx::Size(kThumbnailWidth, kThumbnailHeight));
500 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas; 522 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas;
501 render_widget_host->CopyFromBackingStore( 523 render_widget_host->CopyFromBackingStore(
502 gfx::Rect(), 524 copy_rect,
503 copy_size, 525 copy_size,
504 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas, 526 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas,
505 weak_factory_.GetWeakPtr(), 527 weak_factory_.GetWeakPtr(),
506 web_contents, 528 web_contents,
529 clip_result,
507 base::Owned(temp_canvas)), 530 base::Owned(temp_canvas)),
508 temp_canvas); 531 temp_canvas);
509 } 532 }
510 533
511 void ThumbnailGenerator::UpdateThumbnailWithBitmap( 534 void ThumbnailGenerator::UpdateThumbnailWithBitmap(
512 WebContents* web_contents, 535 WebContents* web_contents,
536 ClipResult clip_result,
513 const SkBitmap& bitmap) { 537 const SkBitmap& bitmap) {
514 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 538 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
515 if (bitmap.isNull() || bitmap.empty()) 539 if (bitmap.isNull() || bitmap.empty())
516 return; 540 return;
517 541
518 ClipResult clip_result;
519 SkBitmap thumbnail = CreateThumbnail(bitmap, 542 SkBitmap thumbnail = CreateThumbnail(bitmap,
520 kThumbnailWidth, 543 kThumbnailWidth,
521 kThumbnailHeight, 544 kThumbnailHeight,
522 &clip_result); 545 &clip_result);
523 UpdateThumbnail(web_contents, thumbnail, clip_result); 546 UpdateThumbnail(web_contents, thumbnail, clip_result);
524 } 547 }
525 548
526 void ThumbnailGenerator::UpdateThumbnailWithCanvas( 549 void ThumbnailGenerator::UpdateThumbnailWithCanvas(
527 WebContents* web_contents, 550 WebContents* web_contents,
551 ClipResult clip_result,
528 skia::PlatformCanvas* temp_canvas, 552 skia::PlatformCanvas* temp_canvas,
529 bool succeeded) { 553 bool succeeded) {
530 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 554 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
531 if (!succeeded) 555 if (!succeeded)
532 return; 556 return;
533 557
534 SkBitmap bmp_with_scrollbars = 558 SkBitmap bitmap = skia::GetTopDevice(*temp_canvas)->accessBitmap(false);
535 skia::GetTopDevice(*temp_canvas)->accessBitmap(false); 559 UpdateThumbnailWithBitmap(web_contents, clip_result, bitmap);
536 UpdateThumbnailWithBitmap(web_contents, bmp_with_scrollbars);
537 } 560 }
538 561
539 bool ThumbnailGenerator::ShouldUpdateThumbnail(Profile* profile, 562 bool ThumbnailGenerator::ShouldUpdateThumbnail(Profile* profile,
540 history::TopSites* top_sites, 563 history::TopSites* top_sites,
541 const GURL& url) { 564 const GURL& url) {
542 if (!profile || !top_sites) 565 if (!profile || !top_sites)
543 return false; 566 return false;
544 // Skip if it's in the incognito mode. 567 // Skip if it's in the incognito mode.
545 if (profile->IsOffTheRecord()) 568 if (profile->IsOffTheRecord())
546 return false; 569 return false;
(...skipping 21 matching lines...) Expand all
568 void ThumbnailGenerator::DidStartLoading( 591 void ThumbnailGenerator::DidStartLoading(
569 content::RenderViewHost* render_view_host) { 592 content::RenderViewHost* render_view_host) {
570 load_interrupted_ = false; 593 load_interrupted_ = false;
571 } 594 }
572 595
573 void ThumbnailGenerator::StopNavigation() { 596 void ThumbnailGenerator::StopNavigation() {
574 // This function gets called when the page loading is interrupted by the 597 // This function gets called when the page loading is interrupted by the
575 // stop button. 598 // stop button.
576 load_interrupted_ = true; 599 load_interrupted_ = true;
577 } 600 }
OLDNEW
« no previous file with comments | « chrome/browser/tab_contents/thumbnail_generator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698