Skip to content

Commit

Permalink
Implement getter and setter for rangeStart and rangeEnd.
Browse files Browse the repository at this point in the history
Bug: 1424538

Change-Id: I69506a04387ed76e5daf9d0c173f12afce8b0b6a
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4335845
Reviewed-by: Robert Flack <flackr@chromium.org>
Commit-Queue: Kevin Ellis <kevers@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1117717}
  • Loading branch information
kevers-google authored and Chromium LUCI CQ committed Mar 15, 2023
1 parent cac6ed5 commit 2e148ec
Show file tree
Hide file tree
Showing 14 changed files with 294 additions and 77 deletions.
Expand Up @@ -3842,6 +3842,10 @@ enum WebFeature {
kSpeculationRulesEagernessModerate = 4501,
kSpeculationRulesEagernessEager = 4502,
kURLSetPortCheckOverflow = 4503,
kV8Animation_RangeStart_AttributeGetter = 4504,
kV8Animation_RangeStart_AttributeSetter = 4505,
kV8Animation_RangeEnd_AttributeGetter = 4506,
kV8Animation_RangeEnd_AttributeSetter = 4507,

// Add new features immediately above this line. Don't change assigned
// numbers of any item, and don't reuse removed slots.
Expand Down
55 changes: 3 additions & 52 deletions third_party/blink/renderer/core/animation/animatable.cc
Expand Up @@ -70,55 +70,6 @@ V8UnionKeyframeEffectOptionsOrUnrestrictedDouble* CoerceEffectOptions(
return nullptr;
}

TimelineOffset ConvertRangeOffset(
Element* element,
const V8UnionStringOrTimelineRangeOffset* range_offset,
double default_percent,
ExceptionState& exception_state) {
TimelineOffset result;
if (range_offset->IsString()) {
absl::optional<TimelineOffset> parsed_timeline_offset =
TimelineOffset::Create(element, range_offset->GetAsString(),
exception_state);
if (parsed_timeline_offset) {
// TODO(kevers): Keep track of style dependent value in order to
// re-resolve on a style update.
return parsed_timeline_offset.value();
}
result.name = TimelineOffset::NamedRange::kNone;
result.offset = Length(default_percent, Length::Type::kPercent);
} else {
TimelineRangeOffset* value = range_offset->GetAsTimelineRangeOffset();
result.name = value->hasRangeName() ? value->rangeName().AsEnum()
: TimelineOffset::NamedRange::kNone;
if (value->hasOffset()) {
CSSNumericValue* offset = value->offset();
const CSSPrimitiveValue* css_value =
DynamicTo<CSSPrimitiveValue>(offset->ToCSSValue());

if (!css_value || (!css_value->IsPx() && !css_value->IsPercentage() &&
!css_value->IsCalculatedPercentageWithLength())) {
exception_state.ThrowTypeError(
"CSSNumericValue must be a length or percentage for animation "
"range.");
return result;
}

if (css_value->IsPx()) {
result.offset = Length::Fixed(css_value->GetDoubleValue());
} else if (css_value->IsPercentage()) {
result.offset = Length::Percent(css_value->GetDoubleValue());
} else {
DCHECK(css_value->IsCalculatedPercentageWithLength());
result.offset = TimelineOffset::ResolveLength(element, css_value);
}
} else {
result.offset = Length::Percent(default_percent);
}
}
return result;
}

} // namespace

// https://w3.org/TR/web-animations-1/#dom-animatable-animate
Expand Down Expand Up @@ -168,13 +119,13 @@ Animation* Animatable::animate(
// ViewTimeline options.
if (options_dict->hasRangeStart() &&
RuntimeEnabledFeatures::CSSScrollTimelineEnabled()) {
animation->SetRangeStart(ConvertRangeOffset(
animation->SetRangeStartInternal(TimelineOffset::Create(
element, options_dict->rangeStart(), 0, exception_state));
}
if (options_dict->hasRangeEnd() &&
RuntimeEnabledFeatures::CSSScrollTimelineEnabled()) {
animation->SetRangeEnd(ConvertRangeOffset(element, options_dict->rangeEnd(),
100, exception_state));
animation->SetRangeEndInternal(TimelineOffset::Create(
element, options_dict->rangeEnd(), 100, exception_state));
}
return animation;
}
Expand Down
53 changes: 51 additions & 2 deletions third_party/blink/renderer/core/animation/animation.cc
Expand Up @@ -37,6 +37,7 @@
#include "cc/animation/animation_timeline.h"
#include "third_party/blink/public/platform/platform.h"
#include "third_party/blink/public/platform/task_type.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_timeline_range_offset.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_cssnumericvalue_double.h"
#include "third_party/blink/renderer/core/animation/animation_timeline.h"
#include "third_party/blink/renderer/core/animation/animation_utils.h"
Expand Down Expand Up @@ -2218,6 +2219,54 @@ void Animation::SetCompositorPending(bool effect_changed) {
}
}

const Animation::RangeBoundary* Animation::rangeStart() {
return ToRangeBoundary(range_start_);
}

const Animation::RangeBoundary* Animation::rangeEnd() {
return ToRangeBoundary(range_end_);
}

void Animation::setRangeStart(const Animation::RangeBoundary* range_start,
ExceptionState& exception_state) {
SetRangeStartInternal(
GetEffectiveTimelineOffset(range_start, 0, exception_state));
}

void Animation::setRangeEnd(const Animation::RangeBoundary* range_end,
ExceptionState& exception_state) {
SetRangeEndInternal(
GetEffectiveTimelineOffset(range_end, 1, exception_state));
}

absl::optional<TimelineOffset> Animation::GetEffectiveTimelineOffset(
const Animation::RangeBoundary* boundary,
double default_percent,
ExceptionState& exception_state) {
KeyframeEffect* keyframe_effect = DynamicTo<KeyframeEffect>(effect());
Element* element = keyframe_effect ? keyframe_effect->target() : nullptr;

return TimelineOffset::Create(element, boundary, default_percent,
exception_state);
}

/* static */
Animation::RangeBoundary* Animation::ToRangeBoundary(
absl::optional<TimelineOffset> timeline_offset) {
if (!timeline_offset) {
return MakeGarbageCollected<RangeBoundary>("auto");
}

TimelineRangeOffset* timeline_range_offset =
MakeGarbageCollected<TimelineRangeOffset>();
timeline_range_offset->setRangeName(timeline_offset->name);
CSSPrimitiveValue* value =
CSSPrimitiveValue::CreateFromLength(timeline_offset->offset, 1);
CSSNumericValue* offset = CSSNumericValue::FromCSSValue(*value);
timeline_range_offset->setOffset(offset);
return MakeGarbageCollected<RangeBoundary>(timeline_range_offset);
}

void Animation::UpdateStartTimeForViewTimeline() {
auto* view_timeline = DynamicTo<ViewTimeline>(timeline_.Get());
if (!view_timeline || !effect()) {
Expand All @@ -2227,10 +2276,10 @@ void Animation::UpdateStartTimeForViewTimeline() {
absl::optional<TimelineOffset> boundary;
double default_offset;
if (EffectivePlaybackRate() >= 0) {
boundary = GetRangeStart();
boundary = GetRangeStartInternal();
default_offset = 0;
} else {
boundary = GetRangeEnd();
boundary = GetRangeEndInternal();
default_offset = 1;
}

Expand Down
26 changes: 21 additions & 5 deletions third_party/blink/renderer/core/animation/animation.h
Expand Up @@ -205,18 +205,26 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
virtual void setTimeline(AnimationTimeline* timeline);

// Animation options for ViewTimelines.
// TODO(kevers): Add web-animation-API methods once specced.
const absl::optional<TimelineOffset>& GetRangeStart() const {
using RangeBoundary = V8UnionStringOrTimelineRangeOffset;
const RangeBoundary* rangeStart();
const RangeBoundary* rangeEnd();
void setRangeStart(const RangeBoundary* range_start,
ExceptionState& exception_state);
void setRangeEnd(const RangeBoundary* range_end,
ExceptionState& exception_state);

const absl::optional<TimelineOffset>& GetRangeStartInternal() const {
return range_start_;
}
const absl::optional<TimelineOffset>& GetRangeEnd() const {
const absl::optional<TimelineOffset>& GetRangeEndInternal() const {
return range_end_;
}
void SetRangeStart(const absl::optional<TimelineOffset>& range_start) {
void SetRangeStartInternal(
const absl::optional<TimelineOffset>& range_start) {
range_start_ = range_start;
OnRangeUpdate();
}
void SetRangeEnd(const absl::optional<TimelineOffset>& range_end) {
void SetRangeEndInternal(const absl::optional<TimelineOffset>& range_end) {
range_end_ = range_end;
OnRangeUpdate();
}
Expand Down Expand Up @@ -435,6 +443,14 @@ class CORE_EXPORT Animation : public EventTargetWithInlineData,
// if changing the animation range on a running or finished animation.
void UpdateStartTimeForViewTimeline();

// Conversion between V8 representation of an animation range boundary and the
// internal representation.
absl::optional<TimelineOffset> GetEffectiveTimelineOffset(
const RangeBoundary* boundary,
double default_percent,
ExceptionState& exception_state);
static RangeBoundary* ToRangeBoundary(absl::optional<TimelineOffset> offset);

String id_;

// Extended play state reported to dev tools. This play state has an
Expand Down
2 changes: 2 additions & 0 deletions third_party/blink/renderer/core/animation/animation.idl
Expand Up @@ -44,6 +44,8 @@ enum ReplaceState { "active", "removed", "persisted" };
[Measure, RaisesException=Setter] attribute CSSNumberish? startTime;
[Measure, RaisesException=Setter] attribute CSSNumberish? currentTime;
[Measure, RaisesException=Setter] attribute double playbackRate;
[RuntimeEnabled=ScrollTimeline, Measure, RaisesException=Setter] attribute (TimelineRangeOffset or DOMString) rangeStart;
[RuntimeEnabled=ScrollTimeline, Measure, RaisesException=Setter] attribute (TimelineRangeOffset or DOMString) rangeEnd;
[Measure] readonly attribute AnimationPlayState playState;
[RuntimeEnabled=WebAnimationsAPI, Measure] readonly attribute ReplaceState replaceState;
[Measure] readonly attribute boolean pending;
Expand Down
12 changes: 6 additions & 6 deletions third_party/blink/renderer/core/animation/css/css_animations.cc
Expand Up @@ -1601,11 +1601,11 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) {
entry.animation->setTimeline(entry.timeline);
To<CSSAnimation>(*entry.animation).ResetIgnoreCSSTimeline();
}
if (entry.animation->GetRangeStart() != entry.range_start) {
entry.animation->SetRangeStart(entry.range_start);
if (entry.animation->GetRangeStartInternal() != entry.range_start) {
entry.animation->SetRangeStartInternal(entry.range_start);
}
if (entry.animation->GetRangeEnd() != entry.range_end) {
entry.animation->SetRangeEnd(entry.range_end);
if (entry.animation->GetRangeEndInternal() != entry.range_end) {
entry.animation->SetRangeEndInternal(entry.range_end);
}

running_animations_[entry.index]->Update(entry);
Expand Down Expand Up @@ -1641,8 +1641,8 @@ void CSSAnimations::MaybeApplyPendingUpdate(Element* element) {
if (inert_animation->Paused())
animation->pause();
animation->resetIgnoreCSSPlayState();
animation->SetRangeStart(entry.range_start);
animation->SetRangeEnd(entry.range_end);
animation->SetRangeStartInternal(entry.range_start);
animation->SetRangeEndInternal(entry.range_end);
animation->Update(kTimingUpdateOnDemand);

running_animations_.push_back(
Expand Down
Expand Up @@ -159,10 +159,10 @@ class CORE_EXPORT CSSAnimations final {

AnimationTimeline* Timeline() const { return animation->timeline(); }
const absl::optional<TimelineOffset>& RangeStart() const {
return animation->GetRangeStart();
return animation->GetRangeStartInternal();
}
const absl::optional<TimelineOffset>& RangeEnd() const {
return animation->GetRangeEnd();
return animation->GetRangeEndInternal();
}

void Update(UpdatedCSSAnimation update) {
Expand Down
53 changes: 53 additions & 0 deletions third_party/blink/renderer/core/animation/timeline_offset.cc
Expand Up @@ -4,10 +4,12 @@

#include "third_party/blink/renderer/core/animation/timeline_offset.h"

#include "third_party/blink/renderer/bindings/core/v8/v8_timeline_range_offset.h"
#include "third_party/blink/renderer/core/css/css_identifier_value.h"
#include "third_party/blink/renderer/core/css/css_primitive_value_mappings.h"
#include "third_party/blink/renderer/core/css/css_to_length_conversion_data.h"
#include "third_party/blink/renderer/core/css/css_value_list.h"
#include "third_party/blink/renderer/core/css/cssom/css_numeric_value.h"
#include "third_party/blink/renderer/core/css/parser/css_parser.h"
#include "third_party/blink/renderer/core/css/properties/computed_style_utils.h"
#include "third_party/blink/renderer/core/css/resolver/element_resolve_context.h"
Expand Down Expand Up @@ -69,6 +71,14 @@ absl::optional<TimelineOffset> TimelineOffset::Create(
Element* element,
String css_text,
ExceptionState& exception_state) {
if (!element) {
exception_state.ThrowDOMException(
DOMExceptionCode::kInvalidStateError,
"Unable to parse TimelineOffset from CSS text with a null effect or "
"target");
return absl::nullopt;
}

Document& document = element->GetDocument();
const CSSValue* value_list = CSSParser::ParseSingleValue(
CSSPropertyID::kAnimationRangeStart, css_text,
Expand Down Expand Up @@ -109,6 +119,49 @@ absl::optional<TimelineOffset> TimelineOffset::Create(
ResolveLength(element, &list.Item(1)));
}

/* static */
absl::optional<TimelineOffset> TimelineOffset::Create(
Element* element,
const V8UnionStringOrTimelineRangeOffset* range_offset,
double default_percent,
ExceptionState& exception_state) {
if (range_offset->IsString()) {
return Create(element, range_offset->GetAsString(), exception_state);
}

TimelineRangeOffset* value = range_offset->GetAsTimelineRangeOffset();
NamedRange name =
value->hasRangeName() ? value->rangeName().AsEnum() : NamedRange::kNone;

Length parsed_offset;
if (value->hasOffset()) {
CSSNumericValue* offset = value->offset();
const CSSPrimitiveValue* css_value =
DynamicTo<CSSPrimitiveValue>(offset->ToCSSValue());

if (!css_value || (!css_value->IsPx() && !css_value->IsPercentage() &&
!css_value->IsCalculatedPercentageWithLength())) {
exception_state.ThrowTypeError(
"CSSNumericValue must be a length or percentage for animation "
"range.");
return absl::nullopt;
}

if (css_value->IsPx()) {
parsed_offset = Length::Fixed(css_value->GetDoubleValue());
} else if (css_value->IsPercentage()) {
parsed_offset = Length::Percent(css_value->GetDoubleValue());
} else {
DCHECK(css_value->IsCalculatedPercentageWithLength());
parsed_offset = TimelineOffset::ResolveLength(element, css_value);
}
} else {
parsed_offset = Length::Percent(default_percent);
}

return TimelineOffset(name, parsed_offset);
}

/* static */
Length TimelineOffset::ResolveLength(Element* element, const CSSValue* value) {
ElementResolveContext element_resolve_context(*element);
Expand Down
7 changes: 7 additions & 0 deletions third_party/blink/renderer/core/animation/timeline_offset.h
Expand Up @@ -6,6 +6,7 @@
#define THIRD_PARTY_BLINK_RENDERER_CORE_ANIMATION_TIMELINE_OFFSET_H_

#include "third_party/blink/renderer/bindings/core/v8/v8_timeline_range.h"
#include "third_party/blink/renderer/bindings/core/v8/v8_union_string_timelinerangeoffset.h"
#include "third_party/blink/renderer/platform/geometry/length.h"

namespace blink {
Expand Down Expand Up @@ -36,6 +37,12 @@ struct TimelineOffset {
String value,
ExceptionState& exception_state);

static absl::optional<TimelineOffset> Create(
Element* element,
const V8UnionStringOrTimelineRangeOffset* range_offset,
double default_percent,
ExceptionState& exception_state);

static Length ResolveLength(Element* element, const CSSValue* value);

String ToString() const;
Expand Down
22 changes: 12 additions & 10 deletions third_party/blink/renderer/core/animation/view_timeline.cc
Expand Up @@ -258,12 +258,14 @@ AnimationTimeDelta ViewTimeline::CalculateIntrinsicIterationDuration(
if (duration && timing.iteration_count > 0) {
double active_interval = 1;

double start = animation->GetRangeStart()
? ToFractionalOffset(animation->GetRangeStart().value())
: 0;
double end = animation->GetRangeEnd()
? ToFractionalOffset(animation->GetRangeEnd().value())
: 1;
double start =
animation->GetRangeStartInternal()
? ToFractionalOffset(animation->GetRangeStartInternal().value())
: 0;
double end =
animation->GetRangeEndInternal()
? ToFractionalOffset(animation->GetRangeEndInternal().value())
: 1;

active_interval -= start;
active_interval -= (1 - end);
Expand Down Expand Up @@ -533,12 +535,12 @@ bool ViewTimeline::ResolveTimelineOffsets(bool invalidate_effect) const {
for (Animation* animation : GetAnimations()) {
if (auto* effect = DynamicTo<KeyframeEffect>(animation->effect())) {
double range_start =
animation->GetRangeStart()
? ToFractionalOffset(animation->GetRangeStart().value())
animation->GetRangeStartInternal()
? ToFractionalOffset(animation->GetRangeStartInternal().value())
: 0;
double range_end =
animation->GetRangeEnd()
? ToFractionalOffset(animation->GetRangeEnd().value())
animation->GetRangeEndInternal()
? ToFractionalOffset(animation->GetRangeEndInternal().value())
: 1;
if (effect->Model()->ResolveTimelineOffsets(range_start, range_end)) {
has_keyframe_update = true;
Expand Down

0 comments on commit 2e148ec

Please sign in to comment.