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

Side by Side 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: 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 unified diff | Download patch | Annotate | Revision Log
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/thumbnails/thumbnail_tab_helper.h" 5 #include "chrome/browser/thumbnails/thumbnail_tab_helper.h"
6 6
7 #include "base/metrics/histogram.h"
8 #include "chrome/browser/browser_process.h" 7 #include "chrome/browser/browser_process.h"
9 #include "chrome/browser/profiles/profile.h" 8 #include "chrome/browser/profiles/profile.h"
10 #include "chrome/browser/thumbnails/render_widget_snapshot_taker.h" 9 #include "chrome/browser/thumbnails/render_widget_snapshot_taker.h"
11 #include "chrome/browser/thumbnails/thumbnail_service.h" 10 #include "chrome/browser/thumbnails/thumbnail_service.h"
12 #include "chrome/browser/thumbnails/thumbnail_service_factory.h" 11 #include "chrome/browser/thumbnails/thumbnail_service_factory.h"
12 #include "chrome/browser/thumbnails/thumbnailing_algorithm.h"
13 #include "chrome/browser/thumbnails/thumbnailing_context.h"
13 #include "content/public/browser/notification_details.h" 14 #include "content/public/browser/notification_details.h"
14 #include "content/public/browser/notification_source.h" 15 #include "content/public/browser/notification_source.h"
15 #include "content/public/browser/notification_types.h" 16 #include "content/public/browser/notification_types.h"
16 #include "content/public/browser/render_view_host.h" 17 #include "content/public/browser/render_view_host.h"
17 #include "content/public/browser/render_widget_host_view.h" 18 #include "content/public/browser/render_widget_host_view.h"
18 #include "skia/ext/platform_canvas.h" 19 #include "skia/ext/platform_canvas.h"
19 #include "ui/gfx/color_utils.h" 20 #include "ui/gfx/color_utils.h"
20 #include "ui/gfx/size_conversions.h" 21 #include "ui/gfx/size_conversions.h"
21 #include "ui/gfx/screen.h" 22 #include "ui/gfx/screen.h"
22 #include "ui/gfx/scrollbar_size.h" 23 #include "ui/gfx/scrollbar_size.h"
(...skipping 15 matching lines...) Expand all
38 // When a renderer is about to be hidden (this usually occurs when the 39 // When a renderer is about to be hidden (this usually occurs when the
39 // current tab is closed or another tab is clicked), update the 40 // current tab is closed or another tab is clicked), update the
40 // thumbnail for the tab rendered by the renderer, if needed. The 41 // thumbnail for the tab rendered by the renderer, if needed. The
41 // heuristics to judge whether or not to update the thumbnail is 42 // heuristics to judge whether or not to update the thumbnail is
42 // implemented in ShouldUpdateThumbnail(). 43 // implemented in ShouldUpdateThumbnail().
43 44
44 using content::RenderViewHost; 45 using content::RenderViewHost;
45 using content::RenderWidgetHost; 46 using content::RenderWidgetHost;
46 using content::WebContents; 47 using content::WebContents;
47 48
49 using thumbnails::ClipResult;
50 using thumbnails::ThumbnailingContext;
51 using thumbnails::ThumbnailingAlgorithm;
52
48 namespace { 53 namespace {
49 54
50 // The thumbnail size in DIP. 55 // Feed the constructed thumbnail to the thumbnail service.
51 static const int kThumbnailWidth = 212; 56 void UpdateThumbnail(ThumbnailingContext* context,
sky 2013/01/17 20:18:36 Can this take a const ThumbnailContext&
motek. 2013/01/18 18:38:41 Sure it can. Changed as suggested.
52 static const int kThumbnailHeight = 132; 57 const SkBitmap& thumbnail) {
58 Profile* profile =
59 Profile::FromBrowserContext(context->browser_context);
60 scoped_refptr<thumbnails::ThumbnailService> thumbnail_service =
61 ThumbnailServiceFactory::GetForProfile(profile);
53 62
54 static const char kThumbnailHistogramName[] = "Thumbnail.ComputeMS"; 63 if (!thumbnail_service)
64 return;
55 65
56 // Returns the size used by RenderWidgetHost::CopyFromBackingStore. 66 gfx::Image image(thumbnail);
57 // 67 thumbnail_service->SetPageThumbnail(*context, image);
58 // The size is calculated in such a way that the copied size in pixel becomes 68 VLOG(1) << "Thumbnail taken for " << context->url << ": "
59 // equal to (f * kThumbnailWidth, f * kThumbnailHeight), where f is the scale 69 << context->score.ToString();
60 // of ui::SCALE_FACTOR_200P. Since RenderWidgetHost::CopyFromBackingStore takes
61 // the size in DIP, we need to adjust the size based on |view|'s device scale
62 // factor in order to copy the pixels with the size above.
63 //
64 // The copied size was chosen for the following reasons.
65 //
66 // 1. When the scale factor of the primary monitor is ui::SCALE_FACTOR_200P, the
67 // generated thumbnail size is (f * kThumbnailWidth, f * kThumbnailHeight).
68 // In order to avoid degrading the image quality by magnification, the size
69 // of the copied pixels should be equal to or larger than this thumbnail size.
70 //
71 // 2. RenderWidgetHost::CopyFromBackingStore can be costly especially when
72 // it is necessary to read back the web contents image data from GPU. As the
73 // cost is roughly propotional to the number of the copied pixels, the size of
74 // the copied pixels should be as small as possible.
75 //
76 // When the scale factor of the primary monitor is ui::SCALE_FACTOR_100P,
77 // we still copy the pixels with the same size as ui::SCALE_FACTOR_200P because
78 // the resampling method used in RenderWidgetHost::CopyFromBackingStore is not
79 // good enough for the resampled image to be used directly for the thumbnail
80 // (http://crbug.com/141235). We assume this is not an issue in case of
81 // ui::SCALE_FACTOR_200P because the high resolution thumbnail on high density
82 // display alleviates the aliasing.
83 // TODO(mazda): Copy the pixels with the smaller size in the case of
84 // ui::SCALE_FACTOR_100P once the resampling method has been improved.
85 gfx::Size GetCopySizeForThumbnail(content::RenderWidgetHostView* view) {
86 gfx::Size copy_size(kThumbnailWidth, kThumbnailHeight);
87 ui::ScaleFactor scale_factor =
88 ui::GetScaleFactorForNativeView(view->GetNativeView());
89 switch (scale_factor) {
90 case ui::SCALE_FACTOR_100P:
91 copy_size = gfx::ToFlooredSize(gfx::ScaleSize(
92 copy_size, ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P)));
93 break;
94 case ui::SCALE_FACTOR_200P:
95 // Use the size as-is.
96 break;
97 default:
98 DLOG(WARNING) << "Unsupported scale factor. Use the same copy size as "
99 << "ui::SCALE_FACTOR_100P";
100 copy_size = gfx::ToFlooredSize(gfx::ScaleSize(
101 copy_size, ui::GetScaleFactorScale(ui::SCALE_FACTOR_200P)));
102 break;
103 }
104 return copy_size;
105 } 70 }
106 71
107 // Returns the size of the thumbnail stored in the database in pixel. 72 void ProcessCanvas(ThumbnailingContext* context,
108 gfx::Size GetThumbnailSizeInPixel() { 73 ThumbnailingAlgorithm* algorithm,
109 gfx::Size thumbnail_size(kThumbnailWidth, kThumbnailHeight); 74 skia::PlatformBitmap* temp_bitmap,
110 // Determine the resolution of the thumbnail based on the maximum scale 75 bool succeeded) {
111 // factor. 76 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
112 // TODO(mazda|oshima): Update thumbnail when the max scale factor changes. 77 if (!succeeded)
113 // crbug.com/159157. 78 return;
114 float max_scale_factor = 79
115 ui::GetScaleFactorScale(ui::GetMaxScaleFactor()); 80 SkBitmap bitmap = temp_bitmap->GetBitmap();
116 return gfx::ToFlooredSize(gfx::ScaleSize(thumbnail_size, max_scale_factor)); 81 algorithm->ProcessBitmap(context, bitmap, base::Bind(&UpdateThumbnail));
117 } 82 }
118 83
119 // Returns the clipping rectangle that is used for creating a thumbnail with 84 void AsyncProcessThumbnail(content::WebContents* web_contents,
120 // the size of |desired_size| from the bitmap with the size of |source_size|. 85 scoped_refptr<ThumbnailingContext> context,
121 // The type of clipping that needs to be done is assigned to |clip_result|. 86 scoped_refptr<ThumbnailingAlgorithm> algorithm) {
122 gfx::Rect GetClippingRect(const gfx::Size& source_size, 87 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
123 const gfx::Size& desired_size, 88 RenderWidgetHost* render_widget_host = web_contents->GetRenderViewHost();
124 ThumbnailTabHelper::ClipResult* clip_result) { 89 content::RenderWidgetHostView* view = render_widget_host->GetView();
125 DCHECK(clip_result); 90 if (!view)
126 91 return;
127 float desired_aspect = 92 if (!view->IsSurfaceAvailableForCopy()) {
128 static_cast<float>(desired_size.width()) / desired_size.height(); 93 #if defined(OS_WIN)
129 94 // On Windows XP, neither the backing store nor the compositing surface is
130 // Get the clipping rect so that we can preserve the aspect ratio while 95 // available in the browser when accelerated compositing is active, so ask
131 // filling the destination. 96 // the renderer to send a snapshot for creating the thumbnail.
132 gfx::Rect clipping_rect; 97 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
133 if (source_size.width() < desired_size.width() || 98 gfx::Size view_size =
134 source_size.height() < desired_size.height()) { 99 render_widget_host->GetView()->GetViewBounds().size();
135 // Source image is smaller: we clip the part of source image within the 100 g_browser_process->GetRenderWidgetSnapshotTaker()->AskForSnapshot(
136 // dest rect, and then stretch it to fill the dest rect. We don't respect 101 render_widget_host,
137 // the aspect ratio in this case. 102 base::Bind(&ThumbnailingAlgorithm::ProcessBitmap,
138 clipping_rect = gfx::Rect(desired_size); 103 algorithm, context, base::Bind(&UpdateThumbnail)),
139 *clip_result = ThumbnailTabHelper::kSourceIsSmaller; 104 view_size,
140 } else { 105 view_size);
141 float src_aspect =
142 static_cast<float>(source_size.width()) / source_size.height();
143 if (src_aspect > desired_aspect) {
144 // Wider than tall, clip horizontally: we center the smaller
145 // thumbnail in the wider screen.
146 int new_width = static_cast<int>(source_size.height() * desired_aspect);
147 int x_offset = (source_size.width() - new_width) / 2;
148 clipping_rect.SetRect(x_offset, 0, new_width, source_size.height());
149 *clip_result = (src_aspect >= ThumbnailScore::kTooWideAspectRatio) ?
150 ThumbnailTabHelper::kTooWiderThanTall :
151 ThumbnailTabHelper::kWiderThanTall;
152 } else if (src_aspect < desired_aspect) {
153 clipping_rect =
154 gfx::Rect(source_size.width(), source_size.width() / desired_aspect);
155 *clip_result = ThumbnailTabHelper::kTallerThanWide;
156 } else {
157 clipping_rect = gfx::Rect(source_size);
158 *clip_result = ThumbnailTabHelper::kNotClipped;
159 } 106 }
160 } 107 #endif
161 return clipping_rect; 108 return;
162 }
163
164 // Creates a downsampled thumbnail from the given bitmap.
165 // store. The returned bitmap will be isNull if there was an error creating it.
166 SkBitmap CreateThumbnail(
167 const SkBitmap& bitmap,
168 const gfx::Size& desired_size,
169 ThumbnailTabHelper::ClipResult* clip_result) {
170 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
171
172 SkBitmap clipped_bitmap;
173 if (*clip_result == ThumbnailTabHelper::kUnprocessed) {
174 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
175 // thumbnails.
176 int scrollbar_size = gfx::scrollbar_size();
177 SkIRect scrollbarless_rect =
178 { 0, 0,
179 std::max(1, bitmap.width() - scrollbar_size),
180 std::max(1, bitmap.height() - scrollbar_size) };
181 SkBitmap bmp;
182 bitmap.extractSubset(&bmp, scrollbarless_rect);
183
184 clipped_bitmap = ThumbnailTabHelper::GetClippedBitmap(
185 bmp, desired_size.width(), desired_size.height(), clip_result);
186 } else {
187 clipped_bitmap = bitmap;
188 } 109 }
189 110
190 // Need to resize it to the size we want, so downsample until it's 111 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
191 // close, and let the caller make it the exact size if desired. 112 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
192 SkBitmap result = SkBitmapOperations::DownsampleByTwoUntilSize( 113 // thumbnails.
193 clipped_bitmap, desired_size.width(), desired_size.height()); 114 int scrollbar_size = gfx::scrollbar_size();
194 #if !defined(USE_AURA) 115 gfx::Size copy_size;
195 // This is a bit subtle. SkBitmaps are refcounted, but the magic 116 copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size);
196 // ones in PlatformCanvas can't be assigned to SkBitmap with proper
197 // refcounting. If the bitmap doesn't change, then the downsampler
198 // will return the input bitmap, which will be the reference to the
199 // weird PlatformCanvas one insetad of a regular one. To get a
200 // regular refcounted bitmap, we need to copy it.
201 //
202 // On Aura, the PlatformCanvas is platform-independent and does not have
203 // any native platform resources that can't be refounted, so this issue does
204 // not occur.
205 //
206 // Note that GetClippedBitmap() does extractSubset() but it won't copy
207 // the pixels, hence we check result size == clipped_bitmap size here.
208 if (clipped_bitmap.width() == result.width() &&
209 clipped_bitmap.height() == result.height())
210 clipped_bitmap.copyTo(&result, SkBitmap::kARGB_8888_Config);
211 #endif
212 117
213 HISTOGRAM_TIMES(kThumbnailHistogramName, 118 context->clip_result = algorithm->GetCanvasCopyInfo(
214 base::TimeTicks::Now() - begin_compute_thumbnail); 119 copy_rect.size(),
215 return result; 120 ui::GetScaleFactorForNativeView(view->GetNativeView()),
121 &copy_rect,
122 &copy_size);
123
124 skia::PlatformBitmap* temp_bitmap = new skia::PlatformBitmap;
125 render_widget_host->CopyFromBackingStore(
126 copy_rect,
127 copy_size,
128 base::Bind(&ProcessCanvas, context, algorithm, base::Owned(temp_bitmap)),
129 temp_bitmap);
216 } 130 }
217 131
218 } // namespace 132 } // namespace
219 133
220 ThumbnailTabHelper::ThumbnailingContext::ThumbnailingContext(
221 content::WebContents* web_contents,
222 bool load_interrupted)
223 : browser_context(web_contents->GetBrowserContext()),
224 url(web_contents->GetURL()),
225 clip_result(kUnprocessed) {
226 score.at_top =
227 (web_contents->GetRenderViewHost()->GetLastScrollOffset().y() == 0);
228 score.load_completed = !web_contents->IsLoading() && !load_interrupted;
229 }
230
231 ThumbnailTabHelper::ThumbnailingContext::~ThumbnailingContext() {
232 }
233
234 ThumbnailTabHelper::ThumbnailTabHelper(content::WebContents* contents) 134 ThumbnailTabHelper::ThumbnailTabHelper(content::WebContents* contents)
235 : content::WebContentsObserver(contents), 135 : content::WebContentsObserver(contents),
236 enabled_(true), 136 enabled_(true),
237 load_interrupted_(false) { 137 load_interrupted_(false) {
238 // Even though we deal in RenderWidgetHosts, we only care about its 138 // Even though we deal in RenderWidgetHosts, we only care about its
239 // subclass, RenderViewHost when it is in a tab. We don't make thumbnails 139 // subclass, RenderViewHost when it is in a tab. We don't make thumbnails
240 // for RenderViewHosts that aren't in tabs, or RenderWidgetHosts that 140 // for RenderViewHosts that aren't in tabs, or RenderWidgetHosts that
241 // aren't views like select popups. 141 // aren't views like select popups.
242 registrar_.Add(this, 142 registrar_.Add(this,
243 content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED, 143 content::NOTIFICATION_WEB_CONTENTS_RENDER_VIEW_HOST_CREATED,
(...skipping 59 matching lines...) Expand 10 before | Expand all | Expand 10 after
303 registrar_.Remove( 203 registrar_.Remove(
304 this, 204 this,
305 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED, 205 content::NOTIFICATION_RENDER_WIDGET_VISIBILITY_CHANGED,
306 content::Source<RenderWidgetHost>(renderer)); 206 content::Source<RenderWidgetHost>(renderer));
307 registrar_.Remove( 207 registrar_.Remove(
308 this, 208 this,
309 content::NOTIFICATION_RENDER_VIEW_HOST_DELETED, 209 content::NOTIFICATION_RENDER_VIEW_HOST_DELETED,
310 content::Source<RenderViewHost>(renderer)); 210 content::Source<RenderViewHost>(renderer));
311 } 211 }
312 212
313 double ThumbnailTabHelper::CalculateBoringScore(const SkBitmap& bitmap) {
314 if (bitmap.isNull() || bitmap.empty())
315 return 1.0;
316 int histogram[256] = {0};
317 color_utils::BuildLumaHistogram(bitmap, histogram);
318
319 int color_count = *std::max_element(histogram, histogram + 256);
320 int pixel_count = bitmap.width() * bitmap.height();
321 return static_cast<double>(color_count) / pixel_count;
322 }
323
324 SkBitmap ThumbnailTabHelper::GetClippedBitmap(const SkBitmap& bitmap,
325 int desired_width,
326 int desired_height,
327 ClipResult* clip_result) {
328 gfx::Rect clipping_rect =
329 GetClippingRect(gfx::Size(bitmap.width(), bitmap.height()),
330 gfx::Size(desired_width, desired_height),
331 clip_result);
332 SkIRect src_rect = { clipping_rect.x(), clipping_rect.y(),
333 clipping_rect.right(), clipping_rect.bottom() };
334 SkBitmap clipped_bitmap;
335 bitmap.extractSubset(&clipped_bitmap, src_rect);
336 return clipped_bitmap;
337 }
338
339 void ThumbnailTabHelper::UpdateThumbnailIfNecessary( 213 void ThumbnailTabHelper::UpdateThumbnailIfNecessary(
340 WebContents* web_contents) { 214 WebContents* web_contents) {
341 // Destroying a WebContents may trigger it to be hidden, prompting a snapshot 215 // Destroying a WebContents may trigger it to be hidden, prompting a snapshot
342 // which would be unwise to attempt <http://crbug.com/130097>. If the 216 // which would be unwise to attempt <http://crbug.com/130097>. If the
343 // WebContents is in the middle of destruction, do not risk it. 217 // WebContents is in the middle of destruction, do not risk it.
344 if (web_contents->IsBeingDestroyed()) 218 if (web_contents->IsBeingDestroyed())
345 return; 219 return;
346 // Skip if a pending entry exists. WidgetHidden can be called while navigating 220 // Skip if a pending entry exists. WidgetHidden can be called while navigating
347 // pages and this is not a time when thumbnails should be generated. 221 // pages and this is not a time when thumbnails should be generated.
348 if (web_contents->GetController().GetPendingEntry()) 222 if (web_contents->GetController().GetPendingEntry())
349 return; 223 return;
350 const GURL& url = web_contents->GetURL(); 224 const GURL& url = web_contents->GetURL();
351 Profile* profile = 225 Profile* profile =
352 Profile::FromBrowserContext(web_contents->GetBrowserContext()); 226 Profile::FromBrowserContext(web_contents->GetBrowserContext());
353 227
354 scoped_refptr<thumbnails::ThumbnailService> thumbnail_service = 228 scoped_refptr<thumbnails::ThumbnailService> thumbnail_service =
355 ThumbnailServiceFactory::GetForProfile(profile); 229 ThumbnailServiceFactory::GetForProfile(profile);
356 230
357 // Skip if we don't need to update the thumbnail. 231 // Skip if we don't need to update the thumbnail.
358 if (thumbnail_service == NULL || 232 if (thumbnail_service == NULL ||
359 !thumbnail_service->ShouldAcquirePageThumbnail(url)) { 233 !thumbnail_service->ShouldAcquirePageThumbnail(url)) {
360 return; 234 return;
361 } 235 }
362 236
363 AsyncUpdateThumbnail(web_contents); 237 scoped_refptr<thumbnails::ThumbnailingAlgorithm> algorithm(
364 } 238 thumbnail_service->CreateThumbnailingAlgorithm());
365 239
366 void ThumbnailTabHelper::UpdateThumbnail( 240 if (algorithm != NULL) {
367 ThumbnailingContext* context, 241 scoped_refptr<ThumbnailingContext> context(
368 const SkBitmap& thumbnail) {
369 Profile* profile =
370 Profile::FromBrowserContext(context->browser_context);
371 scoped_refptr<thumbnails::ThumbnailService> thumbnail_service =
372 ThumbnailServiceFactory::GetForProfile(profile);
373
374 if (!thumbnail_service)
375 return;
376
377 context->score.boring_score = CalculateBoringScore(thumbnail);
378 context->score.good_clipping =
379 (context->clip_result == ThumbnailTabHelper::kWiderThanTall ||
380 context->clip_result == ThumbnailTabHelper::kTallerThanWide ||
381 context->clip_result == ThumbnailTabHelper::kNotClipped);
382
383 gfx::Image image(thumbnail);
384 thumbnail_service->SetPageThumbnail(context->url, image, context->score);
385 VLOG(1) << "Thumbnail taken for " << context->url << ": "
386 << context->score.ToString();
387 }
388
389 void ThumbnailTabHelper::AsyncUpdateThumbnail(
390 WebContents* web_contents) {
391 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
392 RenderWidgetHost* render_widget_host = web_contents->GetRenderViewHost();
393 content::RenderWidgetHostView* view = render_widget_host->GetView();
394 if (!view)
395 return;
396 if (!view->IsSurfaceAvailableForCopy()) {
397 #if defined(OS_WIN)
398 // On Windows XP, neither the backing store nor the compositing surface is
399 // available in the browser when accelerated compositing is active, so ask
400 // the renderer to send a snapshot for creating the thumbnail.
401 if (base::win::GetVersion() < base::win::VERSION_VISTA) {
402 scoped_refptr<ThumbnailingContext> context(
403 new ThumbnailingContext(web_contents, load_interrupted_)); 242 new ThumbnailingContext(web_contents, load_interrupted_));
404 gfx::Size view_size = 243 AsyncProcessThumbnail(web_contents, context, algorithm);
405 render_widget_host->GetView()->GetViewBounds().size();
406 g_browser_process->GetRenderWidgetSnapshotTaker()->AskForSnapshot(
407 render_widget_host,
408 base::Bind(&ThumbnailTabHelper::UpdateThumbnailWithBitmap,
409 context),
410 view_size,
411 view_size);
412 }
413 #endif
414 return;
415 } 244 }
416
417 gfx::Rect copy_rect = gfx::Rect(view->GetViewBounds().size());
418 // Clip the pixels that will commonly hold a scrollbar, which looks bad in
419 // thumbnails.
420 int scrollbar_size = gfx::scrollbar_size();
421 copy_rect.Inset(0, 0, scrollbar_size, scrollbar_size);
422
423 scoped_refptr<ThumbnailingContext> context(
424 new ThumbnailingContext(web_contents, load_interrupted_));
425 copy_rect = GetClippingRect(copy_rect.size(),
426 gfx::Size(kThumbnailWidth, kThumbnailHeight),
427 &context->clip_result);
428
429 gfx::Size copy_size = GetCopySizeForThumbnail(view);
430 skia::PlatformBitmap* temp_bitmap = new skia::PlatformBitmap;
431 render_widget_host->CopyFromBackingStore(
432 copy_rect,
433 copy_size,
434 base::Bind(&ThumbnailTabHelper::UpdateThumbnailWithCanvas,
435 context,
436 base::Owned(temp_bitmap)),
437 temp_bitmap);
438 }
439
440 void ThumbnailTabHelper::UpdateThumbnailWithBitmap(
441 ThumbnailingContext* context,
442 const SkBitmap& bitmap) {
443 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
444 if (bitmap.isNull() || bitmap.empty())
445 return;
446
447 SkBitmap thumbnail = CreateThumbnail(bitmap,
448 GetThumbnailSizeInPixel(),
449 &context->clip_result);
450
451 UpdateThumbnail(context, thumbnail);
452 }
453
454 void ThumbnailTabHelper::UpdateThumbnailWithCanvas(
455 ThumbnailingContext* context,
456 skia::PlatformBitmap* temp_bitmap,
457 bool succeeded) {
458 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
459 if (!succeeded)
460 return;
461
462 SkBitmap bitmap = temp_bitmap->GetBitmap();
463 UpdateThumbnailWithBitmap(context, bitmap);
464 } 245 }
465 246
466 void ThumbnailTabHelper::DidStartLoading( 247 void ThumbnailTabHelper::DidStartLoading(
467 content::RenderViewHost* render_view_host) { 248 content::RenderViewHost* render_view_host) {
468 load_interrupted_ = false; 249 load_interrupted_ = false;
469 } 250 }
470 251
471 void ThumbnailTabHelper::StopNavigation() { 252 void ThumbnailTabHelper::StopNavigation() {
472 // This function gets called when the page loading is interrupted by the 253 // This function gets called when the page loading is interrupted by the
473 // stop button. 254 // stop button.
474 load_interrupted_ = true; 255 load_interrupted_ = true;
475 } 256 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698