Chromium Code Reviews| Index: chrome/browser/thumbnails/thumbnail_tab_helper.cc |
| diff --git a/chrome/browser/thumbnails/thumbnail_tab_helper.cc b/chrome/browser/thumbnails/thumbnail_tab_helper.cc |
| index b9a57b31e1b03a4c2703e47a397c071c55491afc..d9563a011273760fc1f355f7bbf739e30d000b50 100644 |
| --- a/chrome/browser/thumbnails/thumbnail_tab_helper.cc |
| +++ b/chrome/browser/thumbnails/thumbnail_tab_helper.cc |
| @@ -54,35 +54,56 @@ using thumbnails::ThumbnailingAlgorithm; |
| namespace { |
| +// Balance the call to IncrementCapturerCount() from |
| +// UpdateThumbnailIfNecessary(), and inform the tab helper that thumbnail |
| +// generation is complete. |
| +void DecrementCapturerCount(const ThumbnailingContext& context) { |
|
Lei Zhang
2015/11/20 20:01:04
If you make these ThumbnailTabHelper methods, and
Lei Zhang
2016/01/07 22:15:29
I just reiterated this idea in person. :)
shrike
2016/01/08 18:32:36
I think I found a way around having to hand the th
|
| + if (context.web_contents()) { |
| + context.web_contents()->DecrementCapturerCount(); |
| + } |
| + // When ProcessCapturedBitmap receives a failed response, and that failure |
| + // is due to shutdown, the current thread is not the UI thread. However the |
| + // tab helper weakptr can only be dereferenced from the UI thread. |
| + if (!content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)) { |
| + return; |
| + } |
| + ThumbnailTabHelper* tab_helper = context.source_tab_helper().get(); |
| + if (tab_helper) { |
| + tab_helper->set_thumbnail_generation_in_progress(false); |
| + } |
| +} |
| + |
| // Feed the constructed thumbnail to the thumbnail service. |
| void UpdateThumbnail(const ThumbnailingContext& context, |
| const SkBitmap& thumbnail) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| gfx::Image image = gfx::Image::CreateFrom1xBitmap(thumbnail); |
| - context.service->SetPageThumbnail(context, image); |
| - DVLOG(1) << "Thumbnail taken for " << context.url << ": " |
| - << context.score.ToString(); |
| + context.service()->SetPageThumbnail(context, image); |
| + DVLOG(1) << "Thumbnail taken for " << context.GetURL() << ": " |
| + << context.score().ToString(); |
| + |
| + DecrementCapturerCount(context); |
| } |
| void ProcessCapturedBitmap(scoped_refptr<ThumbnailingContext> context, |
| scoped_refptr<ThumbnailingAlgorithm> algorithm, |
| const SkBitmap& bitmap, |
| content::ReadbackResponse response) { |
| - if (response != content::READBACK_SUCCESS) |
| - return; |
| - |
| - // On success, we must be on the UI thread (on failure because of shutdown we |
| - // are not on the UI thread). |
| - DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| - |
| - algorithm->ProcessBitmap(context, base::Bind(&UpdateThumbnail), bitmap); |
| + if (context->web_contents() && response == content::READBACK_SUCCESS) { |
| + // On success, we must be on the UI thread (on failure because of shutdown |
| + // we are not on the UI thread). |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| + algorithm->ProcessBitmap(context, base::Bind(&UpdateThumbnail), bitmap); |
| + } else { |
| + DecrementCapturerCount(*context); |
| + } |
| } |
| -void AsyncProcessThumbnail(content::WebContents* web_contents, |
| - scoped_refptr<ThumbnailingContext> context, |
| +void AsyncProcessThumbnail(scoped_refptr<ThumbnailingContext> context, |
| scoped_refptr<ThumbnailingAlgorithm> algorithm) { |
| DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| RenderWidgetHost* render_widget_host = |
| - web_contents->GetRenderViewHost()->GetWidget(); |
| + context->web_contents()->GetRenderViewHost()->GetWidget(); |
| content::RenderWidgetHostView* view = render_widget_host->GetView(); |
| if (!view) |
| return; |
| @@ -102,14 +123,16 @@ void AsyncProcessThumbnail(content::WebContents* web_contents, |
| ui::ScaleFactor scale_factor = |
| ui::GetSupportedScaleFactor( |
| ui::GetScaleFactorForNativeView(view->GetNativeView())); |
| - context->clip_result = algorithm->GetCanvasCopyInfo( |
| + gfx::Size requested_copy_size; |
| + context->set_clip_result(algorithm->GetCanvasCopyInfo( |
| copy_rect.size(), |
| scale_factor, |
| ©_rect, |
| - &context->requested_copy_size); |
| + &requested_copy_size)); |
| + context->set_requested_copy_size(requested_copy_size); |
| render_widget_host->CopyFromBackingStore( |
| copy_rect, |
| - context->requested_copy_size, |
| + requested_copy_size, |
| base::Bind(&ProcessCapturedBitmap, context, algorithm), |
| kN32_SkColorType); |
| } |
| @@ -118,7 +141,9 @@ void AsyncProcessThumbnail(content::WebContents* web_contents, |
| ThumbnailTabHelper::ThumbnailTabHelper(content::WebContents* contents) |
| : content::WebContentsObserver(contents), |
| - load_interrupted_(false) { |
| + load_interrupted_(false), |
| + thumbnail_generation_in_progress_(false), |
| + weak_factory_(this) { |
| // Even though we deal in RenderWidgetHosts, we only care about its |
| // subclass, RenderViewHost when it is in a tab. We don't make thumbnails |
| // for RenderViewHosts that aren't in tabs, or RenderWidgetHosts that |
| @@ -165,6 +190,10 @@ void ThumbnailTabHelper::DidStartLoading() { |
| load_interrupted_ = false; |
| } |
| +void ThumbnailTabHelper::set_thumbnail_generation_in_progress(bool flag) { |
|
Lei Zhang
2015/11/20 20:01:04
Since we only call this with flag = false, make it
shrike
2016/01/08 18:32:35
This method will go away in my revised patchset.
|
| + thumbnail_generation_in_progress_ = flag; |
| +} |
| + |
| void ThumbnailTabHelper::NavigationStopped() { |
| // This function gets called when the page loading is interrupted by the |
| // stop button. |
| @@ -173,6 +202,11 @@ void ThumbnailTabHelper::NavigationStopped() { |
| void ThumbnailTabHelper::UpdateThumbnailIfNecessary( |
| WebContents* web_contents) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| + // Ignore thumbnail update requests if one is already being generated. |
| + if (thumbnail_generation_in_progress_) { |
| + return; |
| + } |
| // Destroying a WebContents may trigger it to be hidden, prompting a snapshot |
| // which would be unwise to attempt <http://crbug.com/130097>. If the |
| // WebContents is in the middle of destruction, do not risk it. |
| @@ -195,12 +229,20 @@ void ThumbnailTabHelper::UpdateThumbnailIfNecessary( |
| return; |
| } |
| + web_contents->IncrementCapturerCount(gfx::Size()); |
| + // It turns out that the corresponding DecrementCapturerCount() can trigger a |
| + // call to content::WebContentsImpl::WasHidden(), which eventually calls |
| + // ThumbnailTabHelper::UpdateThumbnailIfNecessary(), starting the thumbnail |
| + // generation process all over again. Break this cycle by noting that we're |
| + // currently generating a thumbnail. |
| + thumbnail_generation_in_progress_ = true; |
| scoped_refptr<thumbnails::ThumbnailingAlgorithm> algorithm( |
| thumbnail_service->GetThumbnailingAlgorithm()); |
| scoped_refptr<ThumbnailingContext> context(new ThumbnailingContext( |
| - web_contents, thumbnail_service.get(), load_interrupted_)); |
| - AsyncProcessThumbnail(web_contents, context, algorithm); |
| + web_contents, thumbnail_service.get(), weak_factory_.GetWeakPtr(), |
| + load_interrupted_)); |
| + AsyncProcessThumbnail(context, algorithm); |
| } |
| void ThumbnailTabHelper::RenderViewHostCreated( |