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

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: address comments 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 12 matching lines...) Expand all
23 #include "content/public/browser/render_process_host.h" 23 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h" 24 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/render_widget_host_view.h" 25 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/web_contents.h" 26 #include "content/public/browser/web_contents.h"
27 #include "googleurl/src/gurl.h" 27 #include "googleurl/src/gurl.h"
28 #include "skia/ext/image_operations.h" 28 #include "skia/ext/image_operations.h"
29 #include "skia/ext/platform_canvas.h" 29 #include "skia/ext/platform_canvas.h"
30 #include "third_party/skia/include/core/SkBitmap.h" 30 #include "third_party/skia/include/core/SkBitmap.h"
31 #include "ui/gfx/color_utils.h" 31 #include "ui/gfx/color_utils.h"
32 #include "ui/gfx/rect.h" 32 #include "ui/gfx/rect.h"
33 #include "ui/gfx/scrollbar_size.h"
33 #include "ui/gfx/skbitmap_operations.h" 34 #include "ui/gfx/skbitmap_operations.h"
34 35
35 #if defined(OS_WIN) 36 #if defined(OS_WIN)
36 #include "base/win/windows_version.h" 37 #include "base/win/windows_version.h"
37 #endif 38 #endif
38 39
39 // Overview 40 // Overview
40 // -------- 41 // --------
41 // This class provides current thumbnails for tabs. The simplest operation is 42 // This class provides current thumbnails for tabs. The simplest operation is
42 // when a request for a thumbnail comes in, to grab the backing store and make 43 // when a request for a thumbnail comes in, to grab the backing store and make
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
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 float desired_aspect =
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 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 pixels that will commonly hold a scrollbar, which looks bad in
106 { 0, 0, 152 // thumbnails.
107 std::max(1, bmp_with_scrollbars.width() - 15), 153 int scrollbar_size = gfx::scrollbar_size();
108 std::max(1, bmp_with_scrollbars.height() - 15) }; 154 SkIRect scrollbarless_rect =
109 SkBitmap bmp; 155 { 0, 0,
110 bmp_with_scrollbars.extractSubset(&bmp, scrollbarless_rect); 156 std::max(1, bitmap.width() - scrollbar_size),
157 std::max(1, bitmap.height() - scrollbar_size) };
158 SkBitmap bmp;
159 bitmap.extractSubset(&bmp, scrollbarless_rect);
111 160
112 SkBitmap clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( 161 clipped_bitmap = ThumbnailGenerator::GetClippedBitmap(
113 bmp, desired_width, desired_height, clip_result); 162 bmp, desired_width, desired_height, clip_result);
163 } else {
164 clipped_bitmap = bitmap;
165 }
114 166
115 // Need to resize it to the size we want, so downsample until it's 167 // 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. 168 // close, and let the caller make it the exact size if desired.
117 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize( 169 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize(
118 clipped_bitmap, desired_width, desired_height); 170 clipped_bitmap, desired_width, desired_height);
119 #if !defined(USE_AURA) 171 #if !defined(USE_AURA)
120 // This is a bit subtle. SkBitmaps are refcounted, but the magic 172 // This is a bit subtle. SkBitmaps are refcounted, but the magic
121 // ones in PlatformCanvas can't be assigned to SkBitmap with proper 173 // ones in PlatformCanvas can't be assigned to SkBitmap with proper
122 // refcounting. If the bitmap doesn't change, then the downsampler 174 // refcounting. If the bitmap doesn't change, then the downsampler
123 // will return the input bitmap, which will be the reference to the 175 // 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 421
370 int color_count = *std::max_element(histogram, histogram + 256); 422 int color_count = *std::max_element(histogram, histogram + 256);
371 int pixel_count = bitmap.width() * bitmap.height(); 423 int pixel_count = bitmap.width() * bitmap.height();
372 return static_cast<double>(color_count) / pixel_count; 424 return static_cast<double>(color_count) / pixel_count;
373 } 425 }
374 426
375 SkBitmap ThumbnailGenerator::GetClippedBitmap(const SkBitmap& bitmap, 427 SkBitmap ThumbnailGenerator::GetClippedBitmap(const SkBitmap& bitmap,
376 int desired_width, 428 int desired_width,
377 int desired_height, 429 int desired_height,
378 ClipResult* clip_result) { 430 ClipResult* clip_result) {
379 const SkRect dest_rect = { 0, 0, 431 gfx::Rect clipping_rect =
380 SkIntToScalar(desired_width), 432 GetClippingRect(gfx::Size(bitmap.width(), bitmap.height()),
381 SkIntToScalar(desired_height) }; 433 gfx::Size(desired_width, desired_height),
382 const float dest_aspect = dest_rect.width() / dest_rect.height(); 434 clip_result);
383 435 SkIRect src_rect = { clipping_rect.x(), clipping_rect.y(),
384 // Get the src rect so that we can preserve the aspect ratio while filling 436 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; 437 SkBitmap clipped_bitmap;
423 bitmap.extractSubset(&clipped_bitmap, src_rect); 438 bitmap.extractSubset(&clipped_bitmap, src_rect);
424 return clipped_bitmap; 439 return clipped_bitmap;
425 } 440 }
426 441
427 void ThumbnailGenerator::UpdateThumbnailIfNecessary( 442 void ThumbnailGenerator::UpdateThumbnailIfNecessary(
428 WebContents* web_contents) { 443 WebContents* web_contents) {
429 // Skip if a pending entry exists. WidgetHidden can be called while navigaing 444 // 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. 445 // pages and this is not a timing when thumbnails should be generated.
431 if (web_contents->GetController().GetPendingEntry()) 446 if (web_contents->GetController().GetPendingEntry())
432 return; 447 return;
433 const GURL& url = web_contents->GetURL(); 448 const GURL& url = web_contents->GetURL();
434 Profile* profile = 449 Profile* profile =
435 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 450 Profile::FromBrowserContext(web_contents->GetBrowserContext());
436 history::TopSites* top_sites = profile->GetTopSites(); 451 history::TopSites* top_sites = profile->GetTopSites();
437 // Skip if we don't need to update the thumbnail. 452 // Skip if we don't need to update the thumbnail.
438 if (!ShouldUpdateThumbnail(profile, top_sites, url)) 453 if (!ShouldUpdateThumbnail(profile, top_sites, url))
439 return; 454 return;
440 455
441 AsyncUpdateThumbnail(web_contents); 456 AsyncUpdateThumbnail(web_contents);
442 } 457 }
443 458
444 void ThumbnailGenerator::UpdateThumbnail( 459 void ThumbnailGenerator::UpdateThumbnail(
445 WebContents* web_contents, const SkBitmap& thumbnail, 460 WebContents* web_contents, const SkBitmap& thumbnail,
446 const ThumbnailGenerator::ClipResult& clip_result) { 461 const ClipResult& clip_result) {
447 462
448 Profile* profile = 463 Profile* profile =
449 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 464 Profile::FromBrowserContext(web_contents->GetBrowserContext());
450 history::TopSites* top_sites = profile->GetTopSites(); 465 history::TopSites* top_sites = profile->GetTopSites();
451 if (!top_sites) 466 if (!top_sites)
452 return; 467 return;
453 468
454 // Compute the thumbnail score. 469 // Compute the thumbnail score.
455 ThumbnailScore score; 470 ThumbnailScore score;
456 score.at_top = 471 score.at_top =
(...skipping 22 matching lines...) Expand all
479 #if defined(OS_WIN) 494 #if defined(OS_WIN)
480 // On Windows XP, neither the backing store nor the compositing surface is 495 // On Windows XP, neither the backing store nor the compositing surface is
481 // available in the browser when accelerated compositing is active, so ask 496 // available in the browser when accelerated compositing is active, so ask
482 // the renderer to send a snapshot for creating the thumbnail. 497 // the renderer to send a snapshot for creating the thumbnail.
483 if (base::win::GetVersion() < base::win::VERSION_VISTA) { 498 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
484 gfx::Size view_size = 499 gfx::Size view_size =
485 render_widget_host->GetView()->GetViewBounds().size(); 500 render_widget_host->GetView()->GetViewBounds().size();
486 AskForSnapshot(render_widget_host, 501 AskForSnapshot(render_widget_host,
487 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithBitmap, 502 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithBitmap,
488 weak_factory_.GetWeakPtr(), 503 weak_factory_.GetWeakPtr(),
489 web_contents), 504 web_contents,
505 ThumbnailGenerator::kUnprocessed),
490 view_size, 506 view_size,
491 view_size); 507 view_size);
492 } 508 }
493 #endif 509 #endif
494 return; 510 return;
495 } 511 }
496 512
513 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
514 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
515 // thumbnails.
516 int scrollbar_size = gfx::scrollbar_size();
517 copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size);
518 ClipResult clip_result = ThumbnailGenerator::kUnprocessed;
519 copy_rect = GetClippingRect(copy_rect.size(),
520 gfx::Size(kThumbnailWidth, kThumbnailHeight),
521 &clip_result);
497 gfx::Size copy_size = 522 gfx::Size copy_size =
498 GetCopySizeForThumbnail(view->GetViewBounds().size(), 523 gfx::Size(kThumbnailWidth, kThumbnailHeight).Scale(kThumbnailCopyScale);
499 gfx::Size(kThumbnailWidth, kThumbnailHeight));
500 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas; 524 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas;
501 render_widget_host->CopyFromBackingStore( 525 render_widget_host->CopyFromBackingStore(
502 gfx::Rect(), 526 copy_rect,
503 copy_size, 527 copy_size,
504 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas, 528 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas,
505 weak_factory_.GetWeakPtr(), 529 weak_factory_.GetWeakPtr(),
506 web_contents, 530 web_contents,
531 clip_result,
507 base::Owned(temp_canvas)), 532 base::Owned(temp_canvas)),
508 temp_canvas); 533 temp_canvas);
509 } 534 }
510 535
511 void ThumbnailGenerator::UpdateThumbnailWithBitmap( 536 void ThumbnailGenerator::UpdateThumbnailWithBitmap(
512 WebContents* web_contents, 537 WebContents* web_contents,
538 ClipResult clip_result,
513 const SkBitmap& bitmap) { 539 const SkBitmap& bitmap) {
514 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 540 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
515 if (bitmap.isNull() || bitmap.empty()) 541 if (bitmap.isNull() || bitmap.empty())
516 return; 542 return;
517 543
518 ClipResult clip_result;
519 SkBitmap thumbnail = CreateThumbnail(bitmap, 544 SkBitmap thumbnail = CreateThumbnail(bitmap,
520 kThumbnailWidth, 545 kThumbnailWidth,
521 kThumbnailHeight, 546 kThumbnailHeight,
522 &clip_result); 547 &clip_result);
523 UpdateThumbnail(web_contents, thumbnail, clip_result); 548 UpdateThumbnail(web_contents, thumbnail, clip_result);
524 } 549 }
525 550
526 void ThumbnailGenerator::UpdateThumbnailWithCanvas( 551 void ThumbnailGenerator::UpdateThumbnailWithCanvas(
527 WebContents* web_contents, 552 WebContents* web_contents,
553 ClipResult clip_result,
528 skia::PlatformCanvas* temp_canvas, 554 skia::PlatformCanvas* temp_canvas,
529 bool succeeded) { 555 bool succeeded) {
530 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 556 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
531 if (!succeeded) 557 if (!succeeded)
532 return; 558 return;
533 559
534 SkBitmap bmp_with_scrollbars = 560 SkBitmap bitmap = skia::GetTopDevice(*temp_canvas)->accessBitmap(false);
535 skia::GetTopDevice(*temp_canvas)->accessBitmap(false); 561 UpdateThumbnailWithBitmap(web_contents, clip_result, bitmap);
536 UpdateThumbnailWithBitmap(web_contents, bmp_with_scrollbars);
537 } 562 }
538 563
539 bool ThumbnailGenerator::ShouldUpdateThumbnail(Profile* profile, 564 bool ThumbnailGenerator::ShouldUpdateThumbnail(Profile* profile,
540 history::TopSites* top_sites, 565 history::TopSites* top_sites,
541 const GURL& url) { 566 const GURL& url) {
542 if (!profile || !top_sites) 567 if (!profile || !top_sites)
543 return false; 568 return false;
544 // Skip if it's in the incognito mode. 569 // Skip if it's in the incognito mode.
545 if (profile->IsOffTheRecord()) 570 if (profile->IsOffTheRecord())
546 return false; 571 return false;
(...skipping 21 matching lines...) Expand all
568 void ThumbnailGenerator::DidStartLoading( 593 void ThumbnailGenerator::DidStartLoading(
569 content::RenderViewHost* render_view_host) { 594 content::RenderViewHost* render_view_host) {
570 load_interrupted_ = false; 595 load_interrupted_ = false;
571 } 596 }
572 597
573 void ThumbnailGenerator::StopNavigation() { 598 void ThumbnailGenerator::StopNavigation() {
574 // This function gets called when the page loading is interrupted by the 599 // This function gets called when the page loading is interrupted by the
575 // stop button. 600 // stop button.
576 load_interrupted_ = true; 601 load_interrupted_ = true;
577 } 602 }
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