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