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.
5 #include "components/wallpaper/wallpaper_resizer.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "base/threading/worker_pool.h"
12 #include "components/wallpaper/wallpaper_resizer_observer.h"
13 #include "third_party/skia/include/core/SkImage.h"
14 #include "ui/gfx/image/image_skia_rep.h"
15 #include "ui/gfx/skia_util.h"
17 using base::SequencedWorkerPool
;
22 // For our scaling ratios we need to round positive numbers.
23 int RoundPositive(double x
) {
24 return static_cast<int>(floor(x
+ 0.5));
27 // Resizes |orig_bitmap| to |target_size| using |layout| and stores the
28 // resulting bitmap at |resized_bitmap_out|.
29 void Resize(SkBitmap orig_bitmap
,
30 const gfx::Size
& target_size
,
31 WallpaperLayout layout
,
32 SkBitmap
* resized_bitmap_out
,
33 SequencedWorkerPool
* worker_pool
) {
34 DCHECK(worker_pool
->RunsTasksOnCurrentThread());
35 SkBitmap new_bitmap
= orig_bitmap
;
37 const int orig_width
= orig_bitmap
.width();
38 const int orig_height
= orig_bitmap
.height();
39 const int new_width
= target_size
.width();
40 const int new_height
= target_size
.height();
42 if (orig_width
> new_width
|| orig_height
> new_height
) {
43 gfx::Rect
wallpaper_rect(0, 0, orig_width
, orig_height
);
44 gfx::Size cropped_size
= gfx::Size(std::min(new_width
, orig_width
),
45 std::min(new_height
, orig_height
));
47 case WALLPAPER_LAYOUT_CENTER
:
48 wallpaper_rect
.ClampToCenteredSize(cropped_size
);
49 orig_bitmap
.extractSubset(&new_bitmap
,
50 gfx::RectToSkIRect(wallpaper_rect
));
52 case WALLPAPER_LAYOUT_TILE
:
53 wallpaper_rect
.set_size(cropped_size
);
54 orig_bitmap
.extractSubset(&new_bitmap
,
55 gfx::RectToSkIRect(wallpaper_rect
));
57 case WALLPAPER_LAYOUT_STRETCH
:
58 new_bitmap
= skia::ImageOperations::Resize(
59 orig_bitmap
, skia::ImageOperations::RESIZE_LANCZOS3
, new_width
,
62 case WALLPAPER_LAYOUT_CENTER_CROPPED
:
63 if (orig_width
> new_width
&& orig_height
> new_height
) {
64 // The dimension with the smallest ratio must be cropped, the other
65 // one is preserved. Both are set in gfx::Size cropped_size.
66 double horizontal_ratio
=
67 static_cast<double>(new_width
) / static_cast<double>(orig_width
);
68 double vertical_ratio
= static_cast<double>(new_height
) /
69 static_cast<double>(orig_height
);
71 if (vertical_ratio
> horizontal_ratio
) {
72 cropped_size
= gfx::Size(
73 RoundPositive(static_cast<double>(new_width
) / vertical_ratio
),
76 cropped_size
= gfx::Size(
77 orig_width
, RoundPositive(static_cast<double>(new_height
) /
80 wallpaper_rect
.ClampToCenteredSize(cropped_size
);
82 orig_bitmap
.extractSubset(&sub_image
,
83 gfx::RectToSkIRect(wallpaper_rect
));
84 new_bitmap
= skia::ImageOperations::Resize(
85 sub_image
, skia::ImageOperations::RESIZE_LANCZOS3
, new_width
,
89 case NUM_WALLPAPER_LAYOUT
:
95 *resized_bitmap_out
= new_bitmap
;
96 resized_bitmap_out
->setImmutable();
102 uint32_t WallpaperResizer::GetImageId(const gfx::ImageSkia
& image
) {
103 const gfx::ImageSkiaRep
& image_rep
= image
.GetRepresentation(1.0f
);
104 return image_rep
.is_null() ? 0 : image_rep
.sk_bitmap().getGenerationID();
107 WallpaperResizer::WallpaperResizer(const gfx::ImageSkia
& image
,
108 const gfx::Size
& target_size
,
109 WallpaperLayout layout
,
110 base::SequencedWorkerPool
* worker_pool_ptr
)
112 original_image_id_(GetImageId(image_
)),
113 target_size_(target_size
),
115 worker_pool_(worker_pool_ptr
),
116 weak_ptr_factory_(this) {
117 image_
.MakeThreadSafe();
120 WallpaperResizer::~WallpaperResizer() {
123 void WallpaperResizer::StartResize() {
124 SkBitmap
* resized_bitmap
= new SkBitmap
;
125 scoped_refptr
<SequencedWorkerPool
> worker_pool_refptr(worker_pool_
);
126 if (!worker_pool_
->PostTaskAndReply(
127 FROM_HERE
, base::Bind(&Resize
, *image_
.bitmap(), target_size_
,
128 layout_
, resized_bitmap
, worker_pool_refptr
),
129 base::Bind(&WallpaperResizer::OnResizeFinished
,
130 weak_ptr_factory_
.GetWeakPtr(),
131 base::Owned(resized_bitmap
)))) {
132 LOG(WARNING
) << "PostSequencedWorkerTask failed. "
133 << "Wallpaper may not be resized.";
137 void WallpaperResizer::AddObserver(WallpaperResizerObserver
* observer
) {
138 observers_
.AddObserver(observer
);
141 void WallpaperResizer::RemoveObserver(WallpaperResizerObserver
* observer
) {
142 observers_
.RemoveObserver(observer
);
145 void WallpaperResizer::OnResizeFinished(SkBitmap
* resized_bitmap
) {
146 image_
= gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap
);
147 FOR_EACH_OBSERVER(WallpaperResizerObserver
, observers_
, OnWallpaperResized());
150 } // namespace wallpaper