blob: fb731e65db34545a446489438c46bf94fa391893 [file] [log] [blame]
// Copyright 2016 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_translate_interpolation_type.h"
#include <memory>
#include <utility>
#include "base/memory/ptr_util.h"
#include "third_party/blink/renderer/core/animation/length_interpolation_functions.h"
#include "third_party/blink/renderer/core/css/css_value_list.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/platform/transforms/translate_transform_operation.h"
namespace blink {
namespace {
InterpolationValue CreateNoneValue() {
return InterpolationValue(InterpolableList::Create(0));
}
bool IsNoneValue(const InterpolationValue& value) {
return ToInterpolableList(*value.interpolable_value).length() == 0;
}
class InheritedTranslateChecker
: public CSSInterpolationType::CSSConversionChecker {
public:
~InheritedTranslateChecker() override = default;
static std::unique_ptr<InheritedTranslateChecker> Create(
scoped_refptr<TranslateTransformOperation> inherited_translate) {
return base::WrapUnique(
new InheritedTranslateChecker(std::move(inherited_translate)));
}
bool IsValid(const StyleResolverState& state,
const InterpolationValue& underlying) const final {
const TransformOperation* inherited_translate =
state.ParentStyle()->Translate();
if (inherited_translate_ == inherited_translate)
return true;
if (!inherited_translate_ || !inherited_translate)
return false;
return *inherited_translate_ == *inherited_translate;
}
private:
InheritedTranslateChecker(
scoped_refptr<TranslateTransformOperation> inherited_translate)
: inherited_translate_(std::move(inherited_translate)) {}
scoped_refptr<TransformOperation> inherited_translate_;
};
enum TranslateComponentIndex : unsigned {
kTranslateX,
kTranslateY,
kTranslateZ,
kTranslateComponentIndexCount,
};
std::unique_ptr<InterpolableValue> CreateTranslateIdentity() {
std::unique_ptr<InterpolableList> result =
InterpolableList::Create(kTranslateComponentIndexCount);
result->Set(kTranslateX,
LengthInterpolationFunctions::CreateNeutralInterpolableValue());
result->Set(kTranslateY,
LengthInterpolationFunctions::CreateNeutralInterpolableValue());
result->Set(kTranslateZ,
LengthInterpolationFunctions::CreateNeutralInterpolableValue());
return std::move(result);
}
InterpolationValue ConvertTranslateOperation(
const TranslateTransformOperation* translate,
double zoom) {
if (!translate)
return CreateNoneValue();
std::unique_ptr<InterpolableList> result =
InterpolableList::Create(kTranslateComponentIndexCount);
result->Set(kTranslateX, LengthInterpolationFunctions::MaybeConvertLength(
translate->X(), zoom)
.interpolable_value);
result->Set(kTranslateY, LengthInterpolationFunctions::MaybeConvertLength(
translate->Y(), zoom)
.interpolable_value);
result->Set(kTranslateZ, LengthInterpolationFunctions::MaybeConvertLength(
Length(translate->Z(), kFixed), zoom)
.interpolable_value);
return InterpolationValue(std::move(result));
}
} // namespace
InterpolationValue CSSTranslateInterpolationType::MaybeConvertNeutral(
const InterpolationValue& underlying,
ConversionCheckers&) const {
return InterpolationValue(CreateTranslateIdentity());
}
InterpolationValue CSSTranslateInterpolationType::MaybeConvertInitial(
const StyleResolverState&,
ConversionCheckers&) const {
return CreateNoneValue();
}
InterpolationValue CSSTranslateInterpolationType::MaybeConvertInherit(
const StyleResolverState& state,
ConversionCheckers& conversion_checkers) const {
TranslateTransformOperation* inherited_translate =
state.ParentStyle()->Translate();
conversion_checkers.push_back(
InheritedTranslateChecker::Create(inherited_translate));
return ConvertTranslateOperation(inherited_translate,
state.ParentStyle()->EffectiveZoom());
}
InterpolationValue CSSTranslateInterpolationType::MaybeConvertValue(
const CSSValue& value,
const StyleResolverState*,
ConversionCheckers&) const {
if (!value.IsBaseValueList()) {
return CreateNoneValue();
}
const CSSValueList& list = ToCSSValueList(value);
if (list.length() < 1 || list.length() > 3)
return nullptr;
std::unique_ptr<InterpolableList> result =
InterpolableList::Create(kTranslateComponentIndexCount);
for (wtf_size_t i = 0; i < kTranslateComponentIndexCount; i++) {
InterpolationValue component = nullptr;
if (i < list.length()) {
component =
LengthInterpolationFunctions::MaybeConvertCSSValue(list.Item(i));
if (!component)
return nullptr;
} else {
component = InterpolationValue(
LengthInterpolationFunctions::CreateNeutralInterpolableValue());
}
result->Set(i, std::move(component.interpolable_value));
}
return InterpolationValue(std::move(result));
}
PairwiseInterpolationValue CSSTranslateInterpolationType::MaybeMergeSingles(
InterpolationValue&& start,
InterpolationValue&& end) const {
size_t start_list_length =
ToInterpolableList(*start.interpolable_value).length();
size_t end_list_length = ToInterpolableList(*end.interpolable_value).length();
if (start_list_length < end_list_length)
start.interpolable_value = CreateTranslateIdentity();
else if (end_list_length < start_list_length)
end.interpolable_value = CreateTranslateIdentity();
return PairwiseInterpolationValue(std::move(start.interpolable_value),
std::move(end.interpolable_value));
}
InterpolationValue
CSSTranslateInterpolationType::MaybeConvertStandardPropertyUnderlyingValue(
const ComputedStyle& style) const {
return ConvertTranslateOperation(style.Translate(), style.EffectiveZoom());
}
void CSSTranslateInterpolationType::Composite(
UnderlyingValueOwner& underlying_value_owner,
double underlying_fraction,
const InterpolationValue& value,
double interpolation_fraction) const {
if (IsNoneValue(value)) {
return;
}
if (IsNoneValue(underlying_value_owner.MutableValue())) {
underlying_value_owner.MutableValue().interpolable_value =
CreateTranslateIdentity();
}
return CSSInterpolationType::Composite(underlying_value_owner,
underlying_fraction, value,
interpolation_fraction);
}
void CSSTranslateInterpolationType::ApplyStandardPropertyValue(
const InterpolableValue& interpolable_value,
const NonInterpolableValue*,
StyleResolverState& state) const {
const InterpolableList& list = ToInterpolableList(interpolable_value);
if (list.length() == 0) {
state.Style()->SetTranslate(nullptr);
return;
}
const CSSToLengthConversionData& conversion_data =
state.CssToLengthConversionData();
Length x = LengthInterpolationFunctions::CreateLength(
*list.Get(kTranslateX), nullptr, conversion_data, kValueRangeAll);
Length y = LengthInterpolationFunctions::CreateLength(
*list.Get(kTranslateY), nullptr, conversion_data, kValueRangeAll);
float z =
LengthInterpolationFunctions::CreateLength(
*list.Get(kTranslateZ), nullptr, conversion_data, kValueRangeAll)
.Pixels();
scoped_refptr<TranslateTransformOperation> result =
TranslateTransformOperation::Create(x, y, z,
TransformOperation::kTranslate3D);
state.Style()->SetTranslate(std::move(result));
}
} // namespace blink