| // Copyright 2015 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_length_list_interpolation_type.h" |
| |
| #include <memory> |
| #include <utility> |
| |
| #include "base/memory/ptr_util.h" |
| #include "third_party/blink/renderer/core/animation/interpolable_length.h" |
| #include "third_party/blink/renderer/core/animation/length_list_property_functions.h" |
| #include "third_party/blink/renderer/core/animation/list_interpolation_functions.h" |
| #include "third_party/blink/renderer/core/animation/underlying_length_checker.h" |
| #include "third_party/blink/renderer/core/css/css_primitive_value.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/wtf/functional.h" |
| |
| namespace blink { |
| |
| CSSLengthListInterpolationType::CSSLengthListInterpolationType( |
| PropertyHandle property) |
| : CSSInterpolationType(property), |
| value_range_(LengthListPropertyFunctions::GetValueRange(CssProperty())) {} |
| |
| InterpolationValue CSSLengthListInterpolationType::MaybeConvertNeutral( |
| const InterpolationValue& underlying, |
| ConversionCheckers& conversion_checkers) const { |
| wtf_size_t underlying_length = |
| UnderlyingLengthChecker::GetUnderlyingLength(underlying); |
| conversion_checkers.push_back( |
| std::make_unique<UnderlyingLengthChecker>(underlying_length)); |
| |
| if (underlying_length == 0) |
| return nullptr; |
| |
| return ListInterpolationFunctions::CreateList( |
| underlying_length, [](wtf_size_t) { |
| return InterpolationValue(InterpolableLength::CreateNeutral()); |
| }); |
| } |
| |
| static InterpolationValue MaybeConvertLengthList( |
| const Vector<Length>& length_list, |
| float zoom) { |
| if (length_list.IsEmpty()) |
| return nullptr; |
| |
| return ListInterpolationFunctions::CreateList( |
| length_list.size(), [&length_list, zoom](wtf_size_t index) { |
| return InterpolationValue( |
| InterpolableLength::MaybeConvertLength(length_list[index], zoom)); |
| }); |
| } |
| |
| InterpolationValue CSSLengthListInterpolationType::MaybeConvertInitial( |
| const StyleResolverState&, |
| ConversionCheckers& conversion_checkers) const { |
| Vector<Length> initial_length_list; |
| if (!LengthListPropertyFunctions::GetInitialLengthList(CssProperty(), |
| initial_length_list)) |
| return nullptr; |
| return MaybeConvertLengthList(initial_length_list, 1); |
| } |
| |
| class InheritedLengthListChecker final |
| : public CSSInterpolationType::CSSConversionChecker { |
| public: |
| InheritedLengthListChecker(const CSSProperty& property, |
| const Vector<Length>& inherited_length_list) |
| : property_(property), inherited_length_list_(inherited_length_list) {} |
| ~InheritedLengthListChecker() final = default; |
| |
| private: |
| bool IsValid(const StyleResolverState& state, |
| const InterpolationValue& underlying) const final { |
| Vector<Length> inherited_length_list; |
| LengthListPropertyFunctions::GetLengthList(property_, *state.ParentStyle(), |
| inherited_length_list); |
| return inherited_length_list_ == inherited_length_list; |
| } |
| |
| const CSSProperty& property_; |
| Vector<Length> inherited_length_list_; |
| }; |
| |
| InterpolationValue CSSLengthListInterpolationType::MaybeConvertInherit( |
| const StyleResolverState& state, |
| ConversionCheckers& conversion_checkers) const { |
| Vector<Length> inherited_length_list; |
| bool success = LengthListPropertyFunctions::GetLengthList( |
| CssProperty(), *state.ParentStyle(), inherited_length_list); |
| conversion_checkers.push_back(std::make_unique<InheritedLengthListChecker>( |
| CssProperty(), inherited_length_list)); |
| if (!success) |
| return nullptr; |
| return MaybeConvertLengthList(inherited_length_list, |
| state.ParentStyle()->EffectiveZoom()); |
| } |
| |
| InterpolationValue CSSLengthListInterpolationType::MaybeConvertValue( |
| const CSSValue& value, |
| const StyleResolverState*, |
| ConversionCheckers&) const { |
| if (!value.IsBaseValueList()) |
| return nullptr; |
| |
| const auto& list = To<CSSValueList>(value); |
| return ListInterpolationFunctions::CreateList( |
| list.length(), [&list](wtf_size_t index) { |
| return InterpolationValue( |
| InterpolableLength::MaybeConvertCSSValue(list.Item(index))); |
| }); |
| } |
| |
| PairwiseInterpolationValue CSSLengthListInterpolationType::MaybeMergeSingles( |
| InterpolationValue&& start, |
| InterpolationValue&& end) const { |
| return ListInterpolationFunctions::MaybeMergeSingles( |
| std::move(start), std::move(end), |
| ListInterpolationFunctions::LengthMatchingStrategy::kLowestCommonMultiple, |
| WTF::BindRepeating( |
| [](InterpolationValue&& start_item, InterpolationValue&& end_item) { |
| return InterpolableLength::MergeSingles( |
| std::move(start_item.interpolable_value), |
| std::move(end_item.interpolable_value)); |
| })); |
| } |
| |
| InterpolationValue |
| CSSLengthListInterpolationType::MaybeConvertStandardPropertyUnderlyingValue( |
| const ComputedStyle& style) const { |
| Vector<Length> underlying_length_list; |
| if (!LengthListPropertyFunctions::GetLengthList(CssProperty(), style, |
| underlying_length_list)) |
| return nullptr; |
| return MaybeConvertLengthList(underlying_length_list, style.EffectiveZoom()); |
| } |
| |
| void CSSLengthListInterpolationType::Composite( |
| UnderlyingValueOwner& underlying_value_owner, |
| double underlying_fraction, |
| const InterpolationValue& value, |
| double interpolation_fraction) const { |
| ListInterpolationFunctions::Composite( |
| underlying_value_owner, underlying_fraction, *this, value, |
| ListInterpolationFunctions::LengthMatchingStrategy::kLowestCommonMultiple, |
| WTF::BindRepeating( |
| ListInterpolationFunctions::InterpolableValuesKnownCompatible), |
| WTF::BindRepeating( |
| ListInterpolationFunctions::VerifyNoNonInterpolableValues), |
| WTF::BindRepeating([](UnderlyingValue& underlying_value, |
| double underlying_fraction, |
| const InterpolableValue& interpolable_value, |
| const NonInterpolableValue*) { |
| underlying_value.MutableInterpolableValue().ScaleAndAdd( |
| underlying_fraction, interpolable_value); |
| })); |
| } |
| |
| void CSSLengthListInterpolationType::ApplyStandardPropertyValue( |
| const InterpolableValue& interpolable_value, |
| const NonInterpolableValue* non_interpolable_value, |
| StyleResolverState& state) const { |
| const auto& interpolable_list = To<InterpolableList>(interpolable_value); |
| const wtf_size_t length = interpolable_list.length(); |
| DCHECK_GT(length, 0U); |
| const auto& non_interpolable_list = |
| To<NonInterpolableList>(*non_interpolable_value); |
| DCHECK_EQ(non_interpolable_list.length(), length); |
| Vector<Length> result(length); |
| for (wtf_size_t i = 0; i < length; i++) { |
| result[i] = |
| To<InterpolableLength>(*interpolable_list.Get(i)) |
| .CreateLength(state.CssToLengthConversionData(), value_range_); |
| } |
| LengthListPropertyFunctions::SetLengthList(CssProperty(), *state.Style(), |
| std::move(result)); |
| } |
| |
| } // namespace blink |