- add sources.
[platform/framework/web/crosswalk.git] / src / ash / desktop_background / wallpaper_resizer.cc
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 "ash/desktop_background/wallpaper_resizer.h"
6
7 #include "ash/desktop_background/wallpaper_resizer_observer.h"
8 #include "base/bind.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"
15
16 using content::BrowserThread;
17
18 namespace ash {
19 namespace {
20
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));
24 }
25
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;
34
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();
39
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));
44     switch (layout) {
45       case WALLPAPER_LAYOUT_CENTER:
46         wallpaper_rect.ClampToCenteredSize(cropped_size);
47         orig_bitmap.extractSubset(&new_bitmap,
48                                   gfx::RectToSkIRect(wallpaper_rect));
49         break;
50       case WALLPAPER_LAYOUT_TILE:
51         wallpaper_rect.set_size(cropped_size);
52         orig_bitmap.extractSubset(&new_bitmap,
53                                   gfx::RectToSkIRect(wallpaper_rect));
54         break;
55       case WALLPAPER_LAYOUT_STRETCH:
56         new_bitmap = skia::ImageOperations::Resize(
57             orig_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
58             new_width, new_height);
59         break;
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);
68
69           if (vertical_ratio > horizontal_ratio) {
70             cropped_size = gfx::Size(
71                 RoundPositive(static_cast<double>(new_width) / vertical_ratio),
72                 orig_height);
73           } else {
74             cropped_size = gfx::Size(orig_width, RoundPositive(
75                 static_cast<double>(new_height) / horizontal_ratio));
76           }
77           wallpaper_rect.ClampToCenteredSize(cropped_size);
78           SkBitmap sub_image;
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);
84         }
85     }
86   }
87
88   *resized_bitmap_out = new_bitmap;
89   resized_bitmap_out->setImmutable();
90 }
91
92 }  // namespace
93
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),
100       layout_(layout),
101       weak_ptr_factory_(this) {
102 }
103
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),
109       layout_(layout),
110       weak_ptr_factory_(this) {
111 }
112
113 WallpaperResizer::~WallpaperResizer() {
114 }
115
116 void WallpaperResizer::StartResize() {
117   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
118   SkBitmap* resized_bitmap = new SkBitmap;
119   if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
120           FROM_HERE,
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.";
128   }
129 }
130
131 void WallpaperResizer::AddObserver(WallpaperResizerObserver* observer) {
132   observers_.AddObserver(observer);
133 }
134
135 void WallpaperResizer::RemoveObserver(WallpaperResizerObserver* observer) {
136   observers_.RemoveObserver(observer);
137 }
138
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());
144 }
145
146 } // namespace ash