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 "ash/desktop_background/wallpaper_resizer.h"
7 #include "ash/desktop_background/wallpaper_resizer_observer.h"
9 #include "base/logging.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "base/threading/worker_pool.h"
12 #include "content/public/browser/browser_thread.h"
13 #include "ui/base/resource/resource_bundle.h"
14 #include "ui/gfx/skia_util.h"
16 using content::BrowserThread
;
21 // For our scaling ratios we need to round positive numbers.
22 int RoundPositive(double x
) {
23 return static_cast<int>(floor(x
+ 0.5));
26 // Resizes |orig_bitmap| to |target_size| using |layout| and stores the
27 // resulting bitmap at |resized_bitmap_out|.
28 void Resize(SkBitmap orig_bitmap
,
29 const gfx::Size
& target_size
,
30 WallpaperLayout layout
,
31 SkBitmap
* resized_bitmap_out
) {
32 DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
33 SkBitmap new_bitmap
= orig_bitmap
;
35 const int orig_width
= orig_bitmap
.width();
36 const int orig_height
= orig_bitmap
.height();
37 const int new_width
= target_size
.width();
38 const int new_height
= target_size
.height();
40 if (orig_width
> new_width
|| orig_height
> new_height
) {
41 gfx::Rect
wallpaper_rect(0, 0, orig_width
, orig_height
);
42 gfx::Size cropped_size
= gfx::Size(std::min(new_width
, orig_width
),
43 std::min(new_height
, orig_height
));
45 case WALLPAPER_LAYOUT_CENTER
:
46 wallpaper_rect
.ClampToCenteredSize(cropped_size
);
47 orig_bitmap
.extractSubset(&new_bitmap
,
48 gfx::RectToSkIRect(wallpaper_rect
));
50 case WALLPAPER_LAYOUT_TILE
:
51 wallpaper_rect
.set_size(cropped_size
);
52 orig_bitmap
.extractSubset(&new_bitmap
,
53 gfx::RectToSkIRect(wallpaper_rect
));
55 case WALLPAPER_LAYOUT_STRETCH
:
56 new_bitmap
= skia::ImageOperations::Resize(
57 orig_bitmap
, skia::ImageOperations::RESIZE_LANCZOS3
,
58 new_width
, new_height
);
60 case WALLPAPER_LAYOUT_CENTER_CROPPED
:
61 if (orig_width
> new_width
&& orig_height
> new_height
) {
62 // The dimension with the smallest ratio must be cropped, the other
63 // one is preserved. Both are set in gfx::Size cropped_size.
64 double horizontal_ratio
= static_cast<double>(new_width
) /
65 static_cast<double>(orig_width
);
66 double vertical_ratio
= static_cast<double>(new_height
) /
67 static_cast<double>(orig_height
);
69 if (vertical_ratio
> horizontal_ratio
) {
70 cropped_size
= gfx::Size(
71 RoundPositive(static_cast<double>(new_width
) / vertical_ratio
),
74 cropped_size
= gfx::Size(orig_width
, RoundPositive(
75 static_cast<double>(new_height
) / horizontal_ratio
));
77 wallpaper_rect
.ClampToCenteredSize(cropped_size
);
79 orig_bitmap
.extractSubset(&sub_image
,
80 gfx::RectToSkIRect(wallpaper_rect
));
81 new_bitmap
= skia::ImageOperations::Resize(
82 sub_image
, skia::ImageOperations::RESIZE_LANCZOS3
,
83 new_width
, new_height
);
88 *resized_bitmap_out
= new_bitmap
;
89 resized_bitmap_out
->setImmutable();
94 WallpaperResizer::WallpaperResizer(int image_resource_id
,
95 const gfx::Size
& target_size
,
96 WallpaperLayout layout
)
97 : wallpaper_image_(*(ui::ResourceBundle::GetSharedInstance().
98 GetImageNamed(image_resource_id
).ToImageSkia())),
99 target_size_(target_size
),
101 weak_ptr_factory_(this) {
104 WallpaperResizer::WallpaperResizer(const gfx::ImageSkia
& image
,
105 const gfx::Size
& target_size
,
106 WallpaperLayout layout
)
107 : wallpaper_image_(image
),
108 target_size_(target_size
),
110 weak_ptr_factory_(this) {
113 WallpaperResizer::~WallpaperResizer() {
116 void WallpaperResizer::StartResize() {
117 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
118 SkBitmap
* resized_bitmap
= new SkBitmap
;
119 if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
121 base::Bind(&Resize
, *wallpaper_image_
.bitmap(), target_size_
,
122 layout_
, resized_bitmap
),
123 base::Bind(&WallpaperResizer::OnResizeFinished
,
124 weak_ptr_factory_
.GetWeakPtr(),
125 base::Owned(resized_bitmap
)))) {
126 LOG(WARNING
) << "PostSequencedWorkerTask failed. "
127 << "Wallpaper may not be resized.";
131 void WallpaperResizer::AddObserver(WallpaperResizerObserver
* observer
) {
132 observers_
.AddObserver(observer
);
135 void WallpaperResizer::RemoveObserver(WallpaperResizerObserver
* observer
) {
136 observers_
.RemoveObserver(observer
);
139 void WallpaperResizer::OnResizeFinished(SkBitmap
* resized_bitmap
) {
140 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
141 wallpaper_image_
= gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap
);
142 FOR_EACH_OBSERVER(WallpaperResizerObserver
, observers_
,
143 OnWallpaperResized());