#include "ash/ambient/model/ambient_topic_queue_animation_delegate.h"
#include <algorithm>
#include "ash/ambient/util/ambient_util.h"
#include "base/logging.h"
#include "base/numerics/safe_conversions.h"
#include "cc/paint/skottie_resource_metadata.h"
#include "ui/gfx/geometry/size_f.h"
namespace ash {
namespace {
bool IsPortrait(const gfx::Size& size) {
DCHECK(!size.IsEmpty());
return size.height() > size.width();
}
bool IsSquare(const gfx::Size& size) {
DCHECK(!size.IsEmpty());
static constexpr float kAspectRatioDelta = 0.05f;
static constexpr float kAspectRatioLowerBound = 1.f - kAspectRatioDelta;
static constexpr float kAspectRatioUpperBound = 1.f + kAspectRatioDelta;
float aspect_ratio = gfx::SizeF(size).AspectRatio();
return aspect_ratio > kAspectRatioLowerBound &&
aspect_ratio < kAspectRatioUpperBound;
}
gfx::Size SummarizeImageAssetSizes(
const cc::SkottieResourceMetadataMap& resource_metadata,
bool is_portrait) {
constexpr int kDimensionInvalid = -1;
int largest_width_observed = kDimensionInvalid;
int largest_height_observed = kDimensionInvalid;
float aspect_ratio_sum = 0.f;
int num_assets_found = 0;
for (const auto& [asset_id, asset_metadata] :
resource_metadata.asset_storage()) {
ambient::util::ParsedDynamicAssetId parsed_dynamic_asset_id;
bool is_dynamic_image_asset = ambient::util::ParseDynamicLottieAssetId(
asset_id, parsed_dynamic_asset_id);
if (!is_dynamic_image_asset || !asset_metadata.size.has_value() ||
IsPortrait(*asset_metadata.size) != is_portrait) {
continue;
}
largest_width_observed =
std::max(asset_metadata.size->width(), largest_width_observed);
largest_height_observed =
std::max(asset_metadata.size->height(), largest_height_observed);
if (!IsSquare(*asset_metadata.size)) {
++num_assets_found;
aspect_ratio_sum += gfx::SizeF(*asset_metadata.size).AspectRatio();
}
}
if (num_assets_found == 0) {
if (largest_width_observed == kDimensionInvalid) {
return gfx::Size();
} else {
int square_length =
std::max(largest_width_observed, largest_height_observed);
return gfx::Size(square_length, square_length);
}
}
float average_aspect_ratio = aspect_ratio_sum / num_assets_found;
gfx::Size candidate_a = gfx::Size(
largest_width_observed,
base::ClampRound<int>(largest_width_observed / average_aspect_ratio));
gfx::Size candidate_b = gfx::Size(
base::ClampRound<int>(largest_height_observed * average_aspect_ratio),
largest_height_observed);
return candidate_a.width() > candidate_b.width() ? candidate_a : candidate_b;
}
std::vector<gfx::Size> ComputeTopicSizes(
const cc::SkottieResourceMetadataMap& resource_metadata) {
static constexpr gfx::Size kDefaultTopicSize = gfx::Size(500, 500);
gfx::Size landscape_size =
SummarizeImageAssetSizes(resource_metadata, false);
gfx::Size portrait_size =
SummarizeImageAssetSizes(resource_metadata, true);
std::vector<gfx::Size> output;
if (!landscape_size.IsEmpty())
output.push_back(std::move(landscape_size));
if (!portrait_size.IsEmpty())
output.push_back(std::move(portrait_size));
if (output.empty()) {
LOG(DFATAL) << "Failed to compute topic sizes for animation. Animation "
"file is likely invalid.";
return {kDefaultTopicSize};
}
return output;
}
}
AmbientTopicQueueAnimationDelegate::AmbientTopicQueueAnimationDelegate(
const cc::SkottieResourceMetadataMap& resource_metadata)
: topic_sizes_(ComputeTopicSizes(resource_metadata)) {}
AmbientTopicQueueAnimationDelegate::~AmbientTopicQueueAnimationDelegate() =
default;
std::vector<gfx::Size> AmbientTopicQueueAnimationDelegate::GetTopicSizes() {
return topic_sizes_;
}
}