[go: nahoru, domu]

blob: a812f068e477c8a950d49c3925f796c1bd372b25 [file] [log] [blame]
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "ash/wallpaper/wallpaper_utils/wallpaper_resizer.h"
#include <utility>
#include "ash/utility/cropping_util.h"
#include "base/functional/bind.h"
#include "base/functional/callback_forward.h"
#include "base/location.h"
#include "base/logging.h"
#include "base/metrics/histogram_functions.h"
#include "base/task/task_traits.h"
#include "base/task/thread_pool.h"
#include "base/threading/thread_restrictions.h"
#include "base/time/time.h"
#include "third_party/skia/include/core/SkImage.h"
#include "ui/gfx/geometry/skia_conversions.h"
#include "ui/gfx/image/image_skia.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_rep.h"
namespace ash {
namespace {
// Kilobyte granularity is unnecessary because this metric is purely to prove
// that decoded wallpaper typically occupies several MBs, rather than 20 or 40.
constexpr int kDecodedWallpaperMetricMinMB = 1;
// Assuming 4 bytes per pixel (RGBA), 50 MB should be an image that's roughly
// 3630x3620. This exceeds the expected wallpaper size by a large margin.
constexpr int kDecodedWallpaperMetricMaxMB = 50;
constexpr int kDecodedWallpaperMetricNumBuckets = 10;
// Resizes `image` to `target_size` using `layout`.
//
// NOTE: `image` is intentionally a copy to ensure it exists for the duration of
// the function.
SkBitmap Resize(const gfx::ImageSkia image,
const gfx::Size& target_size,
WallpaperLayout layout) {
base::AssertLongCPUWorkAllowed();
SkBitmap orig_bitmap = *image.bitmap();
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) {
new_bitmap = skia::ImageOperations::Resize(
CenterCropImage(orig_bitmap, target_size),
skia::ImageOperations::RESIZE_LANCZOS3, new_width, new_height);
}
break;
case NUM_WALLPAPER_LAYOUT:
NOTREACHED();
break;
}
}
new_bitmap.setImmutable();
return new_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.GetBitmap().getGenerationID();
}
// static
gfx::ImageSkia WallpaperResizer::GetResizedImage(const gfx::ImageSkia& image,
int max_size_in_dips) {
float aspect_ratio =
static_cast<float>(image.width()) / static_cast<float>(image.height());
int height = max_size_in_dips;
int width = static_cast<int>(aspect_ratio * height);
if (width > max_size_in_dips) {
width = max_size_in_dips;
height = static_cast<int>(width / aspect_ratio);
}
return gfx::ImageSkiaOperations::CreateResizedImage(
image, skia::ImageOperations::RESIZE_BEST, gfx::Size(width, height));
}
WallpaperResizer::WallpaperResizer(const gfx::ImageSkia& image,
const gfx::Size& target_size,
const WallpaperInfo& wallpaper_info)
: image_(image),
original_image_id_(GetImageId(image_)),
target_size_(target_size),
wallpaper_info_(wallpaper_info),
sequenced_task_runner_(base::ThreadPool::CreateSequencedTaskRunner(
{base::MayBlock(), base::TaskPriority::USER_VISIBLE,
base::TaskShutdownBehavior::CONTINUE_ON_SHUTDOWN})) {
image_.MakeThreadSafe();
}
WallpaperResizer::~WallpaperResizer() = default;
void WallpaperResizer::StartResize(base::OnceClosure on_resize_done) {
weak_ptr_factory_.InvalidateWeakPtrs();
start_calculation_time_ = base::TimeTicks::Now();
if (!sequenced_task_runner_->PostTaskAndReplyWithResult(
FROM_HERE,
base::BindOnce(&Resize, image_, target_size_, wallpaper_info_.layout),
base::BindOnce(&WallpaperResizer::OnResizeFinished,
weak_ptr_factory_.GetWeakPtr(),
std::move(on_resize_done)))) {
LOG(WARNING) << "PostSequencedWorkerTask failed. "
<< "Wallpaper may not be resized.";
}
}
void WallpaperResizer::OnResizeFinished(base::OnceClosure on_resize_done,
const SkBitmap& resized_bitmap) {
static constexpr size_t kBytesPerMegabyte = 1024 * 1024;
base::UmaHistogramCustomCounts(
"Ash.Wallpaper.DecodedSizeMB",
base::ClampRound(static_cast<float>(resized_bitmap.computeByteSize()) /
kBytesPerMegabyte),
kDecodedWallpaperMetricMinMB, kDecodedWallpaperMetricMaxMB,
kDecodedWallpaperMetricNumBuckets);
auto resized_image = gfx::ImageSkia::CreateFrom1xBitmap(resized_bitmap);
DVLOG(2) << __func__ << " old=" << image_.size().ToString()
<< " new=" << resized_image.size().ToString()
<< " time=" << base::TimeTicks::Now() - start_calculation_time_;
image_ = resized_image;
std::move(on_resize_done).Run();
}
} // namespace ash