• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/gfx/image/image_skia_rep.h"
15 #include "ui/gfx/skia_util.h"
16 
17 using content::BrowserThread;
18 
19 namespace ash {
20 namespace {
21 
22 // For our scaling ratios we need to round positive numbers.
RoundPositive(double x)23 int RoundPositive(double x) {
24   return static_cast<int>(floor(x + 0.5));
25 }
26 
27 // Resizes |orig_bitmap| to |target_size| using |layout| and stores the
28 // resulting bitmap at |resized_bitmap_out|.
Resize(SkBitmap orig_bitmap,const gfx::Size & target_size,WallpaperLayout layout,SkBitmap * resized_bitmap_out)29 void Resize(SkBitmap orig_bitmap,
30             const gfx::Size& target_size,
31             WallpaperLayout layout,
32             SkBitmap* resized_bitmap_out) {
33   DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread());
34   SkBitmap new_bitmap = orig_bitmap;
35 
36   const int orig_width = orig_bitmap.width();
37   const int orig_height = orig_bitmap.height();
38   const int new_width = target_size.width();
39   const int new_height = target_size.height();
40 
41   if (orig_width > new_width || orig_height > new_height) {
42     gfx::Rect wallpaper_rect(0, 0, orig_width, orig_height);
43     gfx::Size cropped_size = gfx::Size(std::min(new_width, orig_width),
44                                        std::min(new_height, orig_height));
45     switch (layout) {
46       case WALLPAPER_LAYOUT_CENTER:
47         wallpaper_rect.ClampToCenteredSize(cropped_size);
48         orig_bitmap.extractSubset(&new_bitmap,
49                                   gfx::RectToSkIRect(wallpaper_rect));
50         break;
51       case WALLPAPER_LAYOUT_TILE:
52         wallpaper_rect.set_size(cropped_size);
53         orig_bitmap.extractSubset(&new_bitmap,
54                                   gfx::RectToSkIRect(wallpaper_rect));
55         break;
56       case WALLPAPER_LAYOUT_STRETCH:
57         new_bitmap = skia::ImageOperations::Resize(
58             orig_bitmap, skia::ImageOperations::RESIZE_LANCZOS3,
59             new_width, new_height);
60         break;
61       case WALLPAPER_LAYOUT_CENTER_CROPPED:
62         if (orig_width > new_width && orig_height > new_height) {
63           // The dimension with the smallest ratio must be cropped, the other
64           // one is preserved. Both are set in gfx::Size cropped_size.
65           double horizontal_ratio = static_cast<double>(new_width) /
66               static_cast<double>(orig_width);
67           double vertical_ratio = static_cast<double>(new_height) /
68               static_cast<double>(orig_height);
69 
70           if (vertical_ratio > horizontal_ratio) {
71             cropped_size = gfx::Size(
72                 RoundPositive(static_cast<double>(new_width) / vertical_ratio),
73                 orig_height);
74           } else {
75             cropped_size = gfx::Size(orig_width, RoundPositive(
76                 static_cast<double>(new_height) / horizontal_ratio));
77           }
78           wallpaper_rect.ClampToCenteredSize(cropped_size);
79           SkBitmap sub_image;
80           orig_bitmap.extractSubset(&sub_image,
81                                     gfx::RectToSkIRect(wallpaper_rect));
82           new_bitmap = skia::ImageOperations::Resize(
83               sub_image, skia::ImageOperations::RESIZE_LANCZOS3,
84               new_width, new_height);
85         }
86     }
87   }
88 
89   *resized_bitmap_out = new_bitmap;
90   resized_bitmap_out->setImmutable();
91 }
92 
93 }  // namespace
94 
95 // static
GetImageId(const gfx::ImageSkia & image)96 uint32_t WallpaperResizer::GetImageId(const gfx::ImageSkia& image) {
97   const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(1.0f);
98   return image_rep.is_null() ? 0 : image_rep.sk_bitmap().getGenerationID();
99 }
100 
WallpaperResizer(const gfx::ImageSkia & image,const gfx::Size & target_size,WallpaperLayout layout)101 WallpaperResizer::WallpaperResizer(const gfx::ImageSkia& image,
102                                    const gfx::Size& target_size,
103                                    WallpaperLayout layout)
104     : image_(image),
105       original_image_id_(GetImageId(image_)),
106       target_size_(target_size),
107       layout_(layout),
108       weak_ptr_factory_(this) {
109   image_.MakeThreadSafe();
110 }
111 
~WallpaperResizer()112 WallpaperResizer::~WallpaperResizer() {
113 }
114 
StartResize()115 void WallpaperResizer::StartResize() {
116   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
117   SkBitmap* resized_bitmap = new SkBitmap;
118   if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
119           FROM_HERE,
120           base::Bind(&Resize, *image_.bitmap(), target_size_,
121                      layout_, resized_bitmap),
122           base::Bind(&WallpaperResizer::OnResizeFinished,
123                      weak_ptr_factory_.GetWeakPtr(),
124                      base::Owned(resized_bitmap)))) {
125     LOG(WARNING) << "PostSequencedWorkerTask failed. "
126                  << "Wallpaper may not be resized.";
127   }
128 }
129 
AddObserver(WallpaperResizerObserver * observer)130 void WallpaperResizer::AddObserver(WallpaperResizerObserver* observer) {
131   observers_.AddObserver(observer);
132 }
133 
RemoveObserver(WallpaperResizerObserver * observer)134 void WallpaperResizer::RemoveObserver(WallpaperResizerObserver* observer) {
135   observers_.RemoveObserver(observer);
136 }
137 
OnResizeFinished(SkBitmap * resized_bitmap)138 void WallpaperResizer::OnResizeFinished(SkBitmap* resized_bitmap) {
139   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
140   image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap);
141   FOR_EACH_OBSERVER(WallpaperResizerObserver, observers_,
142                     OnWallpaperResized());
143 }
144 
145 } // namespace ash
146