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

Side by Side Diff: chrome/browser/thumbnails/advanced_thumbnail_crop.cc

Issue 15458003: Plugs in the new thumbnailing algorithm to ThumbnailTabHelper. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Added unit tests. Created 7 years, 7 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
(Empty)
1 // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/thumbnails/advanced_thumbnail_crop.h"
6
7 #include "base/metrics/histogram.h"
8 #include "base/threading/sequenced_worker_pool.h"
9 #include "chrome/browser/thumbnails/content_analysis.h"
10 #include "chrome/browser/thumbnails/simple_thumbnail_crop.h"
11 #include "content/public/browser/browser_thread.h"
12 #include "third_party/skia/include/core/SkBitmap.h"
13 #include "ui/gfx/scrollbar_size.h"
14 #include "ui/gfx/size_conversions.h"
15 #include "ui/gfx/skbitmap_operations.h"
16 #include "ui/gfx/skia_util.h"
17
18 namespace {
mazda 2013/05/23 19:13:57 nit: add one empty line
motek. 2013/05/27 16:54:54 Done.
19 static const char kThumbnailHistogramName[] = "Thumbnail.RetargetMS";
20 static const char kFailureHistogramName[] = "Thumbnail.FailedRetargetMS";
21
22 void CallbackInvocationAdapter(
23 const thumbnails::ThumbnailingAlgorithm::ConsumerCallback& callback,
24 scoped_refptr<thumbnails::ThumbnailingContext> context,
25 const SkBitmap& source_bitmap) {
26 callback.Run(*context, source_bitmap);
27 }
28
29 }
mazda 2013/05/23 19:13:57 } // namespace
motek. 2013/05/27 16:54:54 Done.
30
31 namespace thumbnails {
32
33 using content::BrowserThread;
34
35 AdvancedThumbnailCrop::AdvancedThumbnailCrop(const gfx::Size& target_size)
36 : target_size_(target_size) {
37 DCHECK(!target_size.IsEmpty());
38 }
39
40 ClipResult AdvancedThumbnailCrop::GetCanvasCopyInfo(
41 const gfx::Size& source_size,
42 ui::ScaleFactor scale_factor,
43 gfx::Rect* clipping_rect,
44 gfx::Size* target_size) const {
45 DCHECK(!source_size.IsEmpty());
46 gfx::Size target_thumbnail_size =
47 SimpleThumbnailCrop::GetCopySizeForThumbnail(scale_factor, target_size_);
48
49 ClipResult clipping_method = thumbnails::CLIP_RESULT_NOT_CLIPPED;
50 *clipping_rect = GetClippingRect(
51 source_size, target_thumbnail_size, target_size, &clipping_method);
52 return clipping_method;
53 }
54
55 void AdvancedThumbnailCrop::ProcessBitmap(
56 scoped_refptr<ThumbnailingContext> context,
57 const ConsumerCallback& callback,
58 const SkBitmap& bitmap) {
59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
60 DCHECK(context);
61 if (bitmap.isNull() || bitmap.empty())
62 return;
63
64 float max_scale_factor =
65 ui::GetScaleFactorScale(ui::GetMaxScaleFactor());
66 gfx::Size target_thumbnail_size = gfx::ToFlooredSize(
67 gfx::ScaleSize(target_size_, max_scale_factor));
mazda 2013/05/23 19:13:57 Could you share this logic of how the scale factor
motek. 2013/05/27 16:54:54 I did it by applying some refactoring. Effectively
68
69 SkBitmap source_bitmap = PrepareSourceBitmap(
70 bitmap, target_thumbnail_size, context);
71
72 // If the source is same (or smaller) than the target, just return it as
73 // the final result. Otherwise, send the shrinking task to the blocking
74 // thread pool.
75 if (source_bitmap.width() <= target_thumbnail_size.width() ||
76 source_bitmap.height() <= target_thumbnail_size.height()) {
77 context->score.boring_score =
78 SimpleThumbnailCrop::CalculateBoringScore(source_bitmap);
79 context->score.good_clipping =
80 (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL ||
81 context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE ||
82 context->clip_result == CLIP_RESULT_NOT_CLIPPED ||
83 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET);
84
85 callback.Run(*context, source_bitmap);
86 return;
87 }
88
89 if (!BrowserThread::GetBlockingPool()->PostWorkerTaskWithShutdownBehavior(
90 FROM_HERE,
91 base::Bind(&CreateRetargettedThumbnail,
92 source_bitmap,
93 target_thumbnail_size,
94 context,
95 callback),
96 base::SequencedWorkerPool::SKIP_ON_SHUTDOWN)) {
97 LOG(WARNING) << "PostSequencedWorkerTask failed. " <<
98 "The thumbnail for " << context->url << " will not be created.";
mazda 2013/05/23 19:13:57 Move "<<" from the previous line and align it with
motek. 2013/05/27 16:54:54 Done.
99 }
100 }
101
102 // static
103 SkBitmap AdvancedThumbnailCrop::PrepareSourceBitmap(
104 const SkBitmap& received_bitmap,
105 const gfx::Size& thumbnail_size,
106 ThumbnailingContext* context) {
107
108 gfx::Size resize_target;
109 SkBitmap clipped_bitmap;
110 if (context->clip_result == CLIP_RESULT_UNPROCESSED) {
111 // This case will require extracting a fragment from the retrieved bitmap.
112 int scrollbar_size = gfx::scrollbar_size();
113 gfx::Size scrollbarless(
114 std::max(1, received_bitmap.width() - scrollbar_size),
115 std::max(1, received_bitmap.height() - scrollbar_size));
116
117 gfx::Rect clipping_rect = AdvancedThumbnailCrop::GetClippingRect(
118 scrollbarless,
119 thumbnail_size,
120 &resize_target,
121 &context->clip_result);
122
123 received_bitmap.extractSubset(&clipped_bitmap,
124 gfx::RectToSkIRect(clipping_rect));
125 } else {
126 // This means that the source bitmap has been requested and at least
127 // clipped. Upstream code in same cases seems opportunistic and it may
128 // not perform actual resizing if copying with resize is not supported.
129 // In this case we will resize to the orignally requested copy size.
130 resize_target = context->requested_copy_size;
131 clipped_bitmap = received_bitmap;
132 }
133
134 SkBitmap result_bitmap = SkBitmapOperations::DownsampleByTwoUntilSize(
135 clipped_bitmap, resize_target.width(), resize_target.height());
136 #if !defined(USE_AURA)
137 // If the bitmap has not been indeed resized, it has to be copied. In that
138 // case resampler simply returns a reference to the original bitmap, sitting
139 // in PlatformCanvas. One does not simply assign these 'magic' bitmaps to
140 // SkBitmap. They cannot be refcounted.
141 //
142 // With Aura, this does not happen since PlatformCanvas is platform
143 // idependent.
144 if (clipped_bitmap.width() == result_bitmap.width() &&
145 clipped_bitmap.height() == result_bitmap.height()) {
146 clipped_bitmap.copyTo(&result_bitmap, SkBitmap::kARGB_8888_Config);
147 }
148 #endif
149
150 return result_bitmap;
151 }
152
153 // static
154 void AdvancedThumbnailCrop::CreateRetargettedThumbnail(
155 const SkBitmap& source_bitmap,
156 const gfx::Size& thumbnail_size,
157 scoped_refptr<ThumbnailingContext> context,
158 const ConsumerCallback& callback) {
159 base::TimeTicks begin_compute_thumbnail = base::TimeTicks::Now();
160 float kernel_sigma =
161 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET ? 5.0f : 2.5f;
162 SkBitmap thumbnail = thumbnailing_utils::CreateRetargettedThumbnailImage(
163 source_bitmap, thumbnail_size, kernel_sigma);
164 bool processing_failed = thumbnail.empty();
165 if (processing_failed) {
166 // Log and apply the method very much like in SimpleThumbnailCrop (except
167 // that some clipping and copying is not required).
168 LOG(WARNING) << "CreateRetargettedThumbnailImage failed. " <<
169 "The thumbnail for " << context->url <<
170 " will be created the old-fashioned way.";
mazda 2013/05/23 19:13:57 LOG(WARNING) << "CreateRetargettedThumbnailImage f
motek. 2013/05/27 16:54:54 Done.
171 ClipResult clip_result;
172 gfx::Rect clipping_rect = SimpleThumbnailCrop::GetClippingRect(
173 gfx::Size(source_bitmap.width(), source_bitmap.height()),
174 thumbnail_size,
175 &clip_result);
176 source_bitmap.extractSubset(&thumbnail, gfx::RectToSkIRect(clipping_rect));
177 thumbnail = SkBitmapOperations::DownsampleByTwoUntilSize(
178 thumbnail, thumbnail_size.width(), thumbnail_size.height());
179 }
180
181 HISTOGRAM_TIMES(
182 processing_failed ? kFailureHistogramName : kThumbnailHistogramName,
183 base::TimeTicks::Now() - begin_compute_thumbnail);
184 context->score.boring_score =
185 SimpleThumbnailCrop::CalculateBoringScore(source_bitmap);
186 if (!processing_failed)
187 context->score.boring_score *= 1.1f; // A bit of a boost for retargetted.
mazda 2013/05/23 19:13:57 Please make a constant variable for 1.1f.
motek. 2013/05/27 16:54:54 Done.
188 context->score.good_clipping =
189 (context->clip_result == CLIP_RESULT_WIDER_THAN_TALL ||
190 context->clip_result == CLIP_RESULT_TALLER_THAN_WIDE ||
191 context->clip_result == CLIP_RESULT_NOT_CLIPPED ||
192 context->clip_result == CLIP_RESULT_SOURCE_SAME_AS_TARGET);
193 // Post the result (the bitmap) back to the callback.
194 BrowserThread::PostTask(
195 BrowserThread::UI,
196 FROM_HERE,
197 base::Bind(&CallbackInvocationAdapter, callback, context, thumbnail));
198 }
199
200 AdvancedThumbnailCrop::~AdvancedThumbnailCrop() {
201 }
202
203 // static
204 gfx::Rect AdvancedThumbnailCrop::GetClippingRect(
205 const gfx::Size& source_size,
206 const gfx::Size& thumbnail_size,
207 gfx::Size* target_size,
208 ClipResult* clip_result) {
209 // Compute and return the clipping rectagle of the source image and the
210 // size of the target bitmap which will be used for the further processing.
211 // This function in 'general case' is trivial (don't clip, halve the source)
212 // but it is needed for handling edge cases (source smaller than the target
213 // thumbnail size).
214 DCHECK(target_size);
215 DCHECK(clip_result);
216 gfx::Rect clipping_rect;
217 if (source_size.width() < thumbnail_size.width() ||
218 source_size.height() < thumbnail_size.height()) {
219 clipping_rect = gfx::Rect(thumbnail_size);
220 *target_size = thumbnail_size;
221 *clip_result = CLIP_RESULT_SOURCE_IS_SMALLER;
222 } else if (source_size.width() < thumbnail_size.width() * 4 ||
223 source_size.height() < thumbnail_size.height() * 4) {
224 clipping_rect = gfx::Rect(source_size);
225 *target_size = source_size;
226 *clip_result = CLIP_RESULT_SOURCE_SAME_AS_TARGET;
227 } else {
228 clipping_rect = gfx::Rect(source_size);
229 target_size->SetSize(source_size.width() / 2, source_size.height() / 2);
230 *clip_result = CLIP_RESULT_NOT_CLIPPED;
231 }
232
233 return clipping_rect;
234 }
235
236
mazda 2013/05/23 19:13:57 nit: delete two empty lines
motek. 2013/05/27 16:54:54 Done.
237
238 } // namespace thumbnails
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698