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

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

Issue 10831207: Make ThumbnailGenerator support high DPI. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: address comment 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 | « no previous file | 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 <cmath>
8 #include <map> 9 #include <map>
9 10
10 #include "base/bind.h" 11 #include "base/bind.h"
11 #include "base/memory/scoped_ptr.h" 12 #include "base/memory/scoped_ptr.h"
12 #include "base/metrics/histogram.h" 13 #include "base/metrics/histogram.h"
13 #include "base/time.h" 14 #include "base/time.h"
14 #include "build/build_config.h" 15 #include "build/build_config.h"
15 #include "chrome/browser/browser_process.h" 16 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/history/top_sites.h" 17 #include "chrome/browser/history/top_sites.h"
17 #include "chrome/browser/profiles/profile.h" 18 #include "chrome/browser/profiles/profile.h"
18 #include "chrome/common/thumbnail_score.h" 19 #include "chrome/common/thumbnail_score.h"
19 #include "content/public/browser/browser_thread.h" 20 #include "content/public/browser/browser_thread.h"
20 #include "content/public/browser/notification_details.h" 21 #include "content/public/browser/notification_details.h"
21 #include "content/public/browser/notification_source.h" 22 #include "content/public/browser/notification_source.h"
22 #include "content/public/browser/notification_types.h" 23 #include "content/public/browser/notification_types.h"
23 #include "content/public/browser/render_process_host.h" 24 #include "content/public/browser/render_process_host.h"
24 #include "content/public/browser/render_view_host.h" 25 #include "content/public/browser/render_view_host.h"
25 #include "content/public/browser/render_widget_host_view.h" 26 #include "content/public/browser/render_widget_host_view.h"
26 #include "content/public/browser/web_contents.h" 27 #include "content/public/browser/web_contents.h"
27 #include "googleurl/src/gurl.h" 28 #include "googleurl/src/gurl.h"
28 #include "skia/ext/image_operations.h" 29 #include "skia/ext/image_operations.h"
29 #include "skia/ext/platform_canvas.h" 30 #include "skia/ext/platform_canvas.h"
30 #include "third_party/skia/include/core/SkBitmap.h" 31 #include "third_party/skia/include/core/SkBitmap.h"
31 #include "ui/base/layout.h" 32 #include "ui/base/layout.h"
32 #include "ui/gfx/color_utils.h" 33 #include "ui/gfx/color_utils.h"
33 #include "ui/gfx/rect.h" 34 #include "ui/gfx/rect.h"
35 #include "ui/gfx/screen.h"
34 #include "ui/gfx/scrollbar_size.h" 36 #include "ui/gfx/scrollbar_size.h"
35 #include "ui/gfx/skbitmap_operations.h" 37 #include "ui/gfx/skbitmap_operations.h"
36 38
37 #if defined(OS_WIN) 39 #if defined(OS_WIN)
38 #include "base/win/windows_version.h" 40 #include "base/win/windows_version.h"
41 #include "ui/base/win/dpi.h"
39 #endif 42 #endif
40 43
41 // Overview 44 // Overview
42 // -------- 45 // --------
43 // This class provides current thumbnails for tabs. The simplest operation is 46 // This class provides current thumbnails for tabs. The simplest operation is
44 // when a request for a thumbnail comes in, to grab the backing store and make 47 // when a request for a thumbnail comes in, to grab the backing store and make
45 // a smaller version of that. Clients of the class can send such a request by 48 // a smaller version of that. Clients of the class can send such a request by
46 // AskForSnapshot(). 49 // AskForSnapshot().
47 // 50 //
48 // The class also provides a service for updating thumbnails to be used in 51 // The class also provides a service for updating thumbnails to be used in
49 // "Most visited" section of the new tab page. The service can be started 52 // "Most visited" section of the new tab page. The service can be started
50 // by StartThumbnailing(). The current algorithm of the service is as 53 // by StartThumbnailing(). The current algorithm of the service is as
51 // simple as follows: 54 // simple as follows:
52 // 55 //
53 // When a renderer is about to be hidden (this usually occurs when the 56 // When a renderer is about to be hidden (this usually occurs when the
54 // current tab is closed or another tab is clicked), update the 57 // current tab is closed or another tab is clicked), update the
55 // thumbnail for the tab rendered by the renderer, if needed. The 58 // thumbnail for the tab rendered by the renderer, if needed. The
56 // heuristics to judge whether or not to update the thumbnail is 59 // heuristics to judge whether or not to update the thumbnail is
57 // implemented in ShouldUpdateThumbnail(). 60 // implemented in ShouldUpdateThumbnail().
58 // 61 //
59 // We'll likely revise the algorithm to improve quality of thumbnails this 62 // We'll likely revise the algorithm to improve quality of thumbnails this
60 // service generates. 63 // service generates.
61 64
62 using content::RenderViewHost; 65 using content::RenderViewHost;
63 using content::RenderWidgetHost; 66 using content::RenderWidgetHost;
64 using content::WebContents; 67 using content::WebContents;
65 68
66 namespace { 69 namespace {
67 70
71 // The thumbnail size in DIP.
68 static const int kThumbnailWidth = 212; 72 static const int kThumbnailWidth = 212;
69 static const int kThumbnailHeight = 132; 73 static const int kThumbnailHeight = 132;
70 74
71 // This factor determines the number of pixels to be copied by
72 // RenderWidgetHost::CopyFromBackingStore for generating thumbnail.
73 // Smaller scale is good for performance, but too small scale causes aliasing
74 // because the resampling method is not good enough to retain the image quality.
75 // TODO(mazda): the Improve resampling method and use a smaller scale
76 // (http://crbug.com/118571).
77 static const double kThumbnailCopyScale = 2.0;
78
79 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS"; 75 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS";
80 76
81 // Calculates the size used by RenderWidgetHost::CopyFromBackingStore. 77 // Returns the size used by RenderWidgetHost::CopyFromBackingStore.
82 // The result is computed as the minimum size that satisfies the following 78 //
83 // conditions. 79 // The size is calculated in such a way that the copied size in pixel becomes
84 // result.width : result.height == view_size.width : view_size.height 80 // equal to (f * kThumbnailWidth, f * kThumbnailHeight), where f is the scale
85 // result.width >= kThumbnailCopyScale * desired_size.width 81 // of ui::SCALE_FACTOR_200P. Since RenderWidgetHost::CopyFromBackingStore takes
86 // result.height >= kThumbnailCopyScale * desired_size.height 82 // the size in DIP, we need to adjust the size based on |view|'s device scale
87 gfx::Size GetCopySizeForThumbnail(const gfx::Size& view_size, 83 // factor in order to copy the pixels with the size above.
88 const gfx::Size& desired_size) { 84 //
oshima 2012/08/10 02:01:15 so this wasn't used? Just want to confirm.
mazda 2012/08/17 06:10:51 This function has not been used tentatively since
89 const double scale = kThumbnailCopyScale * 85 // The copied size was chosen for the following reasons.
90 std::max(static_cast<double>(desired_size.width()) / view_size.width(), 86 //
91 static_cast<double>(desired_size.height()) / view_size.height()); 87 // 1. When the scale factor of the primary monitor is ui::SCALE_FACTOR_200P, the
92 return gfx::Size(static_cast<int>(scale * view_size.width()), 88 // generated thumbnail size is (f * kThumbnailWidth, f * kThumbnailHeight).
93 static_cast<int>(scale * view_size.height())); 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 because
99 // the resampling method used in RenderWidgetHost::CopyFromBackingStore is not
100 // good enough for the resampled image to be used directly for the thumbnail
101 // (http://crbug.com/141235). We assume this is not an issue in case of
102 // ui::SCALE_FACTOR_200P because the high resolution thumbnail on high density
103 // display alleviates the aliasing.
104 gfx::Size GetCopySizeForThumbnail(content::RenderWidgetHostView* view) {
105 gfx::Size copy_size(kThumbnailWidth, kThumbnailHeight);
106 ui::ScaleFactor scale_factor =
107 ui::GetScaleFactorForNativeView(view->GetNativeView());
108 switch (scale_factor) {
109 case ui::SCALE_FACTOR_100P:
110 copy_size =
111 copy_size.Scale(ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P));
112 break;
113 case ui::SCALE_FACTOR_200P:
114 // Use the size as-is.
115 break;
116 default:
117 LOG(WARNING) << "Unsupported scale factor. Use the same copy size as "
118 << "ui::SCALE_FACTOR_100P";
119 copy_size =
120 copy_size.Scale(ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P));
121 break;
122 }
123 return copy_size;
124 }
125
126 // Returns the size of the thumbnail stored in the database in pixel.
127 gfx::Size GetThumbnailSizeInPixel() {
128 gfx::Size thumbnail_size(kThumbnailWidth, kThumbnailHeight);
129 // Determine the resolution of the thumbnail based on the primary monitor.
130 // TODO(oshima): Use device's default scale factor.
131 gfx::Display primary_display = gfx::Screen::GetPrimaryDisplay();
132 return thumbnail_size.Scale(primary_display.device_scale_factor());
133 }
134
135 // Returns the scrollbar size in DIP.
136 int GetScrollbarSize() {
137 #if defined(OS_WIN) && !defined(USE_AURA)
138 // On windows gfx::scrollbar_size() returns the size taking into account DPI.
139 return static_cast<int>(std::ceil(gfx::scrollbar_size() / ui::GetDPIScale()));
140 #else
141 // TODO(mazda): Revisit Win Aura case
142 return gfx::scrollbar_size();
143 #endif
144 }
145
146 // Returns the scrollbar size in pixel.
147 int GetScrollbarSizeInPixel(content::RenderWidgetHostView* view) {
148 #if defined(OS_WIN) && !defined(USE_AURA)
149 // On windows gfx::scrollbar_size() returns the size taking into account DPI.
150 return gfx::scrollbar_size();
151 #else
152 // TODO(mazda): Revisit Win Aura case
153 float scale_factor = ui::GetScaleFactorScale(ui::GetScaleFactorForNativeView(
154 view->GetNativeView()));
155 return static_cast<int>(scale_factor * gfx::scrollbar_size());
156 #endif
94 } 157 }
95 158
96 // Returns the clipping rectangle that is used for creating a thumbnail with 159 // Returns the clipping rectangle that is used for creating a thumbnail with
97 // the size of |desired_size| from the bitmap with the size of |source_size|. 160 // the size of |desired_size| from the bitmap with the size of |source_size|.
98 // The type of clipping that needs to be done is assigned to |clip_result|. 161 // The type of clipping that needs to be done is assigned to |clip_result|.
99 gfx::Rect GetClippingRect(const gfx::Size& source_size, 162 gfx::Rect GetClippingRect(const gfx::Size& source_size,
100 const gfx::Size& desired_size, 163 const gfx::Size& desired_size,
101 ThumbnailGenerator::ClipResult* clip_result) { 164 ThumbnailGenerator::ClipResult* clip_result) {
102 DCHECK(clip_result); 165 DCHECK(clip_result);
103 166
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 *clip_result = ThumbnailGenerator::kNotClipped; 198 *clip_result = ThumbnailGenerator::kNotClipped;
136 } 199 }
137 } 200 }
138 return clipping_rect; 201 return clipping_rect;
139 } 202 }
140 203
141 // Creates a downsampled thumbnail from the given bitmap. 204 // Creates a downsampled thumbnail from the given bitmap.
142 // store. The returned bitmap will be isNull if there was an error creating it. 205 // store. The returned bitmap will be isNull if there was an error creating it.
143 SkBitmap CreateThumbnail( 206 SkBitmap CreateThumbnail(
144 const SkBitmap& bitmap, 207 const SkBitmap& bitmap,
145 int desired_width, 208 const gfx::Size& desired_size,
146 int desired_height, 209 int scrollbar_size,
147 ThumbnailGenerator::ClipResult* clip_result) { 210 ThumbnailGenerator::ClipResult* clip_result) {
148 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); 211 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
149 212
150 SkBitmap clipped_bitmap; 213 SkBitmap clipped_bitmap;
151 if (*clip_result == ThumbnailGenerator::kUnprocessed) { 214 if (*clip_result == ThumbnailGenerator::kUnprocessed) {
152 // Clip the pixels that will commonly hold a scrollbar, which looks bad in 215 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
153 // thumbnails. 216 // thumbnails.
154 int scrollbar_size = gfx::scrollbar_size();
155 SkIRect scrollbarless_rect = 217 SkIRect scrollbarless_rect =
156 { 0, 0, 218 { 0, 0,
157 std::max(1, bitmap.width() - scrollbar_size), 219 std::max(1, bitmap.width() - scrollbar_size),
158 std::max(1, bitmap.height() - scrollbar_size) }; 220 std::max(1, bitmap.height() - scrollbar_size) };
159 SkBitmap bmp; 221 SkBitmap bmp;
160 bitmap.extractSubset(&bmp, scrollbarless_rect); 222 bitmap.extractSubset(&bmp, scrollbarless_rect);
161 223
162 clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( 224 clipped_bitmap = ThumbnailGenerator::GetClippedBitmap(
163 bmp, desired_width, desired_height, clip_result); 225 bmp, desired_size.width(), desired_size.height(), clip_result);
164 } else { 226 } else {
165 clipped_bitmap = bitmap; 227 clipped_bitmap = bitmap;
166 } 228 }
167 229
168 // Need to resize it to the size we want, so downsample until it's 230 // Need to resize it to the size we want, so downsample until it's
169 // close, and let the caller make it the exact size if desired. 231 // close, and let the caller make it the exact size if desired.
170 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize( 232 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize(
171 clipped_bitmap, desired_width, desired_height); 233 clipped_bitmap, desired_size.width(), desired_size.height());
172 #if !defined(USE_AURA) 234 #if !defined(USE_AURA)
173 // This is a bit subtle. SkBitmaps are refcounted, but the magic 235 // This is a bit subtle. SkBitmaps are refcounted, but the magic
174 // ones in PlatformCanvas can't be assigned to SkBitmap with proper 236 // ones in PlatformCanvas can't be assigned to SkBitmap with proper
175 // refcounting. If the bitmap doesn't change, then the downsampler 237 // refcounting. If the bitmap doesn't change, then the downsampler
176 // will return the input bitmap, which will be the reference to the 238 // will return the input bitmap, which will be the reference to the
177 // weird PlatformCanvas one insetad of a regular one. To get a 239 // weird PlatformCanvas one insetad of a regular one. To get a
178 // regular refcounted bitmap, we need to copy it. 240 // regular refcounted bitmap, we need to copy it.
179 // 241 //
180 // On Aura, the PlatformCanvas is platform-independent and does not have 242 // On Aura, the PlatformCanvas is platform-independent and does not have
181 // any native platform resources that can't be refounted, so this issue does 243 // any native platform resources that can't be refounted, so this issue does
(...skipping 328 matching lines...) Expand 10 before | Expand all | Expand 10 after
510 view_size, 572 view_size,
511 view_size); 573 view_size);
512 } 574 }
513 #endif 575 #endif
514 return; 576 return;
515 } 577 }
516 578
517 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size()); 579 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
518 // Clip the pixels that will commonly hold a scrollbar, which looks bad in 580 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
519 // thumbnails. 581 // thumbnails.
520 int scrollbar_size = gfx::scrollbar_size(); 582 int scrollbar_size = GetScrollbarSize();
521 copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size); 583 copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size);
522 ClipResult clip_result = ThumbnailGenerator::kUnprocessed; 584 ClipResult clip_result = ThumbnailGenerator::kUnprocessed;
523 copy_rect = GetClippingRect(copy_rect.size(), 585 copy_rect = GetClippingRect(copy_rect.size(),
524 gfx::Size(kThumbnailWidth, kThumbnailHeight), 586 gfx::Size(kThumbnailWidth, kThumbnailHeight),
525 &clip_result); 587 &clip_result);
526 gfx::Size copy_size = 588 gfx::Size copy_size = GetCopySizeForThumbnail(view);
527 gfx::Size(kThumbnailWidth, kThumbnailHeight).Scale(kThumbnailCopyScale);
528 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas; 589 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas;
529 render_widget_host->CopyFromBackingStore( 590 render_widget_host->CopyFromBackingStore(
530 copy_rect, 591 copy_rect,
531 copy_size, 592 copy_size,
532 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas, 593 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas,
533 weak_factory_.GetWeakPtr(), 594 weak_factory_.GetWeakPtr(),
534 web_contents, 595 web_contents,
535 clip_result, 596 clip_result,
536 base::Owned(temp_canvas)), 597 base::Owned(temp_canvas)),
537 temp_canvas); 598 temp_canvas);
538 } 599 }
539 600
540 void ThumbnailGenerator::UpdateThumbnailWithBitmap( 601 void ThumbnailGenerator::UpdateThumbnailWithBitmap(
541 WebContents* web_contents, 602 WebContents* web_contents,
542 ClipResult clip_result, 603 ClipResult clip_result,
543 const SkBitmap& bitmap) { 604 const SkBitmap& bitmap) {
544 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 605 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
545 if (bitmap.isNull() || bitmap.empty()) 606 if (bitmap.isNull() || bitmap.empty())
546 return; 607 return;
547 608
548 SkBitmap thumbnail = CreateThumbnail(bitmap, 609 SkBitmap thumbnail = CreateThumbnail(
549 kThumbnailWidth, 610 bitmap,
550 kThumbnailHeight, 611 GetThumbnailSizeInPixel(),
551 &clip_result); 612 GetScrollbarSizeInPixel(web_contents->GetRenderViewHost()->GetView()),
613 &clip_result);
552 UpdateThumbnail(web_contents, thumbnail, clip_result); 614 UpdateThumbnail(web_contents, thumbnail, clip_result);
553 } 615 }
554 616
555 void ThumbnailGenerator::UpdateThumbnailWithCanvas( 617 void ThumbnailGenerator::UpdateThumbnailWithCanvas(
556 WebContents* web_contents, 618 WebContents* web_contents,
557 ClipResult clip_result, 619 ClipResult clip_result,
558 skia::PlatformCanvas* temp_canvas, 620 skia::PlatformCanvas* temp_canvas,
559 bool succeeded) { 621 bool succeeded) {
560 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 622 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
561 if (!succeeded) 623 if (!succeeded)
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 void ThumbnailGenerator::DidStartLoading( 659 void ThumbnailGenerator::DidStartLoading(
598 content::RenderViewHost* render_view_host) { 660 content::RenderViewHost* render_view_host) {
599 load_interrupted_ = false; 661 load_interrupted_ = false;
600 } 662 }
601 663
602 void ThumbnailGenerator::StopNavigation() { 664 void ThumbnailGenerator::StopNavigation() {
603 // This function gets called when the page loading is interrupted by the 665 // This function gets called when the page loading is interrupted by the
604 // stop button. 666 // stop button.
605 load_interrupted_ = true; 667 load_interrupted_ = true;
606 } 668 }
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698