Upstream version 7.36.149.0
[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 "third_party/skia/include/core/SkImage.h"
14 #include "ui/base/resource/resource_bundle.h"
15 #include "ui/gfx/image/image_skia_rep.h"
16 #include "ui/gfx/skia_util.h"
17
18 using content::BrowserThread;
19
20 namespace ash {
21 namespace {
22
23 // For our scaling ratios we need to round positive numbers.
24 int RoundPositive(double x) {
25   return static_cast<int>(floor(x + 0.5));
26 }
27
28 // Resizes |orig_bitmap| to |target_size| using |layout| and stores the
29 // resulting bitmap at |resized_bitmap_out|.
30 void Resize(SkBitmap orig_bitmap,
31             const gfx::Size& target_size,
32             WallpaperLayout layout,
33             SkBitmap* resized_bitmap_out) {
34   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
35   SkBitmap new_bitmap = orig_bitmap;
36
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();
41
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));
46     switch (layout) {
47       case WALLPAPER_LAYOUT_CENTER:
48         wallpaper_rect.ClampToCenteredSize(cropped_size);
49         orig_bitmap.extractSubset(&new_bitmap,
50                                   gfx::RectToSkIRect(wallpaper_rect));
51         break;
52       case WALLPAPER_LAYOUT_TILE:
53         wallpaper_rect.set_size(cropped_size);
54         orig_bitmap.extractSubset(&new_bitmap,
55                                   gfx::RectToSkIRect(wallpaper_rect));
56         break;
57       case WALLPAPER_LAYOUT_STRETCH:
58         new_bitmap = skia::ImageOperations::Resize(
59             orig_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
60             new_width, new_height);
61         break;
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 = static_cast<double>(new_width) /
67               static_cast<double>(orig_width);
68           double vertical_ratio = static_cast<double>(new_height) /
69               static_cast<double>(orig_height);
70
71           if (vertical_ratio > horizontal_ratio) {
72             cropped_size = gfx::Size(
73                 RoundPositive(static_cast<double>(new_width) / vertical_ratio),
74                 orig_height);
75           } else {
76             cropped_size = gfx::Size(orig_width, RoundPositive(
77                 static_cast<double>(new_height) / horizontal_ratio));
78           }
79           wallpaper_rect.ClampToCenteredSize(cropped_size);
80           SkBitmap sub_image;
81           orig_bitmap.extractSubset(&sub_image,
82                                     gfx::RectToSkIRect(wallpaper_rect));
83           new_bitmap = skia::ImageOperations::Resize(
84               sub_image, skia::ImageOperations::RESIZE_LANCZOS3,
85               new_width, new_height);
86         }
87     }
88   }
89
90   *resized_bitmap_out = new_bitmap;
91   resized_bitmap_out->setImmutable();
92 }
93
94 }  // namespace
95
96 // static
97 uint32_t WallpaperResizer::GetImageId(const gfx::ImageSkia& image) {
98   const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(1.0f);
99   return image_rep.is_null() ? 0 : image_rep.sk_bitmap().getGenerationID();
100 }
101
102 WallpaperResizer::WallpaperResizer(int image_resource_id,
103                                    const gfx::Size& target_size,
104                                    WallpaperLayout layout)
105     : image_(*(ui::ResourceBundle::GetSharedInstance()
106                    .GetImageNamed(image_resource_id)
107                    .ToImageSkia())),
108       original_image_id_(GetImageId(image_)),
109       resource_id_(image_resource_id),
110       target_size_(target_size),
111       layout_(layout),
112       weak_ptr_factory_(this) {
113   image_.MakeThreadSafe();
114 }
115
116 WallpaperResizer::WallpaperResizer(const gfx::ImageSkia& image,
117                                    const gfx::Size& target_size,
118                                    WallpaperLayout layout)
119     : image_(image),
120       original_image_id_(GetImageId(image_)),
121       resource_id_(DesktopBackgroundController::kInvalidResourceID),
122       target_size_(target_size),
123       layout_(layout),
124       weak_ptr_factory_(this) {
125   image_.MakeThreadSafe();
126 }
127
128 WallpaperResizer::~WallpaperResizer() {
129 }
130
131 void WallpaperResizer::StartResize() {
132   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
133   SkBitmap* resized_bitmap = new SkBitmap;
134   if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
135           FROM_HERE,
136           base::Bind(&Resize, *image_.bitmap(), target_size_,
137                      layout_, resized_bitmap),
138           base::Bind(&WallpaperResizer::OnResizeFinished,
139                      weak_ptr_factory_.GetWeakPtr(),
140                      base::Owned(resized_bitmap)))) {
141     LOG(WARNING) << "PostSequencedWorkerTask failed. "
142                  << "Wallpaper may not be resized.";
143   }
144 }
145
146 void WallpaperResizer::AddObserver(WallpaperResizerObserver* observer) {
147   observers_.AddObserver(observer);
148 }
149
150 void WallpaperResizer::RemoveObserver(WallpaperResizerObserver* observer) {
151   observers_.RemoveObserver(observer);
152 }
153
154 void WallpaperResizer::OnResizeFinished(SkBitmap* resized_bitmap) {
155   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
156   image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap);
157   FOR_EACH_OBSERVER(WallpaperResizerObserver, observers_,
158                     OnWallpaperResized());
159 }
160
161 } // namespace ash