blob: d0552b1a8d760dfcc78c42be389d603edbc4e18b [file] [log] [blame]
// Copyright 2021 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 "third_party/blink/renderer/core/animation/css_aspect_ratio_interpolation_type.h"
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/animation/interpolable_aspect_ratio.h"
#include "third_party/blink/renderer/core/css/resolver/style_builder_converter.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
#include "third_party/blink/renderer/core/style/computed_style.h"
#include "third_party/blink/renderer/core/style/style_aspect_ratio.h"
namespace blink {
class CSSAspectRatioNonInterpolableValue final : public NonInterpolableValue {
public:
~CSSAspectRatioNonInterpolableValue() final = default;
static scoped_refptr<CSSAspectRatioNonInterpolableValue> Create(
StyleAspectRatio aspect_ratio) {
return base::AdoptRef(
new CSSAspectRatioNonInterpolableValue(aspect_ratio.GetType()));
}
EAspectRatioType GetAspectRatioType() const { return type_; }
bool IsCompatibleWith(const CSSAspectRatioNonInterpolableValue& other) const {
if (GetAspectRatioType() == EAspectRatioType::kAuto ||
GetAspectRatioType() != other.GetAspectRatioType())
return false;
return true;
}
DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
private:
explicit CSSAspectRatioNonInterpolableValue(EAspectRatioType type)
: type_(type) {}
EAspectRatioType type_;
};
DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSAspectRatioNonInterpolableValue);
template <>
struct DowncastTraits<CSSAspectRatioNonInterpolableValue> {
static bool AllowFrom(const NonInterpolableValue* value) {
return value && AllowFrom(*value);
}
static bool AllowFrom(const NonInterpolableValue& value) {
return value.GetType() == CSSAspectRatioNonInterpolableValue::static_type_;
}
};
class InheritedAspectRatioChecker
: public CSSInterpolationType::CSSConversionChecker {
public:
explicit InheritedAspectRatioChecker(StyleAspectRatio aspect_ratio)
: aspect_ratio_(aspect_ratio) {}
private:
bool IsValid(const StyleResolverState& state,
const InterpolationValue& underlying) const final {
return state.ParentStyle()->AspectRatio() == aspect_ratio_;
}
const StyleAspectRatio aspect_ratio_;
};
std::unique_ptr<InterpolableValue>
CSSAspectRatioInterpolationType::CreateInterpolableAspectRatio(
const StyleAspectRatio& aspect_ratio) {
std::unique_ptr<InterpolableAspectRatio> result =
InterpolableAspectRatio::MaybeCreate(aspect_ratio);
return std::move(result);
}
PairwiseInterpolationValue CSSAspectRatioInterpolationType::MaybeMergeSingles(
InterpolationValue&& start,
InterpolationValue&& end) const {
if (!To<CSSAspectRatioNonInterpolableValue>(*start.non_interpolable_value)
.IsCompatibleWith(To<CSSAspectRatioNonInterpolableValue>(
*end.non_interpolable_value))) {
return nullptr;
}
return PairwiseInterpolationValue(std::move(start.interpolable_value),
std::move(end.interpolable_value),
std::move(start.non_interpolable_value));
}
InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertNeutral(
const InterpolationValue& underlying,
ConversionCheckers& conversion_checkers) const {
return InterpolationValue(underlying.interpolable_value->CloneAndZero(),
underlying.non_interpolable_value);
}
InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertInitial(
const StyleResolverState&,
ConversionCheckers& conversion_checkers) const {
StyleAspectRatio initial_ratio = ComputedStyle::InitialStyle().AspectRatio();
return InterpolationValue(
CreateInterpolableAspectRatio(initial_ratio),
CSSAspectRatioNonInterpolableValue::Create(initial_ratio));
}
InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertInherit(
const StyleResolverState& state,
ConversionCheckers& conversion_checkers) const {
if (!state.ParentStyle())
return nullptr;
StyleAspectRatio inherited_aspect_ratio = state.ParentStyle()->AspectRatio();
conversion_checkers.push_back(
std::make_unique<InheritedAspectRatioChecker>(inherited_aspect_ratio));
if (inherited_aspect_ratio.IsAuto())
return nullptr;
return InterpolationValue(
CreateInterpolableAspectRatio(inherited_aspect_ratio),
CSSAspectRatioNonInterpolableValue::Create(inherited_aspect_ratio));
}
InterpolationValue
CSSAspectRatioInterpolationType::MaybeConvertStandardPropertyUnderlyingValue(
const ComputedStyle& style) const {
return InterpolationValue(
CreateInterpolableAspectRatio(style.AspectRatio()),
CSSAspectRatioNonInterpolableValue::Create(style.AspectRatio()));
}
InterpolationValue CSSAspectRatioInterpolationType::MaybeConvertValue(
const CSSValue& value,
const StyleResolverState* state,
ConversionCheckers&) const {
StyleAspectRatio ratio =
StyleBuilderConverter::ConvertAspectRatio(*state, value);
return InterpolationValue(CreateInterpolableAspectRatio(ratio),
CSSAspectRatioNonInterpolableValue::Create(ratio));
}
void CSSAspectRatioInterpolationType::ApplyStandardPropertyValue(
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value,
StyleResolverState& state) const {
const auto& aspect_ratio = To<InterpolableAspectRatio>(interpolable_value);
state.Style()->SetAspectRatio(StyleAspectRatio(
To<CSSAspectRatioNonInterpolableValue>(non_interpolable_value)
->GetAspectRatioType(),
aspect_ratio.GetRatio()));
}
void CSSAspectRatioInterpolationType::Composite(
UnderlyingValueOwner& underlying_value_owner,
double underlying_fraction,
const InterpolationValue& value,
double interpolation_fraction) const {
underlying_value_owner.MutableValue().interpolable_value->ScaleAndAdd(
underlying_fraction, *value.interpolable_value);
}
} // namespace blink