12a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Copyright (c) 2013 The Chromium Authors. All rights reserved. 22a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be 32a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// found in the LICENSE file. 42a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 52a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/desktop_background/wallpaper_resizer.h" 62a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 72a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ash/desktop_background/wallpaper_resizer_observer.h" 82a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/bind.h" 92a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/logging.h" 102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/sequenced_worker_pool.h" 112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "base/threading/worker_pool.h" 122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "content/public/browser/browser_thread.h" 13f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "third_party/skia/include/core/SkImage.h" 14f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)#include "ui/gfx/image/image_skia_rep.h" 152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "ui/gfx/skia_util.h" 162a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 172a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)using content::BrowserThread; 182a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 192a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace ash { 202a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)namespace { 212a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 222a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)// For our scaling ratios we need to round positive numbers. 232a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)int RoundPositive(double x) { 242a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) return static_cast<int>(floor(x + 0.5)); 252a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 262a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 27eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// Resizes |orig_bitmap| to |target_size| using |layout| and stores the 28eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch// resulting bitmap at |resized_bitmap_out|. 29eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid Resize(SkBitmap orig_bitmap, 30868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size& target_size, 31eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch WallpaperLayout layout, 32eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkBitmap* resized_bitmap_out) { 33eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(BrowserThread::GetBlockingPool()->RunsTasksOnCurrentThread()); 34eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkBitmap new_bitmap = orig_bitmap; 35eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 36eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int orig_width = orig_bitmap.width(); 37eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int orig_height = orig_bitmap.height(); 38eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int new_width = target_size.width(); 39eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch const int new_height = target_size.height(); 40eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 41eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (orig_width > new_width || orig_height > new_height) { 42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gfx::Rect wallpaper_rect(0, 0, orig_width, orig_height); 43eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gfx::Size cropped_size = gfx::Size(std::min(new_width, orig_width), 44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch std::min(new_height, orig_height)); 452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) switch (layout) { 462a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case WALLPAPER_LAYOUT_CENTER: 472a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wallpaper_rect.ClampToCenteredSize(cropped_size); 48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch orig_bitmap.extractSubset(&new_bitmap, 49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gfx::RectToSkIRect(wallpaper_rect)); 502a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 512a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case WALLPAPER_LAYOUT_TILE: 522a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) wallpaper_rect.set_size(cropped_size); 53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch orig_bitmap.extractSubset(&new_bitmap, 54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gfx::RectToSkIRect(wallpaper_rect)); 552a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 562a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case WALLPAPER_LAYOUT_STRETCH: 57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new_bitmap = skia::ImageOperations::Resize( 58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch orig_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, 59eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new_width, new_height); 602a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) break; 612a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) case WALLPAPER_LAYOUT_CENTER_CROPPED: 62eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (orig_width > new_width && orig_height > new_height) { 632a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // The dimension with the smallest ratio must be cropped, the other 642a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) // one is preserved. Both are set in gfx::Size cropped_size. 65eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double horizontal_ratio = static_cast<double>(new_width) / 66eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static_cast<double>(orig_width); 67eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch double vertical_ratio = static_cast<double>(new_height) / 68eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static_cast<double>(orig_height); 692a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 702a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) if (vertical_ratio > horizontal_ratio) { 712a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) cropped_size = gfx::Size( 72eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch RoundPositive(static_cast<double>(new_width) / vertical_ratio), 73eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch orig_height); 742a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } else { 75eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch cropped_size = gfx::Size(orig_width, RoundPositive( 76eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch static_cast<double>(new_height) / horizontal_ratio)); 772a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 78868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) wallpaper_rect.ClampToCenteredSize(cropped_size); 792a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) SkBitmap sub_image; 80eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch orig_bitmap.extractSubset(&sub_image, 81eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch gfx::RectToSkIRect(wallpaper_rect)); 82eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new_bitmap = skia::ImageOperations::Resize( 832a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) sub_image, skia::ImageOperations::RESIZE_LANCZOS3, 84eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch new_width, new_height); 852a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 862a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 872a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 88eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch 89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch *resized_bitmap_out = new_bitmap; 90eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch resized_bitmap_out->setImmutable(); 912a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 922a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 932a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace 942a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 95f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)// static 96f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)uint32_t WallpaperResizer::GetImageId(const gfx::ImageSkia& image) { 97f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(1.0f); 98f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) return image_rep.is_null() ? 0 : image_rep.sk_bitmap().getGenerationID(); 99f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles)} 100f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) 101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochWallpaperResizer::WallpaperResizer(const gfx::ImageSkia& image, 102868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) const gfx::Size& target_size, 103eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch WallpaperLayout layout) 104f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) : image_(image), 105f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) original_image_id_(GetImageId(image_)), 106868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles) target_size_(target_size), 107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch layout_(layout), 108c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) weak_ptr_factory_(this) { 109f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) image_.MakeThreadSafe(); 1102a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1112a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1122a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)WallpaperResizer::~WallpaperResizer() { 1132a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1152a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WallpaperResizer::StartResize() { 116eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 117eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch SkBitmap* resized_bitmap = new SkBitmap; 118eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch if (!content::BrowserThread::PostBlockingPoolTaskAndReply( 119c2e0dbddbe15c98d52c4786dac06cb8952a8ae6dTorne (Richard Coles) FROM_HERE, 120f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) base::Bind(&Resize, *image_.bitmap(), target_size_, 121eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch layout_, resized_bitmap), 122eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Bind(&WallpaperResizer::OnResizeFinished, 123eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch weak_ptr_factory_.GetWeakPtr(), 124eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch base::Owned(resized_bitmap)))) { 125eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch LOG(WARNING) << "PostSequencedWorkerTask failed. " 126eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch << "Wallpaper may not be resized."; 1272a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) } 1282a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1292a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1302a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WallpaperResizer::AddObserver(WallpaperResizerObserver* observer) { 1312a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.AddObserver(observer); 1322a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1332a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1342a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)void WallpaperResizer::RemoveObserver(WallpaperResizerObserver* observer) { 1352a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) observers_.RemoveObserver(observer); 1362a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1372a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 138eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochvoid WallpaperResizer::OnResizeFinished(SkBitmap* resized_bitmap) { 139eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 140f2477e01787aa58f445919b809d89e252beef54fTorne (Richard Coles) image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap); 1412a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) FOR_EACH_OBSERVER(WallpaperResizerObserver, observers_, 1422a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) OnWallpaperResized()); 1432a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} 1442a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles) 1452a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)} // namespace ash 146