blob: 404063392e8e827036e234f5a3c245d4ee31cfe9 [file] [log] [blame]
// Copyright 2020 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 "ash/public/cpp/holding_space/holding_space_image.h"
#include <map>
#include "base/bind.h"
#include "base/callback.h"
#include "base/location.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/skia_util.h"
namespace ash {
// HoldingSpaceImage::ImageSkiaSource ------------------------------------------
class HoldingSpaceImage::ImageSkiaSource : public gfx::ImageSkiaSource {
public:
ImageSkiaSource(const base::WeakPtr<HoldingSpaceImage>& host,
const gfx::ImageSkia& placeholder)
: host_(host), placeholder_(placeholder) {}
ImageSkiaSource(const ImageSkiaSource&) = delete;
ImageSkiaSource& operator=(const ImageSkiaSource&) = delete;
~ImageSkiaSource() override = default;
private:
// gfx::ImageSkiaSource:
gfx::ImageSkiaRep GetImageForScale(float scale) override {
if (host_)
host_->LoadBitmap(scale);
// Use `placeholder_` while we wait for the async bitmap to resolve.
return placeholder_.GetRepresentation(scale);
}
const base::WeakPtr<HoldingSpaceImage> host_;
const gfx::ImageSkia placeholder_;
};
// HoldingSpaceImage -----------------------------------------------------------
HoldingSpaceImage::HoldingSpaceImage(const base::FilePath& backing_file_path,
const gfx::ImageSkia& placeholder,
AsyncBitmapResolver async_bitmap_resolver)
: backing_file_path_(backing_file_path),
placeholder_(placeholder),
async_bitmap_resolver_(async_bitmap_resolver) {
CreateImageSkia();
}
HoldingSpaceImage::~HoldingSpaceImage() = default;
bool HoldingSpaceImage::operator==(const HoldingSpaceImage& rhs) const {
return gfx::BitmapsAreEqual(*image_skia_.bitmap(), *rhs.image_skia_.bitmap());
}
base::CallbackListSubscription HoldingSpaceImage::AddImageSkiaChangedCallback(
CallbackList::CallbackType callback) const {
return callback_list_.Add(std::move(callback));
}
void HoldingSpaceImage::LoadBitmap(float scale) {
async_bitmap_resolver_.Run(
backing_file_path_, gfx::ScaleToCeiledSize(image_skia_.size(), scale),
scale,
base::BindOnce(&HoldingSpaceImage::OnBitmapLoaded,
weak_factory_.GetWeakPtr(), backing_file_path_, scale));
}
void HoldingSpaceImage::OnBitmapLoaded(const base::FilePath& file_path,
float scale,
const SkBitmap* bitmap) {
if (!bitmap) {
// Retry load if the backing file path has changed while the image load was
// in progress.
if (backing_file_path_ != file_path)
LoadBitmap(scale);
return;
}
// Force invalidate `image_skia_` for `scale` so that it will request the
// updated `gfx::ImageSkiaRep` at next access.
image_skia_.RemoveRepresentation(scale);
image_skia_.AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale));
image_skia_.RemoveUnsupportedRepresentationsForScale(scale);
// Update the placeholder image, so the newly loaded representation becomes
// the default for any `ImageSkia` instances created when the holding space
// image gets invalidated.
placeholder_.RemoveRepresentation(scale);
placeholder_.AddRepresentation(gfx::ImageSkiaRep(*bitmap, scale));
placeholder_.RemoveUnsupportedRepresentationsForScale(scale);
callback_list_.Notify();
}
void HoldingSpaceImage::Invalidate() {
if (invalidate_timer_.IsRunning())
return;
// Schedule an invalidation task with a delay to reduce number of image loads
// when multiple image invalidations are requested in quick succession. The
// delay is selected somewhat arbitrarily to be non trivial but still not
// easily noticable by the user.
invalidate_timer_.Start(FROM_HERE, base::TimeDelta::FromMilliseconds(250),
base::BindOnce(&HoldingSpaceImage::OnInvalidateTimer,
base::Unretained(this)));
}
void HoldingSpaceImage::UpdateBackingFilePath(const base::FilePath& file_path) {
backing_file_path_ = file_path;
}
bool HoldingSpaceImage::FireInvalidateTimerForTesting() {
if (!invalidate_timer_.IsRunning())
return false;
invalidate_timer_.FireNow();
return true;
}
void HoldingSpaceImage::OnInvalidateTimer() {
// Invalidate the existing pointers to:
// * Invalidate previous `image_skia_`'s host pointer, and prevent it from
// requesting bitmap loads.
// * Prevent pending bitmap request callbacks from running.
weak_factory_.InvalidateWeakPtrs();
CreateImageSkia();
callback_list_.Notify();
}
void HoldingSpaceImage::CreateImageSkia() {
image_skia_ =
gfx::ImageSkia(std::make_unique<ImageSkiaSource>(
/*host=*/weak_factory_.GetWeakPtr(), placeholder_),
placeholder_.size());
}
} // namespace ash