| OLD | NEW |
| 1 // Copyright 2013 The Chromium Authors. All rights reserved. | 1 // Copyright 2013 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/content_based_thumbnailing_algorithm.h" | 5 #include "chrome/browser/thumbnails/content_based_thumbnailing_algorithm.h" |
| 6 | 6 |
| 7 #include "base/metrics/histogram.h" | 7 #include "base/metrics/histogram.h" |
| 8 #include "base/threading/sequenced_worker_pool.h" | 8 #include "base/threading/sequenced_worker_pool.h" |
| 9 #include "chrome/browser/thumbnails/content_analysis.h" | 9 #include "chrome/browser/thumbnails/content_analysis.h" |
| 10 #include "chrome/browser/thumbnails/simple_thumbnail_crop.h" | 10 #include "chrome/browser/thumbnails/simple_thumbnail_crop.h" |
| (...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 69 SimpleThumbnailCrop::ComputeTargetSizeAtMaximumScale(target_size_); | 69 SimpleThumbnailCrop::ComputeTargetSizeAtMaximumScale(target_size_); |
| 70 | 70 |
| 71 SkBitmap source_bitmap = | 71 SkBitmap source_bitmap = |
| 72 PrepareSourceBitmap(bitmap, target_thumbnail_size, context.get()); | 72 PrepareSourceBitmap(bitmap, target_thumbnail_size, context.get()); |
| 73 | 73 |
| 74 // If the source is same (or smaller) than the target, just return it as | 74 // If the source is same (or smaller) than the target, just return it as |
| 75 // the final result. Otherwise, send the shrinking task to the blocking | 75 // the final result. Otherwise, send the shrinking task to the blocking |
| 76 // thread pool. | 76 // thread pool. |
| 77 if (source_bitmap.width() <= target_thumbnail_size.width() || | 77 if (source_bitmap.width() <= target_thumbnail_size.width() || |
| 78 source_bitmap.height() <= target_thumbnail_size.height()) { | 78 source_bitmap.height() <= target_thumbnail_size.height()) { |
| 79 context->score.boring_score = | 79 context->SetBoringScore(color_utils::CalculateBoringScore(source_bitmap)); |
| 80 color_utils::CalculateBoringScore(source_bitmap); | 80 ClipResult clip_result = context->clip_result(); |
| 81 context->score.good_clipping = | 81 bool good_clipping = |
| 82 (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL || | 82 (clip_result == CLIP_RESULT_WIDER_THAN_TALL || |
| 83 context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE || | 83 clip_result == CLIP_RESULT_TALLER_THAN_WIDE || |
| 84 context->clip_result == CLIP_RESULT_NOT_CLIPPED || | 84 clip_result == CLIP_RESULT_NOT_CLIPPED || |
| 85 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET); | 85 clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET); |
| 86 context->SetGoodClipping(good_clipping); |
| 86 | 87 |
| 87 callback.Run(*context.get(), source_bitmap); | 88 callback.Run(*context.get(), source_bitmap); |
| 88 return; | 89 return; |
| 89 } | 90 } |
| 90 | 91 |
| 91 if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( | 92 if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior( |
| 92 FROM_HERE, | 93 FROM_HERE, |
| 93 base::Bind(&CreateRetargetedThumbnail, | 94 base::Bind(&CreateRetargetedThumbnail, |
| 94 source_bitmap, | 95 source_bitmap, |
| 95 target_thumbnail_size, | 96 target_thumbnail_size, |
| 96 context, | 97 context, |
| 97 callback), | 98 callback), |
| 98 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) { | 99 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) { |
| 99 LOG(WARNING) << "PostSequencedWorkerTask failed. The thumbnail for " | 100 LOG(WARNING) << "PostSequencedWorkerTask failed. The thumbnail will " |
| 100 << context->url << " will not be created."; | 101 << "will not be created."; |
| 102 if (context->web_contents() != nullptr) { |
| 103 LOG(WARNING) << "The URL was " << context->GetURL() << "."; |
| 104 } else { |
| 105 LOG(WARNING) << "No URL was specified."; |
| 106 } |
| 101 } | 107 } |
| 102 } | 108 } |
| 103 | 109 |
| 104 // static | 110 // static |
| 105 SkBitmap ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap( | 111 SkBitmap ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap( |
| 106 const SkBitmap& received_bitmap, | 112 const SkBitmap& received_bitmap, |
| 107 const gfx::Size& thumbnail_size, | 113 const gfx::Size& thumbnail_size, |
| 108 ThumbnailingContext* context) { | 114 ThumbnailingContext* context) { |
| 109 gfx::Size resize_target; | 115 gfx::Size resize_target; |
| 110 SkBitmap clipped_bitmap; | 116 SkBitmap clipped_bitmap; |
| 111 if (context->clip_result == CLIP_RESULT_UNPROCESSED) { | 117 if (context->clip_result() == CLIP_RESULT_UNPROCESSED) { |
| 112 // This case will require extracting a fragment from the retrieved bitmap. | 118 // This case will require extracting a fragment from the retrieved bitmap. |
| 113 int scrollbar_size = gfx::scrollbar_size(); | 119 int scrollbar_size = gfx::scrollbar_size(); |
| 114 gfx::Size scrollbarless( | 120 gfx::Size scrollbarless( |
| 115 std::max(1, received_bitmap.width() - scrollbar_size), | 121 std::max(1, received_bitmap.width() - scrollbar_size), |
| 116 std::max(1, received_bitmap.height() - scrollbar_size)); | 122 std::max(1, received_bitmap.height() - scrollbar_size)); |
| 117 | 123 |
| 124 ClipResult clip_result; |
| 118 gfx::Rect clipping_rect = GetClippingRect( | 125 gfx::Rect clipping_rect = GetClippingRect( |
| 119 scrollbarless, | 126 scrollbarless, |
| 120 thumbnail_size, | 127 thumbnail_size, |
| 121 &resize_target, | 128 &resize_target, |
| 122 &context->clip_result); | 129 &clip_result); |
| 130 context->set_clip_result(clip_result); |
| 123 | 131 |
| 124 received_bitmap.extractSubset(&clipped_bitmap, | 132 received_bitmap.extractSubset(&clipped_bitmap, |
| 125 gfx::RectToSkIRect(clipping_rect)); | 133 gfx::RectToSkIRect(clipping_rect)); |
| 126 } else { | 134 } else { |
| 127 // This means that the source bitmap has been requested and at least | 135 // This means that the source bitmap has been requested and at least |
| 128 // clipped. Upstream code in same cases seems opportunistic and it may | 136 // clipped. Upstream code in same cases seems opportunistic and it may |
| 129 // not perform actual resizing if copying with resize is not supported. | 137 // not perform actual resizing if copying with resize is not supported. |
| 130 // In this case we will resize to the orignally requested copy size. | 138 // In this case we will resize to the orignally requested copy size. |
| 131 resize_target = context->requested_copy_size; | 139 resize_target = context->requested_copy_size(); |
| 132 clipped_bitmap = received_bitmap; | 140 clipped_bitmap = received_bitmap; |
| 133 } | 141 } |
| 134 | 142 |
| 135 SkBitmap result_bitmap = SkBitmapOperations::DownsampleByTwoUntilSize( | 143 SkBitmap result_bitmap = SkBitmapOperations::DownsampleByTwoUntilSize( |
| 136 clipped_bitmap, resize_target.width(), resize_target.height()); | 144 clipped_bitmap, resize_target.width(), resize_target.height()); |
| 137 #if !defined(USE_AURA) | 145 #if !defined(USE_AURA) |
| 138 // If the bitmap has not been indeed resized, it has to be copied. In that | 146 // If the bitmap has not been indeed resized, it has to be copied. In that |
| 139 // case resampler simply returns a reference to the original bitmap, sitting | 147 // case resampler simply returns a reference to the original bitmap, sitting |
| 140 // in PlatformCanvas. One does not simply assign these 'magic' bitmaps to | 148 // in PlatformCanvas. One does not simply assign these 'magic' bitmaps to |
| 141 // SkBitmap. They cannot be refcounted. | 149 // SkBitmap. They cannot be refcounted. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 152 } | 160 } |
| 153 | 161 |
| 154 // static | 162 // static |
| 155 void ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail( | 163 void ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail( |
| 156 const SkBitmap& source_bitmap, | 164 const SkBitmap& source_bitmap, |
| 157 const gfx::Size& thumbnail_size, | 165 const gfx::Size& thumbnail_size, |
| 158 scoped_refptr<ThumbnailingContext> context, | 166 scoped_refptr<ThumbnailingContext> context, |
| 159 const ConsumerCallback& callback) { | 167 const ConsumerCallback& callback) { |
| 160 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); | 168 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); |
| 161 float kernel_sigma = | 169 float kernel_sigma = |
| 162 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET ? 5.0f : 2.5f; | 170 context->clip_result() == CLIP_RESULT_SOURCE_SAME_AS_TARGET ? 5.0f : 2.5f; |
| 163 SkBitmap thumbnail = thumbnailing_utils::CreateRetargetedThumbnailImage( | 171 SkBitmap thumbnail = thumbnailing_utils::CreateRetargetedThumbnailImage( |
| 164 source_bitmap, thumbnail_size, kernel_sigma); | 172 source_bitmap, thumbnail_size, kernel_sigma); |
| 165 bool processing_failed = thumbnail.empty(); | 173 bool processing_failed = thumbnail.empty(); |
| 166 if (processing_failed) { | 174 if (processing_failed) { |
| 167 // Log and apply the method very much like in SimpleThumbnailCrop (except | 175 // Log and apply the method very much like in SimpleThumbnailCrop (except |
| 168 // that some clipping and copying is not required). | 176 // that some clipping and copying is not required). |
| 169 LOG(WARNING) << "CreateRetargetedThumbnailImage failed. " | 177 LOG(WARNING) << "CreateRetargetedThumbnailImage failed. " |
| 170 << "The thumbnail for " << context->url | 178 << "Creating the thumbnail the old-fashioned way."; |
| 171 << " will be created the old-fashioned way."; | 179 if (context->web_contents()) { |
| 180 LOG(WARNING) << "The URL was " << context->GetURL(); |
| 181 } else { |
| 182 LOG(WARNING) << "No URL was specified."; |
| 183 } |
| 172 | 184 |
| 173 ClipResult clip_result; | 185 ClipResult clip_result; |
| 174 gfx::Rect clipping_rect = SimpleThumbnailCrop::GetClippingRect( | 186 gfx::Rect clipping_rect = SimpleThumbnailCrop::GetClippingRect( |
| 175 gfx::Size(source_bitmap.width(), source_bitmap.height()), | 187 gfx::Size(source_bitmap.width(), source_bitmap.height()), |
| 176 thumbnail_size, | 188 thumbnail_size, |
| 177 &clip_result); | 189 &clip_result); |
| 178 source_bitmap.extractSubset(&thumbnail, gfx::RectToSkIRect(clipping_rect)); | 190 source_bitmap.extractSubset(&thumbnail, gfx::RectToSkIRect(clipping_rect)); |
| 179 thumbnail = SkBitmapOperations::DownsampleByTwoUntilSize( | 191 thumbnail = SkBitmapOperations::DownsampleByTwoUntilSize( |
| 180 thumbnail, thumbnail_size.width(), thumbnail_size.height()); | 192 thumbnail, thumbnail_size.width(), thumbnail_size.height()); |
| 181 } | 193 } |
| 182 | 194 |
| 183 if (processing_failed) { | 195 if (processing_failed) { |
| 184 LOCAL_HISTOGRAM_TIMES(kFailureHistogramName, | 196 LOCAL_HISTOGRAM_TIMES(kFailureHistogramName, |
| 185 base::TimeTicks::Now() - begin_compute_thumbnail); | 197 base::TimeTicks::Now() - begin_compute_thumbnail); |
| 186 } else { | 198 } else { |
| 187 LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName, | 199 LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName, |
| 188 base::TimeTicks::Now() - begin_compute_thumbnail); | 200 base::TimeTicks::Now() - begin_compute_thumbnail); |
| 189 } | 201 } |
| 190 context->score.boring_score = | 202 double boring_score = color_utils::CalculateBoringScore(source_bitmap); |
| 191 color_utils::CalculateBoringScore(source_bitmap); | 203 if (!processing_failed) { |
| 192 if (!processing_failed) | 204 boring_score *= kScoreBoostFromSuccessfulRetargeting; |
| 193 context->score.boring_score *= kScoreBoostFromSuccessfulRetargeting; | 205 } |
| 194 context->score.good_clipping = | 206 context->SetBoringScore(boring_score); |
| 195 (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL || | 207 ClipResult clip_result = context->clip_result(); |
| 196 context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE || | 208 bool good_clipping = |
| 197 context->clip_result == CLIP_RESULT_NOT_CLIPPED || | 209 (clip_result == CLIP_RESULT_WIDER_THAN_TALL || |
| 198 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET); | 210 clip_result == CLIP_RESULT_TALLER_THAN_WIDE || |
| 211 clip_result == CLIP_RESULT_NOT_CLIPPED || |
| 212 clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET); |
| 213 context->SetGoodClipping(good_clipping); |
| 199 // Post the result (the bitmap) back to the callback. | 214 // Post the result (the bitmap) back to the callback. |
| 200 BrowserThread::PostTask( | 215 BrowserThread::PostTask( |
| 201 BrowserThread::UI, | 216 BrowserThread::UI, |
| 202 FROM_HERE, | 217 FROM_HERE, |
| 203 base::Bind(&CallbackInvocationAdapter, callback, context, thumbnail)); | 218 base::Bind(&CallbackInvocationAdapter, callback, context, thumbnail)); |
| 204 } | 219 } |
| 205 | 220 |
| 206 ContentBasedThumbnailingAlgorithm::~ContentBasedThumbnailingAlgorithm() { | 221 ContentBasedThumbnailingAlgorithm::~ContentBasedThumbnailingAlgorithm() { |
| 207 } | 222 } |
| 208 | 223 |
| (...skipping 24 matching lines...) Expand all Loading... |
| 233 } else { | 248 } else { |
| 234 clipping_rect = gfx::Rect(source_size); | 249 clipping_rect = gfx::Rect(source_size); |
| 235 target_size->SetSize(source_size.width() / 2, source_size.height() / 2); | 250 target_size->SetSize(source_size.width() / 2, source_size.height() / 2); |
| 236 *clip_result = CLIP_RESULT_NOT_CLIPPED; | 251 *clip_result = CLIP_RESULT_NOT_CLIPPED; |
| 237 } | 252 } |
| 238 | 253 |
| 239 return clipping_rect; | 254 return clipping_rect; |
| 240 } | 255 } |
| 241 | 256 |
| 242 } // namespace thumbnails | 257 } // namespace thumbnails |
| OLD | NEW |