Commit 6e152347 authored by Anders Hartvoll Ruud's avatar Anders Hartvoll Ruud Committed by Commit Bot

Introduce UnderlyingValue to avoid mutable NonInterpolableValues

Instead of passing around scoped_refptr<NonInterpolableValue>&, pass
around a virtual UnderlyingValue& which represents the underlying value.
This should allow the internal APIs to cooperate better long term, since
UnderlyingValue can have multiple implementations depending on what's
required by the circumstance.

If ::Composite now wants to modify the NonInterpolableValue, it must
replace the entire value; it can no longer mutate the incoming
scoped_refptr. This property will make it possible to store a
scoped_refptr<const NonInterpolableValue> in InterpolationValue.

A consequence of this is that ListInterpolationFunctions can no longer
modify the underlying NonInterpolableList in-place. Hence

NonInterpolableList::AutoBuilder is added to implement copy-on-write-like
behavior for those lists. (Note that this in-place mutation of the
underlying NonInterpolableList is the main reason why we can't just
store a scoped_refptr<const NonInterpolableValue> in InterpolationValue
in the first place ...)

Bug: 981024
Change-Id: Iadc105beea9ea0006ce638011dd7b3168149449f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1722967
Commit-Queue: Anders Hartvoll Ruud <andruud@chromium.org>
Reviewed-by: default avatarRobert Flack <flackr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#682627}
parent 493550b7
...@@ -239,6 +239,7 @@ blink_core_sources("animation") { ...@@ -239,6 +239,7 @@ blink_core_sources("animation") {
"transition_keyframe.h", "transition_keyframe.h",
"typed_interpolation_value.h", "typed_interpolation_value.h",
"underlying_length_checker.h", "underlying_length_checker.h",
"underlying_value.h",
"underlying_value_owner.cc", "underlying_value_owner.cc",
"underlying_value_owner.h", "underlying_value_owner.h",
"worklet_animation_base.h", "worklet_animation_base.h",
......
...@@ -244,21 +244,19 @@ InterpolationValue ConvertBorderImageLengthBox(const BorderImageLengthBox& box, ...@@ -244,21 +244,19 @@ InterpolationValue ConvertBorderImageLengthBox(const BorderImageLengthBox& box,
}); });
} }
void CompositeSide( void CompositeSide(UnderlyingValue& underlying_value,
std::unique_ptr<InterpolableValue>& underlying_interpolable_value, double underlying_fraction,
scoped_refptr<NonInterpolableValue>& underlying_non_interpolable_value, const InterpolableValue& interpolable_value,
double underlying_fraction, const NonInterpolableValue* non_interpolable_value) {
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) {
switch (GetSideType(non_interpolable_value)) { switch (GetSideType(non_interpolable_value)) {
case SideType::kNumber: case SideType::kNumber:
underlying_interpolable_value->ScaleAndAdd(underlying_fraction, underlying_value.MutableInterpolableValue().ScaleAndAdd(
interpolable_value); underlying_fraction, interpolable_value);
break; break;
case SideType::kLength: case SideType::kLength:
LengthInterpolationFunctions::Composite( LengthInterpolationFunctions::CompositeUnderlying(
underlying_interpolable_value, underlying_non_interpolable_value, underlying_value, underlying_fraction, interpolable_value,
underlying_fraction, interpolable_value, non_interpolable_value); non_interpolable_value);
break; break;
case SideType::kAuto: case SideType::kAuto:
break; break;
......
...@@ -145,7 +145,7 @@ void CSSLengthListInterpolationType::Composite( ...@@ -145,7 +145,7 @@ void CSSLengthListInterpolationType::Composite(
ListInterpolationFunctions::LengthMatchingStrategy::kLowestCommonMultiple, ListInterpolationFunctions::LengthMatchingStrategy::kLowestCommonMultiple,
WTF::BindRepeating( WTF::BindRepeating(
LengthInterpolationFunctions::NonInterpolableValuesAreCompatible), LengthInterpolationFunctions::NonInterpolableValuesAreCompatible),
WTF::BindRepeating(LengthInterpolationFunctions::Composite)); WTF::BindRepeating(LengthInterpolationFunctions::CompositeUnderlying));
} }
void CSSLengthListInterpolationType::ApplyStandardPropertyValue( void CSSLengthListInterpolationType::ApplyStandardPropertyValue(
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
#include "third_party/blink/renderer/core/animation/length_interpolation_functions.h" #include "third_party/blink/renderer/core/animation/length_interpolation_functions.h"
#include "third_party/blink/renderer/core/animation/underlying_value.h"
#include "third_party/blink/renderer/core/css/css_math_expression_node.h" #include "third_party/blink/renderer/core/css/css_math_expression_node.h"
#include "third_party/blink/renderer/core/css/css_math_function_value.h" #include "third_party/blink/renderer/core/css/css_math_function_value.h"
#include "third_party/blink/renderer/core/css/css_numeric_literal_value.h" #include "third_party/blink/renderer/core/css/css_numeric_literal_value.h"
...@@ -153,6 +154,21 @@ void LengthInterpolationFunctions::Composite( ...@@ -153,6 +154,21 @@ void LengthInterpolationFunctions::Composite(
underlying_non_interpolable_value.get(), non_interpolable_value); underlying_non_interpolable_value.get(), non_interpolable_value);
} }
void LengthInterpolationFunctions::CompositeUnderlying(
UnderlyingValue& underlying_value,
double underlying_fraction,
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) {
underlying_value.MutableInterpolableValue().ScaleAndAdd(underlying_fraction,
interpolable_value);
const auto merged = CSSLengthNonInterpolableValue::Merge(
underlying_value.GetNonInterpolableValue(), non_interpolable_value);
if (HasPercentage(underlying_value.GetNonInterpolableValue()) !=
HasPercentage(merged.get())) {
underlying_value.SetNonInterpolableValue(merged);
}
}
void LengthInterpolationFunctions::SubtractFromOneHundredPercent( void LengthInterpolationFunctions::SubtractFromOneHundredPercent(
InterpolationValue& result) { InterpolationValue& result) {
InterpolableList& list = ToInterpolableList(*result.interpolable_value); InterpolableList& list = ToInterpolableList(*result.interpolable_value);
......
...@@ -14,6 +14,7 @@ namespace blink { ...@@ -14,6 +14,7 @@ namespace blink {
class CSSToLengthConversionData; class CSSToLengthConversionData;
class CSSValue; class CSSValue;
class UnderlyingValue;
class LengthInterpolationFunctions { class LengthInterpolationFunctions {
STATIC_ONLY(LengthInterpolationFunctions); STATIC_ONLY(LengthInterpolationFunctions);
...@@ -31,11 +32,16 @@ class LengthInterpolationFunctions { ...@@ -31,11 +32,16 @@ class LengthInterpolationFunctions {
static bool NonInterpolableValuesAreCompatible(const NonInterpolableValue*, static bool NonInterpolableValuesAreCompatible(const NonInterpolableValue*,
const NonInterpolableValue*); const NonInterpolableValue*);
static bool HasPercentage(const NonInterpolableValue*); static bool HasPercentage(const NonInterpolableValue*);
// TODO(andruud): Unify these Composite* functions.
static void Composite(std::unique_ptr<InterpolableValue>&, static void Composite(std::unique_ptr<InterpolableValue>&,
scoped_refptr<NonInterpolableValue>&, scoped_refptr<NonInterpolableValue>&,
double underlying_fraction, double underlying_fraction,
const InterpolableValue&, const InterpolableValue&,
const NonInterpolableValue*); const NonInterpolableValue*);
static void CompositeUnderlying(UnderlyingValue&,
double underlying_fraction,
const InterpolableValue&,
const NonInterpolableValue*);
static Length CreateLength(const InterpolableValue&, static Length CreateLength(const InterpolableValue&,
const NonInterpolableValue*, const NonInterpolableValue*,
const CSSToLengthConversionData&, const CSSToLengthConversionData&,
......
...@@ -16,6 +16,40 @@ DEFINE_NON_INTERPOLABLE_VALUE_TYPE(NonInterpolableList); ...@@ -16,6 +16,40 @@ DEFINE_NON_INTERPOLABLE_VALUE_TYPE(NonInterpolableList);
const wtf_size_t kRepeatableListMaxLength = 1000; const wtf_size_t kRepeatableListMaxLength = 1000;
// An UnderlyingValue used for compositing list items.
//
// When new NonInterpolableValues are set, the NonInterpolableList::AutoBuilder
// is modified at the corresponding index. The NonInterpolableValue of the
// underlying_list is updated when the AutoBuilder goes out of scope (if
// any calls to UnderlyingItemValue::SetNonInterpolableValue were made).
class UnderlyingItemValue : public UnderlyingValue {
STACK_ALLOCATED();
public:
UnderlyingItemValue(UnderlyingValue& underlying_list,
NonInterpolableList::AutoBuilder& builder,
wtf_size_t index)
: underlying_list_(underlying_list), builder_(builder), index_(index) {}
InterpolableValue& MutableInterpolableValue() final {
return *ToInterpolableList(underlying_list_.MutableInterpolableValue())
.GetMutable(index_);
}
const NonInterpolableValue* GetNonInterpolableValue() const final {
return ToNonInterpolableList(*underlying_list_.GetNonInterpolableValue())
.Get(index_);
}
void SetNonInterpolableValue(
scoped_refptr<NonInterpolableValue> non_interpolable_value) final {
builder_.Set(index_, std::move(non_interpolable_value));
}
private:
UnderlyingValue& underlying_list_;
NonInterpolableList::AutoBuilder& builder_;
wtf_size_t index_;
};
bool ListInterpolationFunctions::EqualValues( bool ListInterpolationFunctions::EqualValues(
const InterpolationValue& a, const InterpolationValue& a,
const InterpolationValue& b, const InterpolationValue& b,
...@@ -319,15 +353,15 @@ void ListInterpolationFunctions::Composite( ...@@ -319,15 +353,15 @@ void ListInterpolationFunctions::Composite(
if (underlying_length < final_length) { if (underlying_length < final_length) {
RepeatToLength(underlying_value, final_length); RepeatToLength(underlying_value, final_length);
} }
InterpolableList& underlying_interpolable_list =
ToInterpolableList(*underlying_value.interpolable_value);
NonInterpolableList& underlying_non_interpolable_list = NonInterpolableList& underlying_non_interpolable_list =
ToNonInterpolableList(*underlying_value.non_interpolable_value); ToNonInterpolableList(*underlying_value.non_interpolable_value);
NonInterpolableList::AutoBuilder builder(underlying_value_owner,
underlying_non_interpolable_list);
for (wtf_size_t i = 0; i < final_length; i++) { for (wtf_size_t i = 0; i < final_length; i++) {
composite_item.Run(underlying_interpolable_list.GetMutable(i), UnderlyingItemValue underlying_item(underlying_value_owner, builder, i);
underlying_non_interpolable_list.GetMutable(i), composite_item.Run(underlying_item, underlying_fraction,
underlying_fraction,
*interpolable_list.Get(i % value_length), *interpolable_list.Get(i % value_length),
non_interpolable_list.Get(i % value_length)); non_interpolable_list.Get(i % value_length));
} }
...@@ -345,10 +379,13 @@ void ListInterpolationFunctions::Composite( ...@@ -345,10 +379,13 @@ void ListInterpolationFunctions::Composite(
NonInterpolableList& underlying_non_interpolable_list = NonInterpolableList& underlying_non_interpolable_list =
ToNonInterpolableList(*underlying_value.non_interpolable_value); ToNonInterpolableList(*underlying_value.non_interpolable_value);
NonInterpolableList::AutoBuilder builder(underlying_value_owner,
underlying_non_interpolable_list);
for (wtf_size_t i = 0; i < value_length; i++) { for (wtf_size_t i = 0; i < value_length; i++) {
composite_item.Run(underlying_interpolable_list.GetMutable(i), UnderlyingItemValue underlying_item(underlying_value_owner, builder, i);
underlying_non_interpolable_list.GetMutable(i), composite_item.Run(underlying_item, underlying_fraction,
underlying_fraction, *interpolable_list.Get(i), *interpolable_list.Get(i),
non_interpolable_list.Get(i)); non_interpolable_list.Get(i));
} }
for (wtf_size_t i = value_length; i < final_length; i++) { for (wtf_size_t i = value_length; i < final_length; i++) {
...@@ -357,4 +394,39 @@ void ListInterpolationFunctions::Composite( ...@@ -357,4 +394,39 @@ void ListInterpolationFunctions::Composite(
} }
} }
NonInterpolableList::AutoBuilder::AutoBuilder(
UnderlyingValue& underlying_value,
NonInterpolableList& underlying_non_interpolable_list)
: underlying_value_(underlying_value),
underlying_non_interpolable_list_(underlying_non_interpolable_list) {
DCHECK(underlying_value.GetNonInterpolableValue());
DCHECK(IsNonInterpolableList(underlying_value_.GetNonInterpolableValue()));
}
NonInterpolableList::AutoBuilder::~AutoBuilder() {
// If no call to Set ever happened, there is no need to modify
// underlying_value_.
if (!list_.size())
return;
const auto& non_interpolable_list =
ToNonInterpolableList(*underlying_value_.GetNonInterpolableValue());
DCHECK_EQ(non_interpolable_list.length(), list_.size());
underlying_value_.SetNonInterpolableValue(
NonInterpolableList::Create(std::move(list_)));
}
void NonInterpolableList::AutoBuilder::Set(
wtf_size_t index,
scoped_refptr<NonInterpolableValue> non_interpolable_value) {
// Copy list on first call to Set.
if (!list_.size()) {
wtf_size_t underlying_length = underlying_non_interpolable_list_.length();
for (wtf_size_t i = 0; i < underlying_length; ++i)
list_.push_back(underlying_non_interpolable_list_.Get(i));
}
DCHECK_LT(index, list_.size());
list_[index] = non_interpolable_value;
}
} // namespace blink } // namespace blink
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
namespace blink { namespace blink {
class UnderlyingValue;
class UnderlyingValueOwner; class UnderlyingValueOwner;
class InterpolationType; class InterpolationType;
...@@ -52,8 +53,7 @@ class CORE_EXPORT ListInterpolationFunctions { ...@@ -52,8 +53,7 @@ class CORE_EXPORT ListInterpolationFunctions {
base::RepeatingCallback<bool(const NonInterpolableValue*, base::RepeatingCallback<bool(const NonInterpolableValue*,
const NonInterpolableValue*)>; const NonInterpolableValue*)>;
using CompositeItemCallback = using CompositeItemCallback =
base::RepeatingCallback<void(std::unique_ptr<InterpolableValue>&, base::RepeatingCallback<void(UnderlyingValue&,
scoped_refptr<NonInterpolableValue>&,
double underlying_fraction, double underlying_fraction,
const InterpolableValue&, const InterpolableValue&,
const NonInterpolableValue*)>; const NonInterpolableValue*)>;
...@@ -83,9 +83,29 @@ class CORE_EXPORT NonInterpolableList : public NonInterpolableValue { ...@@ -83,9 +83,29 @@ class CORE_EXPORT NonInterpolableList : public NonInterpolableValue {
return list_[index].get(); return list_[index].get();
} }
NonInterpolableValue* Get(wtf_size_t index) { return list_[index].get(); } NonInterpolableValue* Get(wtf_size_t index) { return list_[index].get(); }
scoped_refptr<NonInterpolableValue>& GetMutable(wtf_size_t index) {
return list_[index]; // This class can update the NonInterpolableList of an UnderlyingValue with
} // a series of mutations. The actual update of the list is delayed until the
// AutoBuilder object goes out of scope, to avoid creating a new list for
// every call to Set().
class CORE_EXPORT AutoBuilder {
STACK_ALLOCATED();
public:
// The UnderlyingValue provided here is assumed to contain a
// non-nullptr NonInterpolableList.
//
// TODO(andruud): Remove NonInterpolableList& param.
AutoBuilder(UnderlyingValue&, NonInterpolableList&);
~AutoBuilder();
void Set(wtf_size_t index, scoped_refptr<NonInterpolableValue>);
private:
UnderlyingValue& underlying_value_;
NonInterpolableList& underlying_non_interpolable_list_;
Vector<scoped_refptr<NonInterpolableValue>> list_;
};
DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
#include "third_party/blink/renderer/core/animation/css_number_interpolation_type.h" #include "third_party/blink/renderer/core/animation/css_number_interpolation_type.h"
#include "third_party/blink/renderer/core/animation/interpolation_value.h" #include "third_party/blink/renderer/core/animation/interpolation_value.h"
#include "third_party/blink/renderer/core/animation/underlying_value.h"
#include "third_party/blink/renderer/platform/wtf/functional.h" #include "third_party/blink/renderer/platform/wtf/functional.h"
namespace blink { namespace blink {
...@@ -43,6 +44,30 @@ inline const TestNonInterpolableValue& ToTestNonInterpolableValue( ...@@ -43,6 +44,30 @@ inline const TestNonInterpolableValue& ToTestNonInterpolableValue(
return static_cast<const TestNonInterpolableValue&>(value); return static_cast<const TestNonInterpolableValue&>(value);
} }
class TestUnderlyingValue : public UnderlyingValue {
STACK_ALLOCATED();
public:
TestUnderlyingValue(InterpolationValue& interpolation_value)
: interpolation_value_(interpolation_value) {}
InterpolableValue& MutableInterpolableValue() final {
return *interpolation_value_.interpolable_value;
}
const NonInterpolableValue* GetNonInterpolableValue() const final {
return interpolation_value_.non_interpolable_value.get();
}
void SetNonInterpolableValue(
scoped_refptr<NonInterpolableValue> non_interpolable_value) final {
interpolation_value_.non_interpolable_value = non_interpolable_value;
}
private:
InterpolationValue& interpolation_value_;
};
// Creates an InterpolationValue containing a list of interpolable and // Creates an InterpolationValue containing a list of interpolable and
// non-interpolable values from the pairs of input. // non-interpolable values from the pairs of input.
InterpolationValue CreateInterpolableList( InterpolationValue CreateInterpolableList(
...@@ -65,6 +90,16 @@ InterpolationValue CreateInterpolableList(const Vector<double>& values) { ...@@ -65,6 +90,16 @@ InterpolationValue CreateInterpolableList(const Vector<double>& values) {
}); });
} }
// Creates an InterpolationValue which contains a list of non-interpolable
// values, but an interpolable list of zeroes.
InterpolationValue CreateNonInterpolableList(const Vector<int>& values) {
return ListInterpolationFunctions::CreateList(
values.size(), [&values](size_t i) {
return InterpolationValue(std::make_unique<InterpolableNumber>(0),
TestNonInterpolableValue::Create(values[i]));
});
}
bool NonInterpolableValuesAreCompatible(const NonInterpolableValue* a, bool NonInterpolableValuesAreCompatible(const NonInterpolableValue* a,
const NonInterpolableValue* b) { const NonInterpolableValue* b) {
return (a ? ToTestNonInterpolableValue(*a).GetValue() : 0) == return (a ? ToTestNonInterpolableValue(*a).GetValue() : 0) ==
...@@ -81,16 +116,14 @@ PairwiseInterpolationValue MaybeMergeSingles(InterpolationValue&& start, ...@@ -81,16 +116,14 @@ PairwiseInterpolationValue MaybeMergeSingles(InterpolationValue&& start,
std::move(end.interpolable_value), nullptr); std::move(end.interpolable_value), nullptr);
} }
void Composite( void Composite(UnderlyingValue& underlying_value,
std::unique_ptr<InterpolableValue>& underlying_interpolable_value, double underlying_fraction,
scoped_refptr<NonInterpolableValue>& underlying_non_interpolable_value, const InterpolableValue& interpolable_value,
double underlying_fraction, const NonInterpolableValue* non_interpolable_value) {
const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) {
DCHECK(NonInterpolableValuesAreCompatible( DCHECK(NonInterpolableValuesAreCompatible(
underlying_non_interpolable_value.get(), non_interpolable_value)); underlying_value.GetNonInterpolableValue(), non_interpolable_value));
underlying_interpolable_value->ScaleAndAdd(underlying_fraction, underlying_value.MutableInterpolableValue().ScaleAndAdd(underlying_fraction,
interpolable_value); interpolable_value);
} }
} // namespace } // namespace
...@@ -215,4 +248,138 @@ TEST(ListInterpolationFunctionsTest, EqualCompositeIncompatibleValues) { ...@@ -215,4 +248,138 @@ TEST(ListInterpolationFunctionsTest, EqualCompositeIncompatibleValues) {
EXPECT_EQ(ToInterpolableNumber(result.Get(2))->Value(), 6.0); EXPECT_EQ(ToInterpolableNumber(result.Get(2))->Value(), 6.0);
} }
TEST(ListInterpolationFunctionsTest, BuilderNoModify) {
auto list = CreateNonInterpolableList({1, 2, 3});
auto& before = ToNonInterpolableList(*list.non_interpolable_value);
{
TestUnderlyingValue underlying_value(list);
NonInterpolableList::AutoBuilder builder(underlying_value, before);
}
auto& after = ToNonInterpolableList(*list.non_interpolable_value);
EXPECT_EQ(&before, &after);
ASSERT_EQ(3u, before.length());
EXPECT_EQ(1, ToTestNonInterpolableValue(*before.Get(0)).GetValue());
EXPECT_EQ(2, ToTestNonInterpolableValue(*before.Get(1)).GetValue());
EXPECT_EQ(3, ToTestNonInterpolableValue(*before.Get(2)).GetValue());
}
TEST(ListInterpolationFunctionsTest, BuilderModifyFirst) {
auto list = CreateNonInterpolableList({1, 2, 3});
auto& before = ToNonInterpolableList(*list.non_interpolable_value);
{
TestUnderlyingValue underlying_value(list);
NonInterpolableList::AutoBuilder builder(underlying_value, before);
builder.Set(0, TestNonInterpolableValue::Create(4));
}
auto& after = ToNonInterpolableList(*list.non_interpolable_value);
EXPECT_NE(&before, &after);
ASSERT_EQ(3u, after.length());
EXPECT_EQ(4, ToTestNonInterpolableValue(*after.Get(0)).GetValue());
EXPECT_EQ(2, ToTestNonInterpolableValue(*after.Get(1)).GetValue());
EXPECT_EQ(3, ToTestNonInterpolableValue(*after.Get(2)).GetValue());
}
TEST(ListInterpolationFunctionsTest, BuilderModifyMiddle) {
auto list = CreateNonInterpolableList({1, 2, 3});
auto& before = ToNonInterpolableList(*list.non_interpolable_value);
{
TestUnderlyingValue underlying_value(list);
NonInterpolableList::AutoBuilder builder(underlying_value, before);
builder.Set(1, TestNonInterpolableValue::Create(4));
}
auto& after = ToNonInterpolableList(*list.non_interpolable_value);
EXPECT_NE(&before, &after);
ASSERT_EQ(3u, after.length());
EXPECT_EQ(1, ToTestNonInterpolableValue(*after.Get(0)).GetValue());
EXPECT_EQ(4, ToTestNonInterpolableValue(*after.Get(1)).GetValue());
EXPECT_EQ(3, ToTestNonInterpolableValue(*after.Get(2)).GetValue());
}
TEST(ListInterpolationFunctionsTest, BuilderModifyLast) {
auto list = CreateNonInterpolableList({1, 2, 3});
auto& before = ToNonInterpolableList(*list.non_interpolable_value);
{
TestUnderlyingValue underlying_value(list);
NonInterpolableList::AutoBuilder builder(underlying_value, before);
builder.Set(2, TestNonInterpolableValue::Create(4));
}
auto& after = ToNonInterpolableList(*list.non_interpolable_value);
EXPECT_NE(&before, &after);
ASSERT_EQ(3u, after.length());
EXPECT_EQ(1, ToTestNonInterpolableValue(*after.Get(0)).GetValue());
EXPECT_EQ(2, ToTestNonInterpolableValue(*after.Get(1)).GetValue());
EXPECT_EQ(4, ToTestNonInterpolableValue(*after.Get(2)).GetValue());
}
TEST(ListInterpolationFunctionsTest, BuilderModifyAll) {
auto list = CreateNonInterpolableList({1, 2, 3});
auto& before = ToNonInterpolableList(*list.non_interpolable_value);
{
TestUnderlyingValue underlying_value(list);
NonInterpolableList::AutoBuilder builder(underlying_value, before);
builder.Set(0, TestNonInterpolableValue::Create(4));
builder.Set(1, TestNonInterpolableValue::Create(5));
builder.Set(2, TestNonInterpolableValue::Create(6));
}
auto& after = ToNonInterpolableList(*list.non_interpolable_value);
EXPECT_NE(&before, &after);
ASSERT_EQ(3u, after.length());
EXPECT_EQ(4, ToTestNonInterpolableValue(*after.Get(0)).GetValue());
EXPECT_EQ(5, ToTestNonInterpolableValue(*after.Get(1)).GetValue());
EXPECT_EQ(6, ToTestNonInterpolableValue(*after.Get(2)).GetValue());
}
TEST(ListInterpolationFunctionsTest, BuilderModifyReverse) {
auto list = CreateNonInterpolableList({1, 2, 3, 4, 5});
auto& before = ToNonInterpolableList(*list.non_interpolable_value);
{
TestUnderlyingValue underlying_value(list);
NonInterpolableList::AutoBuilder builder(underlying_value, before);
builder.Set(3, TestNonInterpolableValue::Create(6));
builder.Set(1, TestNonInterpolableValue::Create(7));
}
auto& after = ToNonInterpolableList(*list.non_interpolable_value);
EXPECT_NE(&before, &after);
ASSERT_EQ(5u, after.length());
EXPECT_EQ(1, ToTestNonInterpolableValue(*after.Get(0)).GetValue());
EXPECT_EQ(7, ToTestNonInterpolableValue(*after.Get(1)).GetValue());
EXPECT_EQ(3, ToTestNonInterpolableValue(*after.Get(2)).GetValue());
EXPECT_EQ(6, ToTestNonInterpolableValue(*after.Get(3)).GetValue());
EXPECT_EQ(5, ToTestNonInterpolableValue(*after.Get(4)).GetValue());
}
TEST(ListInterpolationFunctionsTest, BuilderModifyListWithOneItem) {
auto list = CreateNonInterpolableList({1});
auto& before = ToNonInterpolableList(*list.non_interpolable_value);
{
TestUnderlyingValue underlying_value(list);
NonInterpolableList::AutoBuilder builder(underlying_value, before);
builder.Set(0, TestNonInterpolableValue::Create(4));
}
auto& after = ToNonInterpolableList(*list.non_interpolable_value);
EXPECT_NE(&before, &after);
EXPECT_EQ(4, ToTestNonInterpolableValue(*after.Get(0)).GetValue());
}
} // namespace blink } // namespace blink
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "third_party/blink/renderer/core/animation/interpolation_value.h" #include "third_party/blink/renderer/core/animation/interpolation_value.h"
#include "third_party/blink/renderer/core/animation/length_interpolation_functions.h" #include "third_party/blink/renderer/core/animation/length_interpolation_functions.h"
#include "third_party/blink/renderer/core/animation/non_interpolable_value.h" #include "third_party/blink/renderer/core/animation/non_interpolable_value.h"
#include "third_party/blink/renderer/core/animation/underlying_value.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h" #include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_shadow_value.h" #include "third_party/blink/renderer/core/css/css_shadow_value.h"
#include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h" #include "third_party/blink/renderer/core/css/resolver/style_resolver_state.h"
...@@ -153,15 +154,14 @@ ShadowInterpolationFunctions::CreateNeutralInterpolableValue() { ...@@ -153,15 +154,14 @@ ShadowInterpolationFunctions::CreateNeutralInterpolableValue() {
} }
void ShadowInterpolationFunctions::Composite( void ShadowInterpolationFunctions::Composite(
std::unique_ptr<InterpolableValue>& underlying_interpolable_value, UnderlyingValue& underlying_value,
scoped_refptr<NonInterpolableValue>& underlying_non_interpolable_value,
double underlying_fraction, double underlying_fraction,
const InterpolableValue& interpolable_value, const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) { const NonInterpolableValue* non_interpolable_value) {
DCHECK(NonInterpolableValuesAreCompatible( DCHECK(NonInterpolableValuesAreCompatible(
underlying_non_interpolable_value.get(), non_interpolable_value)); underlying_value.GetNonInterpolableValue(), non_interpolable_value));
InterpolableList& underlying_interpolable_list = InterpolableList& underlying_interpolable_list =
ToInterpolableList(*underlying_interpolable_value); ToInterpolableList(underlying_value.MutableInterpolableValue());
const InterpolableList& interpolable_list = const InterpolableList& interpolable_list =
ToInterpolableList(interpolable_value); ToInterpolableList(interpolable_value);
underlying_interpolable_list.ScaleAndAdd(underlying_fraction, underlying_interpolable_list.ScaleAndAdd(underlying_fraction,
......
...@@ -14,6 +14,7 @@ namespace blink { ...@@ -14,6 +14,7 @@ namespace blink {
class ShadowData; class ShadowData;
class CSSValue; class CSSValue;
class StyleResolverState; class StyleResolverState;
class UnderlyingValue;
class ShadowInterpolationFunctions { class ShadowInterpolationFunctions {
public: public:
...@@ -25,8 +26,7 @@ class ShadowInterpolationFunctions { ...@@ -25,8 +26,7 @@ class ShadowInterpolationFunctions {
static PairwiseInterpolationValue MaybeMergeSingles( static PairwiseInterpolationValue MaybeMergeSingles(
InterpolationValue&& start, InterpolationValue&& start,
InterpolationValue&& end); InterpolationValue&& end);
static void Composite(std::unique_ptr<InterpolableValue>&, static void Composite(UnderlyingValue&,
scoped_refptr<NonInterpolableValue>&,
double underlying_fraction, double underlying_fraction,
const InterpolableValue&, const InterpolableValue&,
const NonInterpolableValue*); const NonInterpolableValue*);
......
...@@ -34,10 +34,6 @@ class CSSSizeNonInterpolableValue : public NonInterpolableValue { ...@@ -34,10 +34,6 @@ class CSSSizeNonInterpolableValue : public NonInterpolableValue {
DCHECK(!IsKeyword()); DCHECK(!IsKeyword());
return length_non_interpolable_value_.get(); return length_non_interpolable_value_.get();
} }
scoped_refptr<NonInterpolableValue>& LengthNonInterpolableValue() {
DCHECK(!IsKeyword());
return length_non_interpolable_value_;
}
DECLARE_NON_INTERPOLABLE_VALUE_TYPE(); DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
...@@ -60,6 +56,41 @@ class CSSSizeNonInterpolableValue : public NonInterpolableValue { ...@@ -60,6 +56,41 @@ class CSSSizeNonInterpolableValue : public NonInterpolableValue {
DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSSizeNonInterpolableValue); DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSSizeNonInterpolableValue);
DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSSizeNonInterpolableValue); DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSSizeNonInterpolableValue);
// A wrapper for the UnderlyingValue passed to
// SizeInterpolationFunctions::Composite which can be forwarded to
// LengthInterpolationFunctions::CompositeUnderlying.
//
// If LengthInterpolationFunctions::CompositeUnderlying calls
// SetNonInterpolableValue with a new NonInterpolableValue, this class
// wraps it in a new CSSSizeNonInterpolableValue before being set on the inner
// UnderlyingValue.
class UnderlyingSizeAsLengthValue : public UnderlyingValue {
STACK_ALLOCATED();
public:
UnderlyingSizeAsLengthValue(UnderlyingValue& inner_underlying_value)
: inner_underlying_value_(inner_underlying_value) {}
InterpolableValue& MutableInterpolableValue() final {
return inner_underlying_value_.MutableInterpolableValue();
}
const NonInterpolableValue* GetNonInterpolableValue() const final {
const auto& size_non_interpolable_value = ToCSSSizeNonInterpolableValue(
*inner_underlying_value_.GetNonInterpolableValue());
return size_non_interpolable_value.LengthNonInterpolableValue();
}
void SetNonInterpolableValue(
scoped_refptr<NonInterpolableValue> non_interpolable_value) final {
inner_underlying_value_.SetNonInterpolableValue(
CSSSizeNonInterpolableValue::Create(std::move(non_interpolable_value)));
}
private:
UnderlyingValue& inner_underlying_value_;
};
static InterpolationValue ConvertKeyword(CSSValueID keyword) { static InterpolationValue ConvertKeyword(CSSValueID keyword) {
return InterpolationValue(std::make_unique<InterpolableList>(0), return InterpolationValue(std::make_unique<InterpolableList>(0),
CSSSizeNonInterpolableValue::Create(keyword)); CSSSizeNonInterpolableValue::Create(keyword));
...@@ -157,8 +188,7 @@ bool SizeInterpolationFunctions::NonInterpolableValuesAreCompatible( ...@@ -157,8 +188,7 @@ bool SizeInterpolationFunctions::NonInterpolableValuesAreCompatible(
} }
void SizeInterpolationFunctions::Composite( void SizeInterpolationFunctions::Composite(
std::unique_ptr<InterpolableValue>& underlying_interpolable_value, UnderlyingValue& underlying_value,
scoped_refptr<NonInterpolableValue>& underlying_non_interpolable_value,
double underlying_fraction, double underlying_fraction,
const InterpolableValue& interpolable_value, const InterpolableValue& interpolable_value,
const NonInterpolableValue* non_interpolable_value) { const NonInterpolableValue* non_interpolable_value) {
...@@ -166,12 +196,9 @@ void SizeInterpolationFunctions::Composite( ...@@ -166,12 +196,9 @@ void SizeInterpolationFunctions::Composite(
ToCSSSizeNonInterpolableValue(*non_interpolable_value); ToCSSSizeNonInterpolableValue(*non_interpolable_value);
if (size_non_interpolable_value.IsKeyword()) if (size_non_interpolable_value.IsKeyword())
return; return;
auto& underlying_size_non_interpolable_value = UnderlyingSizeAsLengthValue underlying_size_as_length(underlying_value);
ToCSSSizeNonInterpolableValue(*underlying_non_interpolable_value); LengthInterpolationFunctions::CompositeUnderlying(
LengthInterpolationFunctions::Composite( underlying_size_as_length, underlying_fraction, interpolable_value,
underlying_interpolable_value,
underlying_size_non_interpolable_value.LengthNonInterpolableValue(),
underlying_fraction, interpolable_value,
size_non_interpolable_value.LengthNonInterpolableValue()); size_non_interpolable_value.LengthNonInterpolableValue());
} }
......
...@@ -14,6 +14,7 @@ namespace blink { ...@@ -14,6 +14,7 @@ namespace blink {
class CSSToLengthConversionData; class CSSToLengthConversionData;
class CSSValue; class CSSValue;
class UnderlyingValue;
class SizeInterpolationFunctions { class SizeInterpolationFunctions {
STATIC_ONLY(SizeInterpolationFunctions); STATIC_ONLY(SizeInterpolationFunctions);
...@@ -30,8 +31,7 @@ class SizeInterpolationFunctions { ...@@ -30,8 +31,7 @@ class SizeInterpolationFunctions {
static InterpolationValue CreateNeutralValue(const NonInterpolableValue*); static InterpolationValue CreateNeutralValue(const NonInterpolableValue*);
static bool NonInterpolableValuesAreCompatible(const NonInterpolableValue*, static bool NonInterpolableValuesAreCompatible(const NonInterpolableValue*,
const NonInterpolableValue*); const NonInterpolableValue*);
static void Composite(std::unique_ptr<InterpolableValue>&, static void Composite(UnderlyingValue&,
scoped_refptr<NonInterpolableValue>&,
double underlying_fraction, double underlying_fraction,
const InterpolableValue&, const InterpolableValue&,
const NonInterpolableValue*); const NonInterpolableValue*);
......
// Copyright 2019 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.
#ifndef THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_UNDERLYING_VALUE_H_
#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_UNDERLYING_VALUE_H_
#include "third_party/blink/renderer/core/core_export.h"
namespace blink {
class InterpolableValue;
class NonInterpolableValue;
// Represents the 'underlying value' modified by an 'effect stack'.
//
// This is a virtual class because the representation of the underlying
// value may vary depending on circumstance. See UnderlyingValueOwner,
// and UnderlyingItemValue.
//
// https://drafts.csswg.org/web-animations-1/#underlying-value
// https://drafts.csswg.org/web-animations-1/#effect-stack
class CORE_EXPORT UnderlyingValue {
public:
virtual InterpolableValue& MutableInterpolableValue() = 0;
virtual const NonInterpolableValue* GetNonInterpolableValue() const = 0;
// The NonInterpolableValue part of the underlying value may not be mutated,
// hence there is no MutableNonInterpolableValue function. However, the
// NonInterpolableValue part may be replaced entirely with this function.
virtual void SetNonInterpolableValue(scoped_refptr<NonInterpolableValue>) = 0;
};
} // namespace blink
#endif // THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_UNDERLYING_VALUE_H_
...@@ -13,6 +13,21 @@ struct NullValueWrapper { ...@@ -13,6 +13,21 @@ struct NullValueWrapper {
const InterpolationValue value; const InterpolationValue value;
}; };
InterpolableValue& UnderlyingValueOwner::MutableInterpolableValue() {
return *MutableValue().interpolable_value;
}
const NonInterpolableValue* UnderlyingValueOwner::GetNonInterpolableValue()
const {
DCHECK(value_);
return value_->non_interpolable_value.get();
}
void UnderlyingValueOwner::SetNonInterpolableValue(
scoped_refptr<NonInterpolableValue> non_interpolable_value) {
MutableValue().non_interpolable_value = non_interpolable_value;
}
const InterpolationValue& UnderlyingValueOwner::Value() const { const InterpolationValue& UnderlyingValueOwner::Value() const {
DEFINE_STATIC_LOCAL(NullValueWrapper, null_value_wrapper, ()); DEFINE_STATIC_LOCAL(NullValueWrapper, null_value_wrapper, ());
return *this ? *value_ : null_value_wrapper.value; return *this ? *value_ : null_value_wrapper.value;
......
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "base/macros.h" #include "base/macros.h"
#include "third_party/blink/renderer/core/animation/typed_interpolation_value.h" #include "third_party/blink/renderer/core/animation/typed_interpolation_value.h"
#include "third_party/blink/renderer/core/animation/underlying_value.h"
#include "third_party/blink/renderer/core/core_export.h" #include "third_party/blink/renderer/core/core_export.h"
#include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h"
...@@ -18,7 +19,7 @@ namespace blink { ...@@ -18,7 +19,7 @@ namespace blink {
// Ensures we perform copy on write if we are not the owner of an underlying // Ensures we perform copy on write if we are not the owner of an underlying
// InterpolationValue. This functions similar to a DataRef except on // InterpolationValue. This functions similar to a DataRef except on
// std::unique_ptr'd objects. // std::unique_ptr'd objects.
class CORE_EXPORT UnderlyingValueOwner { class CORE_EXPORT UnderlyingValueOwner : public UnderlyingValue {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
...@@ -30,6 +31,11 @@ class CORE_EXPORT UnderlyingValueOwner { ...@@ -30,6 +31,11 @@ class CORE_EXPORT UnderlyingValueOwner {
return type_; return type_;
} }
// UnderlyingValue
InterpolableValue& MutableInterpolableValue() final;
const NonInterpolableValue* GetNonInterpolableValue() const final;
void SetNonInterpolableValue(scoped_refptr<NonInterpolableValue>) final;
const InterpolationType& GetType() const { const InterpolationType& GetType() const {
DCHECK(type_); DCHECK(type_);
return *type_; return *type_;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment