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

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: 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 <map> 8 #include <map>
9 9
10 #include "base/bind.h" 10 #include "base/bind.h"
(...skipping 13 matching lines...) Expand all
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/base/layout.h" 31 #include "ui/base/layout.h"
32 #include "ui/gfx/color_utils.h" 32 #include "ui/gfx/color_utils.h"
33 #include "ui/gfx/rect.h" 33 #include "ui/gfx/rect.h"
34 #include "ui/gfx/screen.h"
34 #include "ui/gfx/scrollbar_size.h" 35 #include "ui/gfx/scrollbar_size.h"
35 #include "ui/gfx/skbitmap_operations.h" 36 #include "ui/gfx/skbitmap_operations.h"
36 37
37 #if defined(OS_WIN) 38 #if defined(OS_WIN)
38 #include "base/win/windows_version.h" 39 #include "base/win/windows_version.h"
39 #endif 40 #endif
40 41
41 // Overview 42 // Overview
42 // -------- 43 // --------
43 // This class provides current thumbnails for tabs. The simplest operation is 44 // This class provides current thumbnails for tabs. The simplest operation is
(...skipping 14 matching lines...) Expand all
58 // 59 //
59 // We'll likely revise the algorithm to improve quality of thumbnails this 60 // We'll likely revise the algorithm to improve quality of thumbnails this
60 // service generates. 61 // service generates.
61 62
62 using content::RenderViewHost; 63 using content::RenderViewHost;
63 using content::RenderWidgetHost; 64 using content::RenderWidgetHost;
64 using content::WebContents; 65 using content::WebContents;
65 66
66 namespace { 67 namespace {
67 68
69 // The thumbnail size in DIP.
68 static const int kThumbnailWidth = 212; 70 static const int kThumbnailWidth = 212;
69 static const int kThumbnailHeight = 132; 71 static const int kThumbnailHeight = 132;
70 72
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"; 73 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS";
80 74
81 // Calculates the size used by RenderWidgetHost::CopyFromBackingStore. 75 // Returns the size used by RenderWidgetHost::CopyFromBackingStore.
82 // The result is computed as the minimum size that satisfies the following 76 //
83 // conditions. 77 // 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 78 // equal to (f * kThumbnailWidth, f * kThumbnailHeight), where f is the scale
85 // result.width >= kThumbnailCopyScale * desired_size.width 79 // of ui::SCALE_FACTOR_200P. Since RenderWidgetHost::CopyFromBackingStore takes
86 // result.height >= kThumbnailCopyScale * desired_size.height 80 // 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, 81 // factor in order to copy the pixels with the size above.
88 const gfx::Size& desired_size) { 82 //
89 const double scale = kThumbnailCopyScale * 83 // The copied size was chosen for the following reasons.
90 std::max(static_cast<double>(desired_size.width()) / view_size.width(), 84 //
91 static_cast<double>(desired_size.height()) / view_size.height()); 85 // 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()), 86 // generated thumbnail size is (f * kThumbnailWidth, f * kThumbnailHeight).
93 static_cast<int>(scale * view_size.height())); 87 // In order to avoid degrading the image quality by magnification, the size
88 // of the copied pixels should be equal to or larger than this thumbnail size.
89 //
90 // 2. RenderWidgetHost::CopyFromBackingStore can be costly especially when
91 // it is necessary to read back the web contents image data from GPU. As the
92 // cost is roughly propotional to the number of the copied pixels, the size of
93 // the copied pixels should be as small as possible.
94 //
95 // When the scale factor of the primary monitor is ui::SCALE_FACTOR_100P,
96 // we still copy the pixels with the same size as ui::SCALE_FACTOR_200P because
97 // the resampling method used in RenderWidgetHost::CopyFromBackingStore is not
98 // good enough for the resampled image to be used directly for the thumbnail
99 // (http://crbug.com/141235). We assume this is not an issue in case of
100 // ui::SCALE_FACTOR_200P because the high resolution thumbnail on high density
101 // display alleviates the aliasing.
brettw 2012/08/19 23:36:55 One thing that's not clear to me: In the case of a
mazda 2012/08/20 16:04:26 Yes, that a hack around the "scaling is poor" bug.
102 gfx::Size GetCopySizeForThumbnail(content::RenderWidgetHostView* view) {
103 gfx::Size copy_size(kThumbnailWidth, kThumbnailHeight);
104 ui::ScaleFactor scale_factor =
105 ui::GetScaleFactorForNativeView(view->GetNativeView());
106 switch (scale_factor) {
107 case ui::SCALE_FACTOR_100P:
108 copy_size =
109 copy_size.Scale(ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P));
110 break;
111 case ui::SCALE_FACTOR_200P:
112 // Use the size as-is.
113 break;
114 default:
115 LOG(WARNING) << "Unsupported scale factor. Use the same copy size as "
brettw 2012/08/19 23:36:55 Can you make this a DLOG to avoid shipping release
mazda 2012/08/20 16:04:26 Done.
116 << "ui::SCALE_FACTOR_100P";
117 copy_size =
118 copy_size.Scale(ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P));
119 break;
120 }
121 return copy_size;
122 }
123
124 // Returns the size of the thumbnail stored in the database in pixel.
125 gfx::Size GetThumbnailSizeInPixel() {
126 gfx::Size thumbnail_size(kThumbnailWidth, kThumbnailHeight);
127 // Determine the resolution of the thumbnail based on the primary monitor.
128 // TODO(oshima): Use device's default scale factor.
129 gfx::Display primary_display = gfx::Screen::GetPrimaryDisplay();
130 return thumbnail_size.Scale(primary_display.device_scale_factor());
94 } 131 }
95 132
96 // Returns the clipping rectangle that is used for creating a thumbnail with 133 // 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|. 134 // 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|. 135 // The type of clipping that needs to be done is assigned to |clip_result|.
99 gfx::Rect GetClippingRect(const gfx::Size& source_size, 136 gfx::Rect GetClippingRect(const gfx::Size& source_size,
100 const gfx::Size& desired_size, 137 const gfx::Size& desired_size,
101 ThumbnailGenerator::ClipResult* clip_result) { 138 ThumbnailGenerator::ClipResult* clip_result) {
102 DCHECK(clip_result); 139 DCHECK(clip_result);
103 140
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 *clip_result = ThumbnailGenerator::kNotClipped; 172 *clip_result = ThumbnailGenerator::kNotClipped;
136 } 173 }
137 } 174 }
138 return clipping_rect; 175 return clipping_rect;
139 } 176 }
140 177
141 // Creates a downsampled thumbnail from the given bitmap. 178 // Creates a downsampled thumbnail from the given bitmap.
142 // store. The returned bitmap will be isNull if there was an error creating it. 179 // store. The returned bitmap will be isNull if there was an error creating it.
143 SkBitmap CreateThumbnail( 180 SkBitmap CreateThumbnail(
144 const SkBitmap& bitmap, 181 const SkBitmap& bitmap,
145 int desired_width, 182 const gfx::Size& desired_size,
146 int desired_height,
147 ThumbnailGenerator::ClipResult* clip_result) { 183 ThumbnailGenerator::ClipResult* clip_result) {
148 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); 184 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
149 185
150 SkBitmap clipped_bitmap; 186 SkBitmap clipped_bitmap;
151 if (*clip_result == ThumbnailGenerator::kUnprocessed) { 187 if (*clip_result == ThumbnailGenerator::kUnprocessed) {
152 // Clip the pixels that will commonly hold a scrollbar, which looks bad in 188 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
153 // thumbnails. 189 // thumbnails.
154 int scrollbar_size = gfx::scrollbar_size(); 190 int scrollbar_size = gfx::scrollbar_size();
155 SkIRect scrollbarless_rect = 191 SkIRect scrollbarless_rect =
156 { 0, 0, 192 { 0, 0,
157 std::max(1, bitmap.width() - scrollbar_size), 193 std::max(1, bitmap.width() - scrollbar_size),
158 std::max(1, bitmap.height() - scrollbar_size) }; 194 std::max(1, bitmap.height() - scrollbar_size) };
159 SkBitmap bmp; 195 SkBitmap bmp;
160 bitmap.extractSubset(&bmp, scrollbarless_rect); 196 bitmap.extractSubset(&bmp, scrollbarless_rect);
161 197
162 clipped_bitmap = ThumbnailGenerator::GetClippedBitmap( 198 clipped_bitmap = ThumbnailGenerator::GetClippedBitmap(
163 bmp, desired_width, desired_height, clip_result); 199 bmp, desired_size.width(), desired_size.height(), clip_result);
164 } else { 200 } else {
165 clipped_bitmap = bitmap; 201 clipped_bitmap = bitmap;
166 } 202 }
167 203
168 // Need to resize it to the size we want, so downsample until it's 204 // 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. 205 // close, and let the caller make it the exact size if desired.
170 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize( 206 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize(
171 clipped_bitmap, desired_width, desired_height); 207 clipped_bitmap, desired_size.width(), desired_size.height());
172 #if !defined(USE_AURA) 208 #if !defined(USE_AURA)
173 // This is a bit subtle. SkBitmaps are refcounted, but the magic 209 // This is a bit subtle. SkBitmaps are refcounted, but the magic
174 // ones in PlatformCanvas can't be assigned to SkBitmap with proper 210 // ones in PlatformCanvas can't be assigned to SkBitmap with proper
175 // refcounting. If the bitmap doesn't change, then the downsampler 211 // refcounting. If the bitmap doesn't change, then the downsampler
176 // will return the input bitmap, which will be the reference to the 212 // will return the input bitmap, which will be the reference to the
177 // weird PlatformCanvas one insetad of a regular one. To get a 213 // weird PlatformCanvas one insetad of a regular one. To get a
178 // regular refcounted bitmap, we need to copy it. 214 // regular refcounted bitmap, we need to copy it.
179 // 215 //
180 // On Aura, the PlatformCanvas is platform-independent and does not have 216 // 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 217 // any native platform resources that can't be refounted, so this issue does
(...skipping 334 matching lines...) Expand 10 before | Expand all | Expand 10 after
516 552
517 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size()); 553 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
518 // Clip the pixels that will commonly hold a scrollbar, which looks bad in 554 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
519 // thumbnails. 555 // thumbnails.
520 int scrollbar_size = gfx::scrollbar_size(); 556 int scrollbar_size = gfx::scrollbar_size();
521 copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size); 557 copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size);
522 ClipResult clip_result = ThumbnailGenerator::kUnprocessed; 558 ClipResult clip_result = ThumbnailGenerator::kUnprocessed;
523 copy_rect = GetClippingRect(copy_rect.size(), 559 copy_rect = GetClippingRect(copy_rect.size(),
524 gfx::Size(kThumbnailWidth, kThumbnailHeight), 560 gfx::Size(kThumbnailWidth, kThumbnailHeight),
525 &clip_result); 561 &clip_result);
526 gfx::Size copy_size = 562 gfx::Size copy_size = GetCopySizeForThumbnail(view);
527 gfx::Size(kThumbnailWidth, kThumbnailHeight).Scale(kThumbnailCopyScale);
528 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas; 563 skia::PlatformCanvas* temp_canvas = new skia::PlatformCanvas;
529 render_widget_host->CopyFromBackingStore( 564 render_widget_host->CopyFromBackingStore(
530 copy_rect, 565 copy_rect,
531 copy_size, 566 copy_size,
532 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas, 567 base::Bind(&ThumbnailGenerator::UpdateThumbnailWithCanvas,
533 weak_factory_.GetWeakPtr(), 568 weak_factory_.GetWeakPtr(),
534 web_contents, 569 web_contents,
535 clip_result, 570 clip_result,
536 base::Owned(temp_canvas)), 571 base::Owned(temp_canvas)),
537 temp_canvas); 572 temp_canvas);
538 } 573 }
539 574
540 void ThumbnailGenerator::UpdateThumbnailWithBitmap( 575 void ThumbnailGenerator::UpdateThumbnailWithBitmap(
541 WebContents* web_contents, 576 WebContents* web_contents,
542 ClipResult clip_result, 577 ClipResult clip_result,
543 const SkBitmap& bitmap) { 578 const SkBitmap& bitmap) {
544 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 579 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
545 if (bitmap.isNull() || bitmap.empty()) 580 if (bitmap.isNull() || bitmap.empty())
546 return; 581 return;
547 582
548 SkBitmap thumbnail = CreateThumbnail(bitmap, 583 SkBitmap thumbnail = CreateThumbnail(bitmap,
549 kThumbnailWidth, 584 GetThumbnailSizeInPixel(),
550 kThumbnailHeight,
551 &clip_result); 585 &clip_result);
552 UpdateThumbnail(web_contents, thumbnail, clip_result); 586 UpdateThumbnail(web_contents, thumbnail, clip_result);
553 } 587 }
554 588
555 void ThumbnailGenerator::UpdateThumbnailWithCanvas( 589 void ThumbnailGenerator::UpdateThumbnailWithCanvas(
556 WebContents* web_contents, 590 WebContents* web_contents,
557 ClipResult clip_result, 591 ClipResult clip_result,
558 skia::PlatformCanvas* temp_canvas, 592 skia::PlatformCanvas* temp_canvas,
559 bool succeeded) { 593 bool succeeded) {
560 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); 594 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
597 void ThumbnailGenerator::DidStartLoading( 631 void ThumbnailGenerator::DidStartLoading(
598 content::RenderViewHost* render_view_host) { 632 content::RenderViewHost* render_view_host) {
599 load_interrupted_ = false; 633 load_interrupted_ = false;
600 } 634 }
601 635
602 void ThumbnailGenerator::StopNavigation() { 636 void ThumbnailGenerator::StopNavigation() {
603 // This function gets called when the page loading is interrupted by the 637 // This function gets called when the page loading is interrupted by the
604 // stop button. 638 // stop button.
605 load_interrupted_ = true; 639 load_interrupted_ = true;
606 } 640 }
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