Skip to content

Commit

Permalink
ash: Avoid reloading already-resized custom wallpaper.
Browse files Browse the repository at this point in the history
Avoid a white flash at startup caused by
DesktopBackgroundController comparing the resized version of
a custom wallpaper image against the original image, seeing
that they are different, and then resizing the original
image again.

BUG=321402

Review URL: https://codereview.chromium.org/81393004

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@236852 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
derat@chromium.org committed Nov 22, 2013
1 parent 777ad7f commit 75a445f
Show file tree
Hide file tree
Showing 8 changed files with 151 additions and 52 deletions.
32 changes: 18 additions & 14 deletions ash/desktop_background/desktop_background_controller.cc
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@ DesktopBackgroundController::~DesktopBackgroundController() {

gfx::ImageSkia DesktopBackgroundController::GetWallpaper() const {
if (current_wallpaper_)
return current_wallpaper_->wallpaper_image();
return current_wallpaper_->image();
return gfx::ImageSkia();
}

Expand All @@ -189,18 +189,18 @@ WallpaperLayout DesktopBackgroundController::GetWallpaperLayout() const {
return WALLPAPER_LAYOUT_CENTER_CROPPED;
}

void DesktopBackgroundController::OnRootWindowAdded(
aura::Window* root_window) {
void DesktopBackgroundController::OnRootWindowAdded(aura::Window* root_window) {
// The background hasn't been set yet.
if (desktop_background_mode_ == BACKGROUND_NONE)
return;
gfx::Size max_display_size = GetMaxDisplaySizeInNative();

// Handle resolution change for "built-in" images.
if (BACKGROUND_IMAGE == desktop_background_mode_ &&
current_wallpaper_.get() &&
current_max_display_size_ != max_display_size) {
gfx::Size max_display_size = GetMaxDisplaySizeInNative();
if (current_max_display_size_ != max_display_size) {
current_max_display_size_ = max_display_size;
UpdateWallpaper();
if (desktop_background_mode_ == BACKGROUND_IMAGE &&
current_wallpaper_.get())
UpdateWallpaper();
}

InstallDesktopController(root_window);
Expand Down Expand Up @@ -306,11 +306,14 @@ void DesktopBackgroundController::OnDisplayConfigurationChanged() {
gfx::Size max_display_size = GetMaxDisplaySizeInNative();
if (current_max_display_size_ != max_display_size) {
current_max_display_size_ = max_display_size;
timer_.Stop();
timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(wallpaper_reload_delay_),
this,
&DesktopBackgroundController::UpdateWallpaper);
if (desktop_background_mode_ == BACKGROUND_IMAGE &&
current_wallpaper_.get()) {
timer_.Stop();
timer_.Start(FROM_HERE,
base::TimeDelta::FromMilliseconds(wallpaper_reload_delay_),
this,
&DesktopBackgroundController::UpdateWallpaper);
}
}
}

Expand All @@ -327,7 +330,8 @@ bool DesktopBackgroundController::DefaultWallpaperIsAlreadyLoadingOrLoaded(
bool DesktopBackgroundController::CustomWallpaperIsAlreadyLoaded(
const gfx::ImageSkia& image) const {
return current_wallpaper_.get() &&
current_wallpaper_->wallpaper_image().BackedBySameObjectAs(image);
(WallpaperResizer::GetImageId(image) ==
current_wallpaper_->original_image_id());
}

void DesktopBackgroundController::SetDesktopBackgroundImageMode() {
Expand Down
80 changes: 57 additions & 23 deletions ash/desktop_background/desktop_background_controller_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@
#include "base/files/file_path.h"
#include "base/files/scoped_temp_dir.h"
#include "base/message_loop/message_loop.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/test/test_browser_thread.h"
#include "content/public/test/test_utils.h"
#include "third_party/skia/include/core/SkBitmap.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/aura/root_window.h"
Expand Down Expand Up @@ -131,6 +133,15 @@ class DesktopBackgroundControllerTest : public test::AshTestBase {
// and writing images.
static const int kWallpaperSize = 2;

// Creates an image of size |size|.
gfx::ImageSkia CreateImage(int width, int height) {
SkBitmap bitmap;
bitmap.setConfig(SkBitmap::kARGB_8888_Config, width, height);
bitmap.allocPixels();
gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(bitmap);
return image;
}

// Runs kAnimatingDesktopController's animation to completion.
// TODO(bshe): Don't require tests to run animations; it's slow.
void RunDesktopControllerAnimation() {
Expand Down Expand Up @@ -426,82 +437,76 @@ TEST_F(DesktopBackgroundControllerTest, DisplayChange) {
if (!SupportsHostWindowResize())
return;

test::DisplayManagerTestApi display_manager_test_api(
Shell::GetInstance()->display_manager());
// Set the wallpaper to ensure that UpdateWallpaper() will be called when the
// display configuration changes.
gfx::ImageSkia image = CreateImage(640, 480);
wallpaper_delegate_->set_custom_wallpaper(image);
controller_->SetCustomWallpaper(image, WALLPAPER_LAYOUT_STRETCH);

// Small wallpaper images should be used for configurations less than or
// equal to kSmallWallpaperMaxWidth by kSmallWallpaperMaxHeight, even if
// multiple displays are connected.
test::DisplayManagerTestApi display_manager_test_api(
Shell::GetInstance()->display_manager());
display_manager_test_api.UpdateDisplay("800x600");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_SMALL,
controller_->GetAppropriateResolution());
EXPECT_EQ(0,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(0, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

display_manager_test_api.UpdateDisplay("800x600,800x600");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_SMALL,
controller_->GetAppropriateResolution());
EXPECT_EQ(0,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(0, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

display_manager_test_api.UpdateDisplay("1366x800");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_SMALL,
controller_->GetAppropriateResolution());
EXPECT_EQ(1,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(1, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

// At larger sizes, large wallpapers should be used.
display_manager_test_api.UpdateDisplay("1367x800");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_LARGE,
controller_->GetAppropriateResolution());
EXPECT_EQ(1,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(1, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

display_manager_test_api.UpdateDisplay("1367x801");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_LARGE,
controller_->GetAppropriateResolution());
EXPECT_EQ(1,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(1, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

display_manager_test_api.UpdateDisplay("2560x1700");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_LARGE,
controller_->GetAppropriateResolution());
EXPECT_EQ(1,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(1, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

// Rotated smaller screen may use larger image.
display_manager_test_api.UpdateDisplay("800x600/r");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_SMALL,
controller_->GetAppropriateResolution());
EXPECT_EQ(1,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(1, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

display_manager_test_api.UpdateDisplay("800x600/r,800x600");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_SMALL,
controller_->GetAppropriateResolution());
EXPECT_EQ(1,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(1, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
display_manager_test_api.UpdateDisplay("1366x800/r");
RunAllPendingInMessageLoop();
EXPECT_EQ(WALLPAPER_RESOLUTION_LARGE,
controller_->GetAppropriateResolution());
EXPECT_EQ(1,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
EXPECT_EQ(1, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

// Max display size didn't chagne.
display_manager_test_api.UpdateDisplay("900x800/r,400x1366");
RunAllPendingInMessageLoop();
EXPECT_EQ(0,
wallpaper_delegate_->GetUpdateWallpaperCountAndReset());

EXPECT_EQ(0, wallpaper_delegate_->GetUpdateWallpaperCountAndReset());
}

// Test that DesktopBackgroundController loads the appropriate wallpaper
Expand Down Expand Up @@ -589,6 +594,35 @@ TEST_F(DesktopBackgroundControllerTest, LargeGuestWallpaper) {
kLargeGuestWallpaperColor));
}

TEST_F(DesktopBackgroundControllerTest, ResizeCustomWallpaper) {
if (!SupportsMultipleDisplays())
return;

test::DisplayManagerTestApi display_manager_test_api(
Shell::GetInstance()->display_manager());
display_manager_test_api.UpdateDisplay("320x200");

gfx::ImageSkia image = CreateImage(640, 480);

// Set the image as custom wallpaper, wait for the resize to finish, and check
// that the resized image is the expected size.
controller_->SetCustomWallpaper(image, WALLPAPER_LAYOUT_STRETCH);
EXPECT_TRUE(image.BackedBySameObjectAs(controller_->GetWallpaper()));
content::BrowserThread::GetBlockingPool()->FlushForTesting();
content::RunAllPendingInMessageLoop();
gfx::ImageSkia resized_image = controller_->GetWallpaper();
EXPECT_FALSE(image.BackedBySameObjectAs(resized_image));
EXPECT_EQ(gfx::Size(320, 200).ToString(), resized_image.size().ToString());

// Load the original wallpaper again and check that we're still using the
// previously-resized image instead of doing another resize
// (http://crbug.com/321402).
controller_->SetCustomWallpaper(image, WALLPAPER_LAYOUT_STRETCH);
content::BrowserThread::GetBlockingPool()->FlushForTesting();
content::RunAllPendingInMessageLoop();
EXPECT_TRUE(resized_image.BackedBySameObjectAs(controller_->GetWallpaper()));
}

TEST_F(DesktopBackgroundControllerTest, GetMaxDisplaySize) {
// Device scale factor shouldn't affect the native size.
UpdateDisplay("1000x300*2");
Expand Down
20 changes: 16 additions & 4 deletions ash/desktop_background/wallpaper_resizer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
#include "base/threading/sequenced_worker_pool.h"
#include "base/threading/worker_pool.h"
#include "content/public/browser/browser_thread.h"
#include "third_party/skia/include/core/SkImage.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "ui/gfx/skia_util.h"

using content::BrowserThread;
Expand Down Expand Up @@ -91,23 +93,33 @@ void Resize(SkBitmap orig_bitmap,

} // 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(int image_resource_id,
const gfx::Size& target_size,
WallpaperLayout layout)
: wallpaper_image_(*(ui::ResourceBundle::GetSharedInstance().
: image_(*(ui::ResourceBundle::GetSharedInstance().
GetImageNamed(image_resource_id).ToImageSkia())),
original_image_id_(GetImageId(image_)),
target_size_(target_size),
layout_(layout),
weak_ptr_factory_(this) {
image_.MakeThreadSafe();
}

WallpaperResizer::WallpaperResizer(const gfx::ImageSkia& image,
const gfx::Size& target_size,
WallpaperLayout layout)
: wallpaper_image_(image),
: image_(image),
original_image_id_(GetImageId(image_)),
target_size_(target_size),
layout_(layout),
weak_ptr_factory_(this) {
image_.MakeThreadSafe();
}

WallpaperResizer::~WallpaperResizer() {
Expand All @@ -118,7 +130,7 @@ void WallpaperResizer::StartResize() {
SkBitmap* resized_bitmap = new SkBitmap;
if (!content::BrowserThread::PostBlockingPoolTaskAndReply(
FROM_HERE,
base::Bind(&Resize, *wallpaper_image_.bitmap(), target_size_,
base::Bind(&Resize, *image_.bitmap(), target_size_,
layout_, resized_bitmap),
base::Bind(&WallpaperResizer::OnResizeFinished,
weak_ptr_factory_.GetWeakPtr(),
Expand All @@ -138,7 +150,7 @@ void WallpaperResizer::RemoveObserver(WallpaperResizerObserver* observer) {

void WallpaperResizer::OnResizeFinished(SkBitmap* resized_bitmap) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
wallpaper_image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap);
image_ = gfx::ImageSkia::CreateFrom1xBitmap(*resized_bitmap);
FOR_EACH_OBSERVER(WallpaperResizerObserver, observers_,
OnWallpaperResized());
}
Expand Down
19 changes: 14 additions & 5 deletions ash/desktop_background/wallpaper_resizer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ class WallpaperResizerObserver;
// Stores the current wallpaper data and resize it to |target_size| if needed.
class ASH_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(int image_resource_id,
const gfx::Size& target_size,
WallpaperLayout layout);
Expand All @@ -31,8 +36,9 @@ class ASH_EXPORT WallpaperResizer {

~WallpaperResizer();

const gfx::ImageSkia& wallpaper_image() const { return wallpaper_image_; }
const WallpaperLayout layout() const { return layout_; }
const gfx::ImageSkia& image() const { return image_; }
uint32_t original_image_id() const { return original_image_id_; }
WallpaperLayout layout() const { return layout_; }

// Called on the UI thread to run Resize() on the worker pool and post an
// OnResizeFinished() task back to the UI thread on completion.
Expand All @@ -43,16 +49,19 @@ class ASH_EXPORT WallpaperResizer {
void RemoveObserver(WallpaperResizerObserver* observer);

private:
// Copies |resized_bitmap| to |wallpaper_image_| and notifies observers
// after Resize() has finished running.
// 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 wallpaper_image_;
gfx::ImageSkia image_;

// Unique identifier corresponding to the original (i.e. pre-resize) |image_|.
uint32_t original_image_id_;

gfx::Size target_size_;

Expand Down
20 changes: 18 additions & 2 deletions ash/desktop_background/wallpaper_resizer_unittest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ gfx::ImageSkia CreateTestImage(const gfx::Size& size) {
}
}

return gfx::ImageSkia::CreateFrom1xBitmap(src);
gfx::ImageSkia image = gfx::ImageSkia::CreateFrom1xBitmap(src);
return image;
}

bool IsColor(const gfx::ImageSkia& image, const uint32_t expect) {
Expand Down Expand Up @@ -74,7 +75,7 @@ class WallpaperResizerTest : public testing::Test,
resizer->StartResize();
WaitForResize();
resizer->RemoveObserver(this);
return resizer->wallpaper_image();
return resizer->image();
}

void WaitForResize() {
Expand Down Expand Up @@ -141,5 +142,20 @@ TEST_F(WallpaperResizerTest, AllLayoutDifferent) {
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);
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 internal
} // namespace ash
Loading

0 comments on commit 75a445f

Please sign in to comment.