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 for " |
100 << context->url << " will not be created."; | 101 << context->GetURL() << " will not be created."; |
101 } | 102 } |
102 } | 103 } |
103 | 104 |
104 // static | 105 // static |
105 SkBitmap ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap( | 106 SkBitmap ContentBasedThumbnailingAlgorithm::PrepareSourceBitmap( |
106 const SkBitmap& received_bitmap, | 107 const SkBitmap& received_bitmap, |
107 const gfx::Size& thumbnail_size, | 108 const gfx::Size& thumbnail_size, |
108 ThumbnailingContext* context) { | 109 ThumbnailingContext* context) { |
109 gfx::Size resize_target; | 110 gfx::Size resize_target; |
110 SkBitmap clipped_bitmap; | 111 SkBitmap clipped_bitmap; |
111 if (context->clip_result == CLIP_RESULT_UNPROCESSED) { | 112 if (context->clip_result() == CLIP_RESULT_UNPROCESSED) { |
112 // This case will require extracting a fragment from the retrieved bitmap. | 113 // This case will require extracting a fragment from the retrieved bitmap. |
113 int scrollbar_size = gfx::scrollbar_size(); | 114 int scrollbar_size = gfx::scrollbar_size(); |
114 gfx::Size scrollbarless( | 115 gfx::Size scrollbarless( |
115 std::max(1, received_bitmap.width() - scrollbar_size), | 116 std::max(1, received_bitmap.width() - scrollbar_size), |
116 std::max(1, received_bitmap.height() - scrollbar_size)); | 117 std::max(1, received_bitmap.height() - scrollbar_size)); |
117 | 118 |
| 119 ClipResult clip_result; |
118 gfx::Rect clipping_rect = GetClippingRect( | 120 gfx::Rect clipping_rect = GetClippingRect( |
119 scrollbarless, | 121 scrollbarless, |
120 thumbnail_size, | 122 thumbnail_size, |
121 &resize_target, | 123 &resize_target, |
122 &context->clip_result); | 124 &clip_result); |
| 125 context->set_clip_result(clip_result); |
123 | 126 |
124 received_bitmap.extractSubset(&clipped_bitmap, | 127 received_bitmap.extractSubset(&clipped_bitmap, |
125 gfx::RectToSkIRect(clipping_rect)); | 128 gfx::RectToSkIRect(clipping_rect)); |
126 } else { | 129 } else { |
127 // This means that the source bitmap has been requested and at least | 130 // This means that the source bitmap has been requested and at least |
128 // clipped. Upstream code in same cases seems opportunistic and it may | 131 // clipped. Upstream code in same cases seems opportunistic and it may |
129 // not perform actual resizing if copying with resize is not supported. | 132 // not perform actual resizing if copying with resize is not supported. |
130 // In this case we will resize to the orignally requested copy size. | 133 // In this case we will resize to the orignally requested copy size. |
131 resize_target = context->requested_copy_size; | 134 resize_target = context->requested_copy_size(); |
132 clipped_bitmap = received_bitmap; | 135 clipped_bitmap = received_bitmap; |
133 } | 136 } |
134 | 137 |
135 SkBitmap result_bitmap = SkBitmapOperations::DownsampleByTwoUntilSize( | 138 SkBitmap result_bitmap = SkBitmapOperations::DownsampleByTwoUntilSize( |
136 clipped_bitmap, resize_target.width(), resize_target.height()); | 139 clipped_bitmap, resize_target.width(), resize_target.height()); |
137 #if !defined(USE_AURA) | 140 #if !defined(USE_AURA) |
138 // If the bitmap has not been indeed resized, it has to be copied. In that | 141 // 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 | 142 // case resampler simply returns a reference to the original bitmap, sitting |
140 // in PlatformCanvas. One does not simply assign these 'magic' bitmaps to | 143 // in PlatformCanvas. One does not simply assign these 'magic' bitmaps to |
141 // SkBitmap. They cannot be refcounted. | 144 // SkBitmap. They cannot be refcounted. |
(...skipping 10 matching lines...) Expand all Loading... |
152 } | 155 } |
153 | 156 |
154 // static | 157 // static |
155 void ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail( | 158 void ContentBasedThumbnailingAlgorithm::CreateRetargetedThumbnail( |
156 const SkBitmap& source_bitmap, | 159 const SkBitmap& source_bitmap, |
157 const gfx::Size& thumbnail_size, | 160 const gfx::Size& thumbnail_size, |
158 scoped_refptr<ThumbnailingContext> context, | 161 scoped_refptr<ThumbnailingContext> context, |
159 const ConsumerCallback& callback) { | 162 const ConsumerCallback& callback) { |
160 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); | 163 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now(); |
161 float kernel_sigma = | 164 float kernel_sigma = |
162 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET ? 5.0f : 2.5f; | 165 context->clip_result() == CLIP_RESULT_SOURCE_SAME_AS_TARGET ? 5.0f : 2.5f; |
163 SkBitmap thumbnail = thumbnailing_utils::CreateRetargetedThumbnailImage( | 166 SkBitmap thumbnail = thumbnailing_utils::CreateRetargetedThumbnailImage( |
164 source_bitmap, thumbnail_size, kernel_sigma); | 167 source_bitmap, thumbnail_size, kernel_sigma); |
165 bool processing_failed = thumbnail.empty(); | 168 bool processing_failed = thumbnail.empty(); |
166 if (processing_failed) { | 169 if (processing_failed) { |
167 // Log and apply the method very much like in SimpleThumbnailCrop (except | 170 // Log and apply the method very much like in SimpleThumbnailCrop (except |
168 // that some clipping and copying is not required). | 171 // that some clipping and copying is not required). |
169 LOG(WARNING) << "CreateRetargetedThumbnailImage failed. " | 172 LOG(WARNING) << "CreateRetargetedThumbnailImage failed. " |
170 << "The thumbnail for " << context->url | 173 << "The thumbnail for " << context->GetURL() |
171 << " will be created the old-fashioned way."; | 174 << " will be created the old-fashioned way."; |
172 | 175 |
173 ClipResult clip_result; | 176 ClipResult clip_result; |
174 gfx::Rect clipping_rect = SimpleThumbnailCrop::GetClippingRect( | 177 gfx::Rect clipping_rect = SimpleThumbnailCrop::GetClippingRect( |
175 gfx::Size(source_bitmap.width(), source_bitmap.height()), | 178 gfx::Size(source_bitmap.width(), source_bitmap.height()), |
176 thumbnail_size, | 179 thumbnail_size, |
177 &clip_result); | 180 &clip_result); |
178 source_bitmap.extractSubset(&thumbnail, gfx::RectToSkIRect(clipping_rect)); | 181 source_bitmap.extractSubset(&thumbnail, gfx::RectToSkIRect(clipping_rect)); |
179 thumbnail = SkBitmapOperations::DownsampleByTwoUntilSize( | 182 thumbnail = SkBitmapOperations::DownsampleByTwoUntilSize( |
180 thumbnail, thumbnail_size.width(), thumbnail_size.height()); | 183 thumbnail, thumbnail_size.width(), thumbnail_size.height()); |
181 } | 184 } |
182 | 185 |
183 if (processing_failed) { | 186 if (processing_failed) { |
184 LOCAL_HISTOGRAM_TIMES(kFailureHistogramName, | 187 LOCAL_HISTOGRAM_TIMES(kFailureHistogramName, |
185 base::TimeTicks::Now() - begin_compute_thumbnail); | 188 base::TimeTicks::Now() - begin_compute_thumbnail); |
186 } else { | 189 } else { |
187 LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName, | 190 LOCAL_HISTOGRAM_TIMES(kThumbnailHistogramName, |
188 base::TimeTicks::Now() - begin_compute_thumbnail); | 191 base::TimeTicks::Now() - begin_compute_thumbnail); |
189 } | 192 } |
190 context->score.boring_score = | 193 double boring_score = color_utils::CalculateBoringScore(source_bitmap); |
191 color_utils::CalculateBoringScore(source_bitmap); | 194 if (!processing_failed) { |
192 if (!processing_failed) | 195 boring_score *= kScoreBoostFromSuccessfulRetargeting; |
193 context->score.boring_score *= kScoreBoostFromSuccessfulRetargeting; | 196 } |
194 context->score.good_clipping = | 197 context->SetBoringScore(boring_score); |
195 (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL || | 198 ClipResult clip_result = context->clip_result(); |
196 context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE || | 199 bool good_clipping = |
197 context->clip_result == CLIP_RESULT_NOT_CLIPPED || | 200 (clip_result == CLIP_RESULT_WIDER_THAN_TALL || |
198 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET); | 201 clip_result == CLIP_RESULT_TALLER_THAN_WIDE || |
| 202 clip_result == CLIP_RESULT_NOT_CLIPPED || |
| 203 clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET); |
| 204 context->SetGoodClipping(good_clipping); |
199 // Post the result (the bitmap) back to the callback. | 205 // Post the result (the bitmap) back to the callback. |
200 BrowserThread::PostTask( | 206 BrowserThread::PostTask( |
201 BrowserThread::UI, | 207 BrowserThread::UI, |
202 FROM_HERE, | 208 FROM_HERE, |
203 base::Bind(&CallbackInvocationAdapter, callback, context, thumbnail)); | 209 base::Bind(&CallbackInvocationAdapter, callback, context, thumbnail)); |
204 } | 210 } |
205 | 211 |
206 ContentBasedThumbnailingAlgorithm::~ContentBasedThumbnailingAlgorithm() { | 212 ContentBasedThumbnailingAlgorithm::~ContentBasedThumbnailingAlgorithm() { |
207 } | 213 } |
208 | 214 |
(...skipping 24 matching lines...) Expand all Loading... |
233 } else { | 239 } else { |
234 clipping_rect = gfx::Rect(source_size); | 240 clipping_rect = gfx::Rect(source_size); |
235 target_size->SetSize(source_size.width() / 2, source_size.height() / 2); | 241 target_size->SetSize(source_size.width() / 2, source_size.height() / 2); |
236 *clip_result = CLIP_RESULT_NOT_CLIPPED; | 242 *clip_result = CLIP_RESULT_NOT_CLIPPED; |
237 } | 243 } |
238 | 244 |
239 return clipping_rect; | 245 return clipping_rect; |
240 } | 246 } |
241 | 247 |
242 } // namespace thumbnails | 248 } // namespace thumbnails |
OLD | NEW |