Home | History | Annotate | Download | only in desktop_background
      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(const gfx::ImageSkia& image,
    103                                    const gfx::Size& target_size,
    104                                    WallpaperLayout layout)
    105     : image_(image),
    106       original_image_id_(GetImageId(image_)),
    107       target_size_(target_size),
    108       layout_(layout),
    109       weak_ptr_factory_(this) {
    110   image_.MakeThreadSafe();
    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, *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   image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap);
    142   FOR_EACH_OBSERVER(WallpaperResizerObserver, observers_,
    143                     OnWallpaperResized());
    144 }
    145 
    146 } // namespace ash
    147