Commit 243148b0 authored by Stephen McGruer's avatar Stephen McGruer Committed by Commit Bot

Web Animations: use WTF::Optional for Keyframe::offset_

Previously nullable values in the animations code were tracked by
storing nulls as quiet_NaN() and using std::isnan as a null-detector.
It is much more explicit to store such values using WTF::Optional, which
forces code to consider whether or not the offset exists.

Bug: 791086
Change-Id: I4db0457b593d6be61dedb5c13a9daf8b671206b0
Reviewed-on: https://chromium-review.googlesource.com/804116Reviewed-by: default avatarEric Willigers <ericwilligers@chromium.org>
Reviewed-by: default avatarAndrey Kosyakov <caseq@chromium.org>
Commit-Queue: Stephen McGruer <smcgruer@chromium.org>
Cr-Commit-Position: refs/heads/master@{#522021}
parent 5ddbfd5b
This is a testharness.js-based test. This is a testharness.js-based test.
Found 121 tests; 68 PASS, 53 FAIL, 0 TIMEOUT, 0 NOTRUN. Found 121 tests; 75 PASS, 46 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS Element.animate() creates an Animation object PASS Element.animate() creates an Animation object
PASS Element.animate() creates an Animation object in the relevant realm of the target element PASS Element.animate() creates an Animation object in the relevant realm of the target element
PASS Element.animate() creates an Animation object with a KeyframeEffect PASS Element.animate() creates an Animation object with a KeyframeEffect
...@@ -53,18 +53,18 @@ FAIL Element.animate() accepts a two property (a shorthand and one of its compon ...@@ -53,18 +53,18 @@ FAIL Element.animate() accepts a two property (a shorthand and one of its compon
PASS Element.animate() accepts a two property keyframe sequence where one property is missing from the first keyframe PASS Element.animate() accepts a two property keyframe sequence where one property is missing from the first keyframe
PASS Element.animate() accepts a two property keyframe sequence where one property is missing from the last keyframe PASS Element.animate() accepts a two property keyframe sequence where one property is missing from the last keyframe
PASS Element.animate() accepts a one property two keyframe sequence that needs to stringify its values PASS Element.animate() accepts a one property two keyframe sequence that needs to stringify its values
FAIL Element.animate() accepts a keyframe sequence with a CSS variable reference assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS Element.animate() accepts a keyframe sequence with a CSS variable reference
FAIL Element.animate() accepts a keyframe sequence with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "computedOffset,easing,margin,offset" but got "computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset" FAIL Element.animate() accepts a keyframe sequence with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "computedOffset,easing,margin,offset" but got "computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
PASS Element.animate() accepts a keyframe sequence with duplicate values for a given interior offset PASS Element.animate() accepts a keyframe sequence with duplicate values for a given interior offset
PASS Element.animate() accepts a keyframe sequence with duplicate values for offsets 0 and 1 PASS Element.animate() accepts a keyframe sequence with duplicate values for offsets 0 and 1
PASS Element.animate() accepts a two property four keyframe sequence PASS Element.animate() accepts a two property four keyframe sequence
FAIL Element.animate() accepts a single keyframe sequence with omitted offset assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS Element.animate() accepts a single keyframe sequence with omitted offset
FAIL Element.animate() accepts a single keyframe sequence with null offset assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS Element.animate() accepts a single keyframe sequence with null offset
PASS Element.animate() accepts a single keyframe sequence with string offset PASS Element.animate() accepts a single keyframe sequence with string offset
FAIL Element.animate() accepts a one property keyframe sequence with some omitted offsets assert_equals: value for 'offset' on ComputedKeyframe #2 expected (object) null but got (number) NaN PASS Element.animate() accepts a one property keyframe sequence with some omitted offsets
FAIL Element.animate() accepts a one property keyframe sequence with some null offsets assert_equals: value for 'offset' on ComputedKeyframe #2 expected (object) null but got (number) NaN PASS Element.animate() accepts a one property keyframe sequence with some null offsets
FAIL Element.animate() accepts a two property keyframe sequence with some omitted offsets assert_equals: value for 'offset' on ComputedKeyframe #2 expected (object) null but got (number) NaN PASS Element.animate() accepts a two property keyframe sequence with some omitted offsets
FAIL Element.animate() accepts a one property keyframe sequence with all omitted offsets assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS Element.animate() accepts a one property keyframe sequence with all omitted offsets
PASS Element.animate() accepts a keyframe sequence with different easing values, but the same easing value for a given offset PASS Element.animate() accepts a keyframe sequence with different easing values, but the same easing value for a given offset
PASS Element.animate() accepts a keyframe sequence with different composite values, but the same composite value for a given offset PASS Element.animate() accepts a keyframe sequence with different composite values, but the same composite value for a given offset
PASS Element.animate() does not accept keyframes with an out-of-bounded positive offset PASS Element.animate() does not accept keyframes with an out-of-bounded positive offset
......
This is a testharness.js-based test. This is a testharness.js-based test.
Found 167 tests; 89 PASS, 78 FAIL, 0 TIMEOUT, 0 NOTRUN. Found 167 tests; 103 PASS, 64 FAIL, 0 TIMEOUT, 0 NOTRUN.
PASS A KeyframeEffectReadOnly can be constructed with no frames PASS A KeyframeEffectReadOnly can be constructed with no frames
PASS easing values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in KeyframeEffectOptions PASS easing values are parsed correctly when passed to the KeyframeEffectReadOnly constructor in KeyframeEffectOptions
PASS Invalid easing values are correctly rejected when passed to the KeyframeEffectReadOnly constructor in KeyframeEffectOptions PASS Invalid easing values are correctly rejected when passed to the KeyframeEffectReadOnly constructor in KeyframeEffectOptions
...@@ -96,30 +96,30 @@ PASS A KeyframeEffectReadOnly can be constructed with a two property keyframe se ...@@ -96,30 +96,30 @@ PASS A KeyframeEffectReadOnly can be constructed with a two property keyframe se
PASS A KeyframeEffectReadOnly constructed with a two property keyframe sequence where one property is missing from the last keyframe roundtrips PASS A KeyframeEffectReadOnly constructed with a two property keyframe sequence where one property is missing from the last keyframe roundtrips
PASS A KeyframeEffectReadOnly can be constructed with a one property two keyframe sequence that needs to stringify its values PASS A KeyframeEffectReadOnly can be constructed with a one property two keyframe sequence that needs to stringify its values
PASS A KeyframeEffectReadOnly constructed with a one property two keyframe sequence that needs to stringify its values roundtrips PASS A KeyframeEffectReadOnly constructed with a one property two keyframe sequence that needs to stringify its values roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference
FAIL A KeyframeEffectReadOnly constructed with a keyframe sequence with a CSS variable reference roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with a CSS variable reference roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "computedOffset,easing,margin,offset" but got "computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset" FAIL A KeyframeEffectReadOnly can be constructed with a keyframe sequence with a CSS variable reference in a shorthand property assert_equals: properties on ComputedKeyframe #0 should match expected "computedOffset,easing,margin,offset" but got "computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset"
FAIL A KeyframeEffectReadOnly constructed with a keyframe sequence with a CSS variable reference in a shorthand property roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided FAIL A KeyframeEffectReadOnly constructed with a keyframe sequence with a CSS variable reference in a shorthand property roundtrips assert_equals: properties on ComputedKeyframe #0 should match expected "computedOffset,easing,marginBottom,marginLeft,marginRight,marginTop,offset" but got "computedOffset,easing,offset"
PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with duplicate values for a given interior offset PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with duplicate values for a given interior offset
PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with duplicate values for a given interior offset roundtrips PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with duplicate values for a given interior offset roundtrips
PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with duplicate values for offsets 0 and 1 PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with duplicate values for offsets 0 and 1
PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with duplicate values for offsets 0 and 1 roundtrips PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with duplicate values for offsets 0 and 1 roundtrips
PASS A KeyframeEffectReadOnly can be constructed with a two property four keyframe sequence PASS A KeyframeEffectReadOnly can be constructed with a two property four keyframe sequence
PASS A KeyframeEffectReadOnly constructed with a two property four keyframe sequence roundtrips PASS A KeyframeEffectReadOnly constructed with a two property four keyframe sequence roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a single keyframe sequence with omitted offset assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS A KeyframeEffectReadOnly can be constructed with a single keyframe sequence with omitted offset
FAIL A KeyframeEffectReadOnly constructed with a single keyframe sequence with omitted offset roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided PASS A KeyframeEffectReadOnly constructed with a single keyframe sequence with omitted offset roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a single keyframe sequence with null offset assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS A KeyframeEffectReadOnly can be constructed with a single keyframe sequence with null offset
FAIL A KeyframeEffectReadOnly constructed with a single keyframe sequence with null offset roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided PASS A KeyframeEffectReadOnly constructed with a single keyframe sequence with null offset roundtrips
PASS A KeyframeEffectReadOnly can be constructed with a single keyframe sequence with string offset PASS A KeyframeEffectReadOnly can be constructed with a single keyframe sequence with string offset
PASS A KeyframeEffectReadOnly constructed with a single keyframe sequence with string offset roundtrips PASS A KeyframeEffectReadOnly constructed with a single keyframe sequence with string offset roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a one property keyframe sequence with some omitted offsets assert_equals: value for 'offset' on ComputedKeyframe #2 expected (object) null but got (number) NaN PASS A KeyframeEffectReadOnly can be constructed with a one property keyframe sequence with some omitted offsets
FAIL A KeyframeEffectReadOnly constructed with a one property keyframe sequence with some omitted offsets roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided PASS A KeyframeEffectReadOnly constructed with a one property keyframe sequence with some omitted offsets roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a one property keyframe sequence with some null offsets assert_equals: value for 'offset' on ComputedKeyframe #2 expected (object) null but got (number) NaN PASS A KeyframeEffectReadOnly can be constructed with a one property keyframe sequence with some null offsets
FAIL A KeyframeEffectReadOnly constructed with a one property keyframe sequence with some null offsets roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided PASS A KeyframeEffectReadOnly constructed with a one property keyframe sequence with some null offsets roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a two property keyframe sequence with some omitted offsets assert_equals: value for 'offset' on ComputedKeyframe #2 expected (object) null but got (number) NaN PASS A KeyframeEffectReadOnly can be constructed with a two property keyframe sequence with some omitted offsets
FAIL A KeyframeEffectReadOnly constructed with a two property keyframe sequence with some omitted offsets roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided PASS A KeyframeEffectReadOnly constructed with a two property keyframe sequence with some omitted offsets roundtrips
FAIL A KeyframeEffectReadOnly can be constructed with a one property keyframe sequence with all omitted offsets assert_equals: value for 'offset' on ComputedKeyframe #0 expected (object) null but got (number) NaN PASS A KeyframeEffectReadOnly can be constructed with a one property keyframe sequence with all omitted offsets
FAIL A KeyframeEffectReadOnly constructed with a one property keyframe sequence with all omitted offsets roundtrips Failed to construct 'KeyframeEffectReadOnly': Non numeric offset provided PASS A KeyframeEffectReadOnly constructed with a one property keyframe sequence with all omitted offsets roundtrips
PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with different easing values, but the same easing value for a given offset PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with different easing values, but the same easing value for a given offset
PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with different easing values, but the same easing value for a given offset roundtrips PASS A KeyframeEffectReadOnly constructed with a keyframe sequence with different easing values, but the same easing value for a given offset roundtrips
PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with different composite values, but the same composite value for a given offset PASS A KeyframeEffectReadOnly can be constructed with a keyframe sequence with different composite values, but the same composite value for a given offset
......
...@@ -167,7 +167,7 @@ class AnimationCompositorAnimationsTest : public RenderingTest { ...@@ -167,7 +167,7 @@ class AnimationCompositorAnimationsTest : public RenderingTest {
bool DuplicateSingleKeyframeAndTestIsCandidateOnResult( bool DuplicateSingleKeyframeAndTestIsCandidateOnResult(
StringKeyframe* frame) { StringKeyframe* frame) {
EXPECT_EQ(frame->Offset(), 0); EXPECT_EQ(frame->CheckedOffset(), 0);
StringKeyframeVector frames; StringKeyframeVector frames;
scoped_refptr<Keyframe> second = frame->CloneWithOffset(1); scoped_refptr<Keyframe> second = frame->CloneWithOffset(1);
...@@ -260,7 +260,7 @@ class AnimationCompositorAnimationsTest : public RenderingTest { ...@@ -260,7 +260,7 @@ class AnimationCompositorAnimationsTest : public RenderingTest {
scoped_refptr<StringKeyframe> to, scoped_refptr<StringKeyframe> to,
scoped_refptr<StringKeyframe> c = nullptr, scoped_refptr<StringKeyframe> c = nullptr,
scoped_refptr<StringKeyframe> d = nullptr) { scoped_refptr<StringKeyframe> d = nullptr) {
EXPECT_EQ(from->Offset(), 0); EXPECT_EQ(from->CheckedOffset(), 0);
StringKeyframeVector frames; StringKeyframeVector frames;
frames.push_back(from); frames.push_back(from);
EXPECT_LE(from->Offset(), to->Offset()); EXPECT_LE(from->Offset(), to->Offset());
...@@ -272,9 +272,9 @@ class AnimationCompositorAnimationsTest : public RenderingTest { ...@@ -272,9 +272,9 @@ class AnimationCompositorAnimationsTest : public RenderingTest {
if (d) { if (d) {
frames.push_back(d); frames.push_back(d);
EXPECT_LE(c->Offset(), d->Offset()); EXPECT_LE(c->Offset(), d->Offset());
EXPECT_EQ(d->Offset(), 1.0); EXPECT_EQ(d->CheckedOffset(), 1.0);
} else { } else {
EXPECT_EQ(to->Offset(), 1.0); EXPECT_EQ(to->CheckedOffset(), 1.0);
} }
if (!HasFatalFailure()) { if (!HasFatalFailure()) {
return StringKeyframeEffectModel::Create(frames); return StringKeyframeEffectModel::Create(frames);
......
...@@ -48,7 +48,7 @@ TEST(AnimationEffectInputTest, SortedOffsets) { ...@@ -48,7 +48,7 @@ TEST(AnimationEffectInputTest, SortedOffsets) {
DictionarySequenceOrDictionary::FromDictionarySequence(js_keyframes), DictionarySequenceOrDictionary::FromDictionarySequence(js_keyframes),
EffectModel::kCompositeReplace, nullptr, scope.GetExceptionState()); EffectModel::kCompositeReplace, nullptr, scope.GetExceptionState());
EXPECT_FALSE(scope.GetExceptionState().HadException()); EXPECT_FALSE(scope.GetExceptionState().HadException());
EXPECT_EQ(1.0, effect->GetFrames()[1]->Offset()); EXPECT_EQ(1.0, effect->GetFrames()[1]->CheckedOffset());
} }
TEST(AnimationEffectInputTest, UnsortedOffsets) { TEST(AnimationEffectInputTest, UnsortedOffsets) {
...@@ -102,7 +102,7 @@ TEST(AnimationEffectInputTest, LooslySorted) { ...@@ -102,7 +102,7 @@ TEST(AnimationEffectInputTest, LooslySorted) {
DictionarySequenceOrDictionary::FromDictionarySequence(js_keyframes), DictionarySequenceOrDictionary::FromDictionarySequence(js_keyframes),
EffectModel::kCompositeReplace, nullptr, scope.GetExceptionState()); EffectModel::kCompositeReplace, nullptr, scope.GetExceptionState());
EXPECT_FALSE(scope.GetExceptionState().HadException()); EXPECT_FALSE(scope.GetExceptionState().HadException());
EXPECT_EQ(1, effect->GetFrames()[2]->Offset()); EXPECT_EQ(1, effect->GetFrames()[2]->CheckedOffset());
} }
TEST(AnimationEffectInputTest, OutOfOrderWithNullOffsets) { TEST(AnimationEffectInputTest, OutOfOrderWithNullOffsets) {
......
...@@ -22,7 +22,11 @@ Keyframe::PropertySpecificKeyframe::CreateInterpolation( ...@@ -22,7 +22,11 @@ Keyframe::PropertySpecificKeyframe::CreateInterpolation(
void Keyframe::AddKeyframePropertiesToV8Object( void Keyframe::AddKeyframePropertiesToV8Object(
V8ObjectBuilder& object_builder) const { V8ObjectBuilder& object_builder) const {
object_builder.Add("offset", offset_); if (offset_) {
object_builder.Add("offset", offset_.value());
} else {
object_builder.AddNull("offset");
}
object_builder.Add("easing", easing_->ToString()); object_builder.Add("easing", easing_->ToString());
if (composite_.has_value()) { if (composite_.has_value()) {
object_builder.AddString( object_builder.AddString(
...@@ -33,7 +37,9 @@ void Keyframe::AddKeyframePropertiesToV8Object( ...@@ -33,7 +37,9 @@ void Keyframe::AddKeyframePropertiesToV8Object(
bool Keyframe::CompareOffsets(const scoped_refptr<Keyframe>& a, bool Keyframe::CompareOffsets(const scoped_refptr<Keyframe>& a,
const scoped_refptr<Keyframe>& b) { const scoped_refptr<Keyframe>& b) {
return a->Offset() < b->Offset(); if (!a->Offset() || !b->Offset())
return false;
return a->CheckedOffset() < b->CheckedOffset();
} }
} // namespace blink } // namespace blink
...@@ -67,8 +67,9 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> { ...@@ -67,8 +67,9 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> {
virtual ~Keyframe() {} virtual ~Keyframe() {}
// TODO(smcgruer): The keyframe offset should be immutable. // TODO(smcgruer): The keyframe offset should be immutable.
void SetOffset(double offset) { offset_ = offset; } void SetOffset(WTF::Optional<double> offset) { offset_ = offset; }
double Offset() const { return offset_; } WTF::Optional<double> Offset() const { return offset_; }
double CheckedOffset() const { return offset_.value(); }
// TODO(smcgruer): The keyframe composite operation should be immutable. // TODO(smcgruer): The keyframe composite operation should be immutable.
void SetComposite(EffectModel::CompositeOperation composite) { void SetComposite(EffectModel::CompositeOperation composite) {
...@@ -191,10 +192,8 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> { ...@@ -191,10 +192,8 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> {
protected: protected:
Keyframe() Keyframe()
: offset_(NullValue()), : offset_(), composite_(), easing_(LinearTimingFunction::Shared()) {}
composite_(), Keyframe(WTF::Optional<double> offset,
easing_(LinearTimingFunction::Shared()) {}
Keyframe(double offset,
WTF::Optional<EffectModel::CompositeOperation> composite, WTF::Optional<EffectModel::CompositeOperation> composite,
scoped_refptr<TimingFunction> easing) scoped_refptr<TimingFunction> easing)
: offset_(offset), composite_(composite), easing_(std::move(easing)) { : offset_(offset), composite_(composite), easing_(std::move(easing)) {
...@@ -202,7 +201,7 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> { ...@@ -202,7 +201,7 @@ class CORE_EXPORT Keyframe : public RefCounted<Keyframe> {
easing_ = LinearTimingFunction::Shared(); easing_ = LinearTimingFunction::Shared();
} }
double offset_; WTF::Optional<double> offset_;
WTF::Optional<EffectModel::CompositeOperation> composite_; WTF::Optional<EffectModel::CompositeOperation> composite_;
scoped_refptr<TimingFunction> easing_; scoped_refptr<TimingFunction> easing_;
DISALLOW_COPY_AND_ASSIGN(Keyframe); DISALLOW_COPY_AND_ASSIGN(Keyframe);
......
...@@ -154,35 +154,39 @@ bool KeyframeEffectModelBase::SnapshotAllCompositorKeyframes( ...@@ -154,35 +154,39 @@ bool KeyframeEffectModelBase::SnapshotAllCompositorKeyframes(
Vector<double> KeyframeEffectModelBase::GetComputedOffsets( Vector<double> KeyframeEffectModelBase::GetComputedOffsets(
const KeyframeVector& keyframes) { const KeyframeVector& keyframes) {
// To avoid having to create two vectors when converting from the nullable
// offsets to the non-nullable computed offsets, we keep the convention in
// this function that std::numeric_limits::quiet_NaN() represents null.
double last_offset = 0; double last_offset = 0;
Vector<double> result; Vector<double> result;
result.ReserveCapacity(keyframes.size()); result.ReserveCapacity(keyframes.size());
for (const auto& keyframe : keyframes) { for (const auto& keyframe : keyframes) {
double offset = keyframe->Offset(); WTF::Optional<double> offset = keyframe->Offset();
if (!IsNull(offset)) { if (offset) {
DCHECK_GE(offset, 0); DCHECK_GE(offset.value(), 0);
DCHECK_LE(offset, 1); DCHECK_LE(offset.value(), 1);
DCHECK_GE(offset, last_offset); DCHECK_GE(offset.value(), last_offset);
last_offset = offset; last_offset = offset.value();
} }
result.push_back(offset); result.push_back(offset.value_or(std::numeric_limits<double>::quiet_NaN()));
} }
if (result.IsEmpty()) if (result.IsEmpty())
return result; return result;
if (IsNull(result.back())) if (std::isnan(result.back()))
result.back() = 1; result.back() = 1;
if (result.size() > 1 && IsNull(result[0])) if (result.size() > 1 && std::isnan(result[0])) {
result.front() = 0; result.front() = 0;
}
size_t last_index = 0; size_t last_index = 0;
last_offset = result.front(); last_offset = result.front();
for (size_t i = 1; i < result.size(); ++i) { for (size_t i = 1; i < result.size(); ++i) {
double offset = result[i]; double offset = result[i];
if (!IsNull(offset)) { if (!std::isnan(offset)) {
for (size_t j = 1; j < i - last_index; ++j) { for (size_t j = 1; j < i - last_index; ++j) {
result[last_index + j] = result[last_index + j] =
last_offset + (offset - last_offset) * j / (i - last_index); last_offset + (offset - last_offset) * j / (i - last_index);
......
...@@ -123,8 +123,8 @@ TEST_F(AnimationKeyframeEffectV8Test, CanCreateAnAnimation) { ...@@ -123,8 +123,8 @@ TEST_F(AnimationKeyframeEffectV8Test, CanCreateAnAnimation) {
const KeyframeVector keyframes = animation->Model()->GetFrames(); const KeyframeVector keyframes = animation->Model()->GetFrames();
EXPECT_EQ(0, keyframes[0]->Offset()); EXPECT_EQ(0, keyframes[0]->CheckedOffset());
EXPECT_EQ(1, keyframes[1]->Offset()); EXPECT_EQ(1, keyframes[1]->CheckedOffset());
const CSSValue& keyframe1_width = const CSSValue& keyframe1_width =
ToStringKeyframe(keyframes[0].get()) ToStringKeyframe(keyframes[0].get())
......
...@@ -40,7 +40,7 @@ TransitionKeyframe::CreatePropertySpecificKeyframe( ...@@ -40,7 +40,7 @@ TransitionKeyframe::CreatePropertySpecificKeyframe(
DCHECK(offset == offset_); DCHECK(offset == offset_);
EffectModel::CompositeOperation composite = EffectModel::CompositeOperation composite =
composite_.value_or(effect_composite); composite_.value_or(effect_composite);
return PropertySpecificKeyframe::Create(Offset(), &Easing(), composite, return PropertySpecificKeyframe::Create(CheckedOffset(), &Easing(), composite,
value_->Clone(), compositor_value_); value_->Clone(), compositor_value_);
} }
......
...@@ -150,7 +150,8 @@ StringKeyframeEffectModel* CreateKeyframeEffectModel( ...@@ -150,7 +150,8 @@ StringKeyframeEffectModel* CreateKeyframeEffectModel(
Keyframe::CompareOffsets); Keyframe::CompareOffsets);
size_t target_index = 0; size_t target_index = 0;
for (size_t i = 1; i < keyframes.size(); i++) { for (size_t i = 1; i < keyframes.size(); i++) {
if (keyframes[i]->Offset() == keyframes[target_index]->Offset()) { if (keyframes[i]->CheckedOffset() ==
keyframes[target_index]->CheckedOffset()) {
for (const auto& property : keyframes[i]->Properties()) { for (const auto& property : keyframes[i]->Properties()) {
keyframes[target_index]->SetCSSPropertyValue( keyframes[target_index]->SetCSSPropertyValue(
property.GetCSSProperty().PropertyID(), property.GetCSSProperty().PropertyID(),
...@@ -167,22 +168,22 @@ StringKeyframeEffectModel* CreateKeyframeEffectModel( ...@@ -167,22 +168,22 @@ StringKeyframeEffectModel* CreateKeyframeEffectModel(
// Add 0% and 100% keyframes if absent. // Add 0% and 100% keyframes if absent.
scoped_refptr<StringKeyframe> start_keyframe = scoped_refptr<StringKeyframe> start_keyframe =
keyframes.IsEmpty() ? nullptr : keyframes[0]; keyframes.IsEmpty() ? nullptr : keyframes[0];
if (!start_keyframe || keyframes[0]->Offset() != 0) { if (!start_keyframe || keyframes[0]->CheckedOffset() != 0) {
start_keyframe = StringKeyframe::Create(); start_keyframe = StringKeyframe::Create();
start_keyframe->SetOffset(0); start_keyframe->SetOffset(0);
start_keyframe->SetEasing(default_timing_function); start_keyframe->SetEasing(default_timing_function);
keyframes.push_front(start_keyframe); keyframes.push_front(start_keyframe);
} }
scoped_refptr<StringKeyframe> end_keyframe = keyframes[keyframes.size() - 1]; scoped_refptr<StringKeyframe> end_keyframe = keyframes[keyframes.size() - 1];
if (end_keyframe->Offset() != 1) { if (end_keyframe->CheckedOffset() != 1) {
end_keyframe = StringKeyframe::Create(); end_keyframe = StringKeyframe::Create();
end_keyframe->SetOffset(1); end_keyframe->SetOffset(1);
end_keyframe->SetEasing(default_timing_function); end_keyframe->SetEasing(default_timing_function);
keyframes.push_back(end_keyframe); keyframes.push_back(end_keyframe);
} }
DCHECK_GE(keyframes.size(), 2U); DCHECK_GE(keyframes.size(), 2U);
DCHECK(!keyframes.front()->Offset()); DCHECK_EQ(keyframes.front()->CheckedOffset(), 0);
DCHECK_EQ(keyframes.back()->Offset(), 1); DCHECK_EQ(keyframes.back()->CheckedOffset(), 1);
StringKeyframeEffectModel* model = StringKeyframeEffectModel::Create( StringKeyframeEffectModel* model = StringKeyframeEffectModel::Create(
keyframes, EffectModel::kCompositeReplace, &keyframes[0]->Easing()); keyframes, EffectModel::kCompositeReplace, &keyframes[0]->Easing());
......
...@@ -107,8 +107,7 @@ BuildObjectForAnimationEffect(KeyframeEffectReadOnly* effect, ...@@ -107,8 +107,7 @@ BuildObjectForAnimationEffect(KeyframeEffectReadOnly* effect,
DCHECK(effect->Model()->IsKeyframeEffectModel()); DCHECK(effect->Model()->IsKeyframeEffectModel());
const KeyframeVector& keyframes = effect->Model()->GetFrames(); const KeyframeVector& keyframes = effect->Model()->GetFrames();
if (keyframes.size() == 3) { if (keyframes.size() == 3) {
DCHECK(!IsNull(keyframes.at(1)->Offset())); delay = keyframes.at(1)->CheckedOffset() * duration;
delay = keyframes.at(1)->Offset() * duration;
duration -= delay; duration -= delay;
easing = keyframes.at(1)->Easing().ToString(); easing = keyframes.at(1)->Easing().ToString();
} else { } else {
......
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