diff options
author | ranj <ranj@chromium.org> | 2014-12-08 15:07:31 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-12-08 23:07:58 +0000 |
commit | cd4aa551be947c30813b451e9be4a593387145a6 (patch) | |
tree | 0390dc130971040c9ad6b3b771422211944a5f90 /components/wallpaper | |
parent | 41b15014792895ca400934b2e39804bf4c41a370 (diff) | |
download | chromium_src-cd4aa551be947c30813b451e9be4a593387145a6.zip chromium_src-cd4aa551be947c30813b451e9be4a593387145a6.tar.gz chromium_src-cd4aa551be947c30813b451e9be4a593387145a6.tar.bz2 |
Create components/wallpaper directory
Move wallpaper_resizer* from "ash/desktop_background" to "extensions/components/wallpaper"
Move enum WallpaperLayout to a separate file extensions/components/wallpaper/wallpaper_layout_enum.h
that can be accessible from "extensions/components/wallpaper" and "ash/desktop_background"
BUG=431389
Review URL: https://codereview.chromium.org/720473002
Cr-Commit-Position: refs/heads/master@{#307367}
Diffstat (limited to 'components/wallpaper')
-rw-r--r-- | components/wallpaper/BUILD.gn | 20 | ||||
-rw-r--r-- | components/wallpaper/DEPS | 13 | ||||
-rw-r--r-- | components/wallpaper/OWNERS | 1 | ||||
-rw-r--r-- | components/wallpaper/wallpaper_export.h | 32 | ||||
-rw-r--r-- | components/wallpaper/wallpaper_layout.h | 25 | ||||
-rw-r--r-- | components/wallpaper/wallpaper_resizer.cc | 146 | ||||
-rw-r--r-- | components/wallpaper/wallpaper_resizer.h | 82 | ||||
-rw-r--r-- | components/wallpaper/wallpaper_resizer_observer.h | 23 | ||||
-rw-r--r-- | components/wallpaper/wallpaper_resizer_unittest.cc | 151 |
9 files changed, 493 insertions, 0 deletions
diff --git a/components/wallpaper/BUILD.gn b/components/wallpaper/BUILD.gn new file mode 100644 index 0000000..cdbd69b --- /dev/null +++ b/components/wallpaper/BUILD.gn @@ -0,0 +1,20 @@ +# Copyright 2014 The Chromium Authors. All rights reserved. +# Use of this source code is governed by a BSD-style license that can be +# found in the LICENSE file. + +component("wallpaper") { + sources = [ + "wallpaper_resizer.cc", + "wallpaper_resizer.h", + "wallpaper_resizer_observer.h", + "wallpaper_layout.h", + ] + + defines = [ "WALLPAPER_IMPLEMENTATION" ] + + deps = [ + "//base", + "//skia", + "//ui/gfx", + ] +} diff --git a/components/wallpaper/DEPS b/components/wallpaper/DEPS new file mode 100644 index 0000000..06508c6 --- /dev/null +++ b/components/wallpaper/DEPS @@ -0,0 +1,13 @@ +include_rules = [ + "+base", + "+skia/ext", + "+third_party/skia/include", + "+ui/gfx", +] + +specific_include_rules = { + "wallpaper_resizer_unittest\.cc": [ + "+content/public/test", + "+testing/gtest/include/gtest", + ], +} diff --git a/components/wallpaper/OWNERS b/components/wallpaper/OWNERS new file mode 100644 index 0000000..e88b945 --- /dev/null +++ b/components/wallpaper/OWNERS @@ -0,0 +1 @@ +bshe@chromium.org diff --git a/components/wallpaper/wallpaper_export.h b/components/wallpaper/wallpaper_export.h new file mode 100644 index 0000000..3fc352a --- /dev/null +++ b/components/wallpaper/wallpaper_export.h @@ -0,0 +1,32 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WALLPAPER_EXPORT_H_ +#define COMPONENTS_WALLPAPER_EXPORT_H_ + +// Defines WALLPAPER_EXPORT so that functionality implemented by the wallpaper +// module can be exported to consumers. + +#if defined(COMPONENT_BUILD) +#if defined(WIN32) + +#if defined(WALLPAPER_IMPLEMENTATION) +#define WALLPAPER_EXPORT __declspec(dllexport) +#else +#define WALLPAPER_EXPORT __declspec(dllimport) +#endif // defined(WALLPAPER_IMPLEMENTATION) + +#else // defined(WIN32) +#if defined(WALLPAPER_IMPLEMENTATION) +#define WALLPAPER_EXPORT __attribute__((visibility("default"))) +#else +#define WALLPAPER_EXPORT +#endif +#endif + +#else // defined(COMPONENT_BUILD) +#define WALLPAPER_EXPORT +#endif + +#endif // COMPONENTS_WALLPAPER_EXPORT_H_ diff --git a/components/wallpaper/wallpaper_layout.h b/components/wallpaper/wallpaper_layout.h new file mode 100644 index 0000000..73e3383 --- /dev/null +++ b/components/wallpaper/wallpaper_layout.h @@ -0,0 +1,25 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WALLPAPER_WALLPAPER_LAYOUT_H_ +#define COMPONENTS_WALLPAPER_WALLPAPER_LAYOUT_H_ + +namespace wallpaper { + +enum WallpaperLayout { + // Center the wallpaper on the desktop without scaling it. The wallpaper + // may be cropped. + WALLPAPER_LAYOUT_CENTER, + // Scale the wallpaper (while preserving its aspect ratio) to cover the + // desktop; the wallpaper may be cropped. + WALLPAPER_LAYOUT_CENTER_CROPPED, + // Scale the wallpaper (without preserving its aspect ratio) to match the + // desktop's size. + WALLPAPER_LAYOUT_STRETCH, + // Tile the wallpaper over the background without scaling it. + WALLPAPER_LAYOUT_TILE +}; + +} // namespace wallpaper +#endif // COMPONENTS_WALLPAPER_WALLPAPER_LAYOUT_H_ diff --git a/components/wallpaper/wallpaper_resizer.cc b/components/wallpaper/wallpaper_resizer.cc new file mode 100644 index 0000000..2c0f670 --- /dev/null +++ b/components/wallpaper/wallpaper_resizer.cc @@ -0,0 +1,146 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "components/wallpaper/wallpaper_resizer.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/logging.h" +#include "base/threading/sequenced_worker_pool.h" +#include "base/threading/worker_pool.h" +#include "components/wallpaper/wallpaper_resizer_observer.h" +#include "third_party/skia/include/core/SkImage.h" +#include "ui/gfx/image/image_skia_rep.h" +#include "ui/gfx/skia_util.h" + +using base::SequencedWorkerPool; + +namespace wallpaper { +namespace { + +// For our scaling ratios we need to round positive numbers. +int RoundPositive(double x) { + return static_cast<int>(floor(x + 0.5)); +} + +// Resizes |orig_bitmap| to |target_size| using |layout| and stores the +// resulting bitmap at |resized_bitmap_out|. +void Resize(SkBitmap orig_bitmap, + const gfx::Size& target_size, + WallpaperLayout layout, + SkBitmap* resized_bitmap_out, + SequencedWorkerPool* worker_pool) { + DCHECK(worker_pool->RunsTasksOnCurrentThread()); + SkBitmap new_bitmap = orig_bitmap; + + const int orig_width = orig_bitmap.width(); + const int orig_height = orig_bitmap.height(); + const int new_width = target_size.width(); + const int new_height = target_size.height(); + + if (orig_width > new_width || orig_height > new_height) { + gfx::Rect wallpaper_rect(0, 0, orig_width, orig_height); + gfx::Size cropped_size = gfx::Size(std::min(new_width, orig_width), + std::min(new_height, orig_height)); + switch (layout) { + case WALLPAPER_LAYOUT_CENTER: + wallpaper_rect.ClampToCenteredSize(cropped_size); + orig_bitmap.extractSubset(&new_bitmap, + gfx::RectToSkIRect(wallpaper_rect)); + break; + case WALLPAPER_LAYOUT_TILE: + wallpaper_rect.set_size(cropped_size); + orig_bitmap.extractSubset(&new_bitmap, + gfx::RectToSkIRect(wallpaper_rect)); + break; + case WALLPAPER_LAYOUT_STRETCH: + new_bitmap = skia::ImageOperations::Resize( + orig_bitmap, skia::ImageOperations::RESIZE_LANCZOS3, new_width, + new_height); + break; + case WALLPAPER_LAYOUT_CENTER_CROPPED: + if (orig_width > new_width && orig_height > new_height) { + // The dimension with the smallest ratio must be cropped, the other + // one is preserved. Both are set in gfx::Size cropped_size. + double horizontal_ratio = + static_cast<double>(new_width) / static_cast<double>(orig_width); + double vertical_ratio = static_cast<double>(new_height) / + static_cast<double>(orig_height); + + if (vertical_ratio > horizontal_ratio) { + cropped_size = gfx::Size( + RoundPositive(static_cast<double>(new_width) / vertical_ratio), + orig_height); + } else { + cropped_size = gfx::Size( + orig_width, RoundPositive(static_cast<double>(new_height) / + horizontal_ratio)); + } + wallpaper_rect.ClampToCenteredSize(cropped_size); + SkBitmap sub_image; + orig_bitmap.extractSubset(&sub_image, + gfx::RectToSkIRect(wallpaper_rect)); + new_bitmap = skia::ImageOperations::Resize( + sub_image, skia::ImageOperations::RESIZE_LANCZOS3, new_width, + new_height); + } + } + } + + *resized_bitmap_out = new_bitmap; + resized_bitmap_out->setImmutable(); +} + +} // namespace + +// static +uint32_t WallpaperResizer::GetImageId(const gfx::ImageSkia& image) { + const gfx::ImageSkiaRep& image_rep = image.GetRepresentation(1.0f); + return image_rep.is_null() ? 0 : image_rep.sk_bitmap().getGenerationID(); +} + +WallpaperResizer::WallpaperResizer(const gfx::ImageSkia& image, + const gfx::Size& target_size, + WallpaperLayout layout, + base::SequencedWorkerPool* worker_pool_ptr) + : image_(image), + original_image_id_(GetImageId(image_)), + target_size_(target_size), + layout_(layout), + worker_pool_(worker_pool_ptr), + weak_ptr_factory_(this) { + image_.MakeThreadSafe(); +} + +WallpaperResizer::~WallpaperResizer() { +} + +void WallpaperResizer::StartResize() { + SkBitmap* resized_bitmap = new SkBitmap; + scoped_refptr<SequencedWorkerPool> worker_pool_refptr(worker_pool_); + if (!worker_pool_->PostTaskAndReply( + FROM_HERE, base::Bind(&Resize, *image_.bitmap(), target_size_, + layout_, resized_bitmap, worker_pool_refptr), + base::Bind(&WallpaperResizer::OnResizeFinished, + weak_ptr_factory_.GetWeakPtr(), + base::Owned(resized_bitmap)))) { + LOG(WARNING) << "PostSequencedWorkerTask failed. " + << "Wallpaper may not be resized."; + } +} + +void WallpaperResizer::AddObserver(WallpaperResizerObserver* observer) { + observers_.AddObserver(observer); +} + +void WallpaperResizer::RemoveObserver(WallpaperResizerObserver* observer) { + observers_.RemoveObserver(observer); +} + +void WallpaperResizer::OnResizeFinished(SkBitmap* resized_bitmap) { + image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap); + FOR_EACH_OBSERVER(WallpaperResizerObserver, observers_, OnWallpaperResized()); +} + +} // namespace wallpaper diff --git a/components/wallpaper/wallpaper_resizer.h b/components/wallpaper/wallpaper_resizer.h new file mode 100644 index 0000000..b1c7bc3 --- /dev/null +++ b/components/wallpaper/wallpaper_resizer.h @@ -0,0 +1,82 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WALLPAPER_WALLPAPER_RESIZER_H_ +#define COMPONENTS_WALLPAPER_WALLPAPER_RESIZER_H_ + +#include "base/memory/weak_ptr.h" +#include "base/observer_list.h" +#include "components/wallpaper/wallpaper_layout.h" +#include "components/wallpaper/wallpaper_resizer_observer.h" +#include "skia/ext/image_operations.h" +#include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/image/image_skia.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/size.h" + +namespace base { +class SequencedWorkerPool; +} + +namespace wallpaper { + +class WallpaperResizerObserver; + +// Stores the current wallpaper data and resize it to |target_size| if needed. +class WALLPAPER_EXPORT WallpaperResizer { + public: + // Returns a unique identifier corresponding to |image|, suitable for + // comparison against the value returned by original_image_id(). If the image + // is modified, its ID will change. + static uint32_t GetImageId(const gfx::ImageSkia& image); + + WallpaperResizer(const gfx::ImageSkia& image, + const gfx::Size& target_size, + WallpaperLayout layout, + base::SequencedWorkerPool* worker_pool_ptr); + + ~WallpaperResizer(); + + const gfx::ImageSkia& image() const { return image_; } + uint32_t original_image_id() const { return original_image_id_; } + WallpaperLayout layout() const { return layout_; } + base::SequencedWorkerPool* worker_pool() const { return worker_pool_; } + + // Called on the UI thread to run Resize() on the worker pool and post an + // OnResizeFinished() task back to the UI thread on completion. + void StartResize(); + + // Add/Remove observers. + void AddObserver(WallpaperResizerObserver* observer); + void RemoveObserver(WallpaperResizerObserver* observer); + + private: + // Copies |resized_bitmap| to |image_| and notifies observers after Resize() + // has finished running. + void OnResizeFinished(SkBitmap* resized_bitmap); + + ObserverList<WallpaperResizerObserver> observers_; + + // Image that should currently be used for wallpaper. It initially + // contains the original image and is updated to contain the resized + // image by OnResizeFinished(). + gfx::ImageSkia image_; + + // Unique identifier corresponding to the original (i.e. pre-resize) |image_|. + uint32_t original_image_id_; + + gfx::Size target_size_; + + WallpaperLayout layout_; + + base::SequencedWorkerPool* worker_pool_; + + base::WeakPtrFactory<WallpaperResizer> weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(WallpaperResizer); +}; + +} // namespace wallpaper + +#endif // COMPONENTS_WALLPAPER_WALLPAPER_RESIZER_H_ diff --git a/components/wallpaper/wallpaper_resizer_observer.h b/components/wallpaper/wallpaper_resizer_observer.h new file mode 100644 index 0000000..5e3d7ca --- /dev/null +++ b/components/wallpaper/wallpaper_resizer_observer.h @@ -0,0 +1,23 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef COMPONENTS_WALLPAPER_WALLPAPER_RESIZER_OBSERVER_H_ +#define COMPONENTS_WALLPAPER_WALLPAPER_RESIZER_OBSERVER_H_ + +#include "components/wallpaper/wallpaper_export.h" + +namespace wallpaper { + +class WALLPAPER_EXPORT WallpaperResizerObserver { + public: + // Invoked when the wallpaper is resized. + virtual void OnWallpaperResized() = 0; + + protected: + virtual ~WallpaperResizerObserver() {} +}; + +} // namespace wallpaper + +#endif // COMPONENTS_WALLPAPER_WALLPAPER_RESIZER_OBSERVER_H_ diff --git a/components/wallpaper/wallpaper_resizer_unittest.cc b/components/wallpaper/wallpaper_resizer_unittest.cc new file mode 100644 index 0000000..98c314a --- /dev/null +++ b/components/wallpaper/wallpaper_resizer_unittest.cc @@ -0,0 +1,151 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/message_loop/message_loop.h" +#include "components/wallpaper/wallpaper_resizer.h" +#include "components/wallpaper/wallpaper_resizer_observer.h" +#include "content/public/test/test_browser_thread.h" +#include "testing/gtest/include/gtest/gtest.h" +#include "ui/gfx/image/image_skia_rep.h" + +namespace { + +const int kTestImageWidth = 5; +const int kTestImageHeight = 2; +const int kTargetWidth = 1; +const int kTargetHeight = 1; +const uint32_t kExpectedCenter = 0x02020202u; +const uint32_t kExpectedCenterCropped = 0x03030303u; +const uint32_t kExpectedStretch = 0x04040404u; +const uint32_t kExpectedTile = 0; + +gfx::ImageSkia CreateTestImage(const gfx::Size& size) { + SkBitmap src; + int w = size.width(); + int h = size.height(); + src.allocN32Pixels(w, h); + + // Fill bitmap with data. + for (int y = 0; y < h; ++y) { + for (int x = 0; x < w; ++x) { + const uint8_t component = static_cast<uint8_t>(y * w + x); + const SkColor pixel = + SkColorSetARGB(component, component, component, component); + *(src.getAddr32(x, y)) = pixel; + } + } + + gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src); + return image; +} + +bool IsColor(const gfx::ImageSkia& image, const uint32_t expect) { + EXPECT_EQ(image.width(), kTargetWidth); + EXPECT_EQ(image.height(), kTargetHeight); + const SkBitmap* image_bitmap = image.bitmap(); + SkAutoLockPixels image_lock(*image_bitmap); + return *image_bitmap->getAddr32(0, 0) == expect; +} + +} // namespace + +namespace wallpaper { + +class WallpaperResizerTest : public testing::Test, + public WallpaperResizerObserver { + public: + WallpaperResizerTest() + : ui_thread_(content::BrowserThread::UI, &message_loop_) {} + ~WallpaperResizerTest() override {} + + gfx::ImageSkia Resize(const gfx::ImageSkia& image, + const gfx::Size& target_size, + WallpaperLayout layout) { + scoped_ptr<WallpaperResizer> resizer; + resizer.reset(new WallpaperResizer( + image, target_size, layout, content::BrowserThread::GetBlockingPool())); + resizer->AddObserver(this); + resizer->StartResize(); + WaitForResize(); + resizer->RemoveObserver(this); + return resizer->image(); + } + + void WaitForResize() { message_loop_.Run(); } + + void OnWallpaperResized() override { message_loop_.Quit(); } + + private: + base::MessageLoop message_loop_; + content::TestBrowserThread ui_thread_; + + DISALLOW_COPY_AND_ASSIGN(WallpaperResizerTest); +}; + +TEST_F(WallpaperResizerTest, BasicResize) { + // Keeps in sync with WallpaperLayout enum. + WallpaperLayout layouts[4] = { + WALLPAPER_LAYOUT_CENTER, + WALLPAPER_LAYOUT_CENTER_CROPPED, + WALLPAPER_LAYOUT_STRETCH, + WALLPAPER_LAYOUT_TILE, + }; + const int length = arraysize(layouts); + + for (int i = 0; i < length; i++) { + WallpaperLayout layout = layouts[i]; + gfx::ImageSkia small_image(gfx::ImageSkiaRep(gfx::Size(10, 20), 1.0f)); + + gfx::ImageSkia resized_small = + Resize(small_image, gfx::Size(800, 600), layout); + EXPECT_EQ(10, resized_small.width()); + EXPECT_EQ(20, resized_small.height()); + + gfx::ImageSkia large_image(gfx::ImageSkiaRep(gfx::Size(1000, 1000), 1.0f)); + gfx::ImageSkia resized_large = + Resize(large_image, gfx::Size(800, 600), layout); + EXPECT_EQ(800, resized_large.width()); + EXPECT_EQ(600, resized_large.height()); + } +} + +// Test for crbug.com/244629. "CENTER_CROPPED generates the same image as +// STRETCH layout" +TEST_F(WallpaperResizerTest, AllLayoutDifferent) { + gfx::ImageSkia image = + CreateTestImage(gfx::Size(kTestImageWidth, kTestImageHeight)); + + gfx::Size target_size = gfx::Size(kTargetWidth, kTargetHeight); + gfx::ImageSkia center = Resize(image, target_size, WALLPAPER_LAYOUT_CENTER); + + gfx::ImageSkia center_cropped = + Resize(image, target_size, WALLPAPER_LAYOUT_CENTER_CROPPED); + + gfx::ImageSkia stretch = Resize(image, target_size, WALLPAPER_LAYOUT_STRETCH); + + gfx::ImageSkia tile = Resize(image, target_size, WALLPAPER_LAYOUT_TILE); + + EXPECT_TRUE(IsColor(center, kExpectedCenter)); + EXPECT_TRUE(IsColor(center_cropped, kExpectedCenterCropped)); + EXPECT_TRUE(IsColor(stretch, kExpectedStretch)); + EXPECT_TRUE(IsColor(tile, kExpectedTile)); +} + +TEST_F(WallpaperResizerTest, ImageId) { + gfx::ImageSkia image = + CreateTestImage(gfx::Size(kTestImageWidth, kTestImageHeight)); + + // Create a WallpaperResizer and check that it reports an original image ID + // both pre- and post-resize that matches the ID returned by GetImageId(). + WallpaperResizer resizer(image, gfx::Size(10, 20), WALLPAPER_LAYOUT_STRETCH, + content::BrowserThread::GetBlockingPool()); + EXPECT_EQ(WallpaperResizer::GetImageId(image), resizer.original_image_id()); + resizer.AddObserver(this); + resizer.StartResize(); + WaitForResize(); + resizer.RemoveObserver(this); + EXPECT_EQ(WallpaperResizer::GetImageId(image), resizer.original_image_id()); +} + +} // namespace ash |