Commit d7f933bd authored by Nicolas Ouellet-Payeur's avatar Nicolas Ouellet-Payeur Committed by Commit Bot

Revert "Started implementing the STAPIT algorithm"

This reverts commit 4afcd1a6.

Reason for revert: repeatn-remove-add-animation.html is flaky (crbug.com/997279)

Original change's description:
> Started implementing the STAPIT algorithm
> 
> Changed SMILTimeContainer to step through all times where
> an animation stops or ends when just playing it normally. Currently
> it will only add slowdowns but also makes the animations more "correct".
> 
> This commit also fixes issue 688742
> 
> Bug: 688742, 986219
> Change-Id: I847abedc45aba110d09123793abfb3d9c018c94a
> Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1730421
> Commit-Queue: Edvard Thörnros <edvardt@opera.com>
> Reviewed-by: Fredrik Söderquist <fs@opera.com>
> Cr-Commit-Position: refs/heads/master@{#689930}

TBR=pdr@chromium.org,fs@opera.com,edvardt@opera.com

Change-Id: If0fca62a4515a0771745f7b9d69f3f84b6665073
No-Presubmit: true
No-Tree-Checks: true
No-Try: true
Bug: 688742, 986219
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1768829Reviewed-by: default avatarNicolas Ouellet-Payeur <nicolaso@chromium.org>
Commit-Queue: Nicolas Ouellet-Payeur <nicolaso@chromium.org>
Cr-Commit-Position: refs/heads/master@{#690028}
parent 5b6e5cee
...@@ -50,20 +50,19 @@ void SMILAnimationSandwich::Reset() { ...@@ -50,20 +50,19 @@ void SMILAnimationSandwich::Reset() {
} }
} }
void SMILAnimationSandwich::UpdateTiming(double elapsed) { void SMILAnimationSandwich::UpdateTiming(double elapsed, bool seek_to_time) {
if (!std::is_sorted(sandwich_.begin(), sandwich_.end(), if (!std::is_sorted(sandwich_.begin(), sandwich_.end(),
PriorityCompare(elapsed))) { PriorityCompare(elapsed))) {
std::sort(sandwich_.begin(), sandwich_.end(), PriorityCompare(elapsed)); std::sort(sandwich_.begin(), sandwich_.end(), PriorityCompare(elapsed));
} }
active_.Shrink(0);
active_.ReserveCapacity(sandwich_.size()); active_.ReserveCapacity(sandwich_.size());
for (const auto& it_animation : sandwich_) { for (const auto& it_animation : sandwich_) {
SVGSMILElement* animation = it_animation.Get(); SVGSMILElement* animation = it_animation.Get();
DCHECK(animation->HasValidTarget()); DCHECK(animation->HasValidTarget());
if (animation->NeedsToProgress(elapsed)) { if (animation->NeedsToProgress(elapsed)) {
animation->Progress(elapsed); animation->Progress(elapsed, seek_to_time);
active_.push_back(animation); active_.push_back(animation);
} else if (animation->IsContributing(elapsed)) { } else if (animation->IsContributing(elapsed)) {
active_.push_back(animation); active_.push_back(animation);
...@@ -73,18 +72,7 @@ void SMILAnimationSandwich::UpdateTiming(double elapsed) { ...@@ -73,18 +72,7 @@ void SMILAnimationSandwich::UpdateTiming(double elapsed) {
} }
} }
SMILTime SMILAnimationSandwich::NextInterestingTime( SMILTime SMILAnimationSandwich::GetNextFireTime() {
SMILTime document_time) const {
SMILTime interesting_time = SMILTime::Indefinite();
for (const auto& it_animation : sandwich_) {
SVGSMILElement* animation = it_animation.Get();
interesting_time = std::min(interesting_time,
animation->NextInterestingTime(document_time));
}
return interesting_time;
}
SMILTime SMILAnimationSandwich::GetNextFireTime() const {
SMILTime earliest_fire_time = SMILTime::Unresolved(); SMILTime earliest_fire_time = SMILTime::Unresolved();
for (const auto& it_animation : sandwich_) { for (const auto& it_animation : sandwich_) {
SVGSMILElement* animation = it_animation.Get(); SVGSMILElement* animation = it_animation.Get();
...@@ -96,7 +84,13 @@ SMILTime SMILAnimationSandwich::GetNextFireTime() const { ...@@ -96,7 +84,13 @@ SMILTime SMILAnimationSandwich::GetNextFireTime() const {
return earliest_fire_time; return earliest_fire_time;
} }
void SMILAnimationSandwich::SendEvents(double elapsed) { void SMILAnimationSandwich::SendEvents(double elapsed, bool seek_to_time) {
if (seek_to_time) {
for (auto& animation : active_) {
animation->TriggerPendingEvents(elapsed);
}
}
for (auto& animation : active_) { for (auto& animation : active_) {
animation->UpdateSyncBases(); animation->UpdateSyncBases();
} }
......
...@@ -62,12 +62,11 @@ class SMILAnimationSandwich : public GarbageCollected<SMILAnimationSandwich> { ...@@ -62,12 +62,11 @@ class SMILAnimationSandwich : public GarbageCollected<SMILAnimationSandwich> {
void Unschedule(SVGSMILElement* animation); void Unschedule(SVGSMILElement* animation);
void Reset(); void Reset();
void UpdateTiming(double elapsed); void UpdateTiming(double elapsed, bool seek_to_time);
void SendEvents(double elapsed); void SendEvents(double elapsed, bool seek_to_time);
SVGSMILElement* ApplyAnimationValues(); SVGSMILElement* ApplyAnimationValues();
SMILTime NextInterestingTime(SMILTime) const; SMILTime GetNextFireTime();
SMILTime GetNextFireTime() const;
bool IsEmpty() { return sandwich_.IsEmpty(); } bool IsEmpty() { return sandwich_.IsEmpty(); }
......
...@@ -70,9 +70,6 @@ class SMILTimeWithOrigin { ...@@ -70,9 +70,6 @@ class SMILTimeWithOrigin {
const SMILTime& Time() const { return time_; } const SMILTime& Time() const { return time_; }
bool OriginIsScript() const { return origin_ == kScriptOrigin; } bool OriginIsScript() const { return origin_ == kScriptOrigin; }
bool ShareOrigin(SMILTimeWithOrigin other) const {
return origin_ == other.origin_;
}
private: private:
SMILTime time_; SMILTime time_;
......
...@@ -45,12 +45,10 @@ static constexpr base::TimeDelta kAnimationPolicyOnceDuration = ...@@ -45,12 +45,10 @@ static constexpr base::TimeDelta kAnimationPolicyOnceDuration =
SMILTimeContainer::SMILTimeContainer(SVGSVGElement& owner) SMILTimeContainer::SMILTimeContainer(SVGSVGElement& owner)
: presentation_time_(0), : presentation_time_(0),
reference_time_(0), reference_time_(0),
latest_update_time_(0),
frame_scheduling_state_(kIdle), frame_scheduling_state_(kIdle),
started_(false), started_(false),
paused_(false), paused_(false),
document_order_indexes_dirty_(false), document_order_indexes_dirty_(false),
intervals_dirty_(true),
wakeup_timer_( wakeup_timer_(
owner.GetDocument().GetTaskRunner(TaskType::kInternalDefault), owner.GetDocument().GetTaskRunner(TaskType::kInternalDefault),
this, this,
...@@ -136,7 +134,6 @@ bool SMILTimeContainer::HasPendingSynchronization() const { ...@@ -136,7 +134,6 @@ bool SMILTimeContainer::HasPendingSynchronization() const {
} }
void SMILTimeContainer::NotifyIntervalsChanged() { void SMILTimeContainer::NotifyIntervalsChanged() {
intervals_dirty_ = true;
if (!IsStarted()) if (!IsStarted())
return; return;
// Schedule updateAnimations() to be called asynchronously so multiple // Schedule updateAnimations() to be called asynchronously so multiple
...@@ -178,10 +175,6 @@ void SMILTimeContainer::ResetDocumentTime() { ...@@ -178,10 +175,6 @@ void SMILTimeContainer::ResetDocumentTime() {
SynchronizeToDocumentTimeline(); SynchronizeToDocumentTimeline();
} }
double SMILTimeContainer::CurrentDocumentTime() const {
return latest_update_time_;
}
void SMILTimeContainer::SynchronizeToDocumentTimeline() { void SMILTimeContainer::SynchronizeToDocumentTimeline() {
reference_time_ = GetDocument() reference_time_ = GetDocument()
.Timeline() .Timeline()
...@@ -217,7 +210,11 @@ void SMILTimeContainer::Start() { ...@@ -217,7 +210,11 @@ void SMILTimeContainer::Start() {
SynchronizeToDocumentTimeline(); SynchronizeToDocumentTimeline();
started_ = true; started_ = true;
UpdateAnimationsAndScheduleFrameIfNeeded(presentation_time_); // If the "presentation time" is non-zero, the timeline was modified via
// SetElapsed() before the document began. In this case pass on
// seek_to_time=true to issue a seek.
UpdateAnimationsAndScheduleFrameIfNeeded(presentation_time_,
presentation_time_ ? true : false);
} }
void SMILTimeContainer::Pause() { void SMILTimeContainer::Pause() {
...@@ -272,9 +269,8 @@ void SMILTimeContainer::SetElapsed(double elapsed) { ...@@ -272,9 +269,8 @@ void SMILTimeContainer::SetElapsed(double elapsed) {
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
prevent_scheduled_animations_changes_ = false; prevent_scheduled_animations_changes_ = false;
#endif #endif
intervals_dirty_ = true;
latest_update_time_ = 0; UpdateAnimationsAndScheduleFrameIfNeeded(elapsed, true);
UpdateAnimationsAndScheduleFrameIfNeeded(elapsed);
} }
void SMILTimeContainer::ScheduleAnimationFrame(double delay_time) { void SMILTimeContainer::ScheduleAnimationFrame(double delay_time) {
...@@ -414,11 +410,12 @@ bool SMILTimeContainer::CanScheduleFrame(SMILTime earliest_fire_time) const { ...@@ -414,11 +410,12 @@ bool SMILTimeContainer::CanScheduleFrame(SMILTime earliest_fire_time) const {
} }
void SMILTimeContainer::UpdateAnimationsAndScheduleFrameIfNeeded( void SMILTimeContainer::UpdateAnimationsAndScheduleFrameIfNeeded(
double elapsed) { double elapsed,
bool seek_to_time) {
if (!GetDocument().IsActive()) if (!GetDocument().IsActive())
return; return;
UpdateAnimationTimings(elapsed); UpdateAnimationTimings(elapsed, seek_to_time);
ApplyAnimationValues(elapsed); ApplyAnimationValues(elapsed);
SMILTime earliest_fire_time = SMILTime::Unresolved(); SMILTime earliest_fire_time = SMILTime::Unresolved();
...@@ -434,51 +431,8 @@ void SMILTimeContainer::UpdateAnimationsAndScheduleFrameIfNeeded( ...@@ -434,51 +431,8 @@ void SMILTimeContainer::UpdateAnimationsAndScheduleFrameIfNeeded(
ScheduleAnimationFrame(delay_time); ScheduleAnimationFrame(delay_time);
} }
// A helper function to fetch the next interesting time after document_time void SMILTimeContainer::UpdateAnimationTimings(double elapsed,
SMILTime SMILTimeContainer::NextInterestingTime(SMILTime document_time) const { bool seek_to_time) {
DCHECK(document_time.IsFinite());
DCHECK(document_time >= 0.0);
SMILTime next_interesting_time = SMILTime::Indefinite();
for (const auto& entry : scheduled_animations_) {
const auto* sandwich = entry.value.Get();
SMILTime interesting_time = sandwich->NextInterestingTime(document_time);
next_interesting_time = std::min(next_interesting_time, interesting_time);
}
DCHECK(!next_interesting_time.IsFinite() ||
document_time < next_interesting_time);
return next_interesting_time;
}
void SMILTimeContainer::RemoveUnusedKeys() {
Vector<AnimationId> invalid_keys;
for (auto& entry : scheduled_animations_) {
if (entry.value->IsEmpty()) {
invalid_keys.push_back(entry.key);
}
}
scheduled_animations_.RemoveAll(invalid_keys);
}
void SMILTimeContainer::UpdateIntervals(SMILTime document_time) {
// This Shrink should free up the memory from the previous
// run in this loop. Otherwise it won't do anything.
DCHECK(document_time.IsFinite());
DCHECK(document_time >= 0.0);
active_sandwiches_.Shrink(0);
for (auto& entry : scheduled_animations_) {
auto* sandwich = entry.value.Get();
sandwich->UpdateTiming(document_time.Value());
if (!sandwich->IsEmpty()) {
active_sandwiches_.push_back(sandwich);
}
}
for (auto& sandwich : active_sandwiches_)
sandwich->SendEvents(document_time.Value());
}
void SMILTimeContainer::UpdateAnimationTimings(SMILTime elapsed) {
DCHECK(GetDocument().IsActive()); DCHECK(GetDocument().IsActive());
#if DCHECK_IS_ON() #if DCHECK_IS_ON()
...@@ -493,30 +447,29 @@ void SMILTimeContainer::UpdateAnimationTimings(SMILTime elapsed) { ...@@ -493,30 +447,29 @@ void SMILTimeContainer::UpdateAnimationTimings(SMILTime elapsed) {
if (document_order_indexes_dirty_) if (document_order_indexes_dirty_)
UpdateDocumentOrderIndexes(); UpdateDocumentOrderIndexes();
RemoveUnusedKeys(); {
Vector<AnimationId> invalid_keys;
// Don't update if it's a duplicate. for (auto& entry : scheduled_animations_) {
if (elapsed == latest_update_time_ && elapsed != 0.0) { if (entry.value->IsEmpty()) {
return; invalid_keys.push_back(entry.key);
}
}
scheduled_animations_.RemoveAll(invalid_keys);
} }
active_sandwiches_.ReserveCapacity(scheduled_animations_.size()); active_sandwiches_.ReserveCapacity(scheduled_animations_.size());
intervals_dirty_ |= latest_update_time_ == elapsed; for (auto& entry : scheduled_animations_) {
if (intervals_dirty_) { auto* sandwich = entry.value.Get();
const SMILTime interesting_time = NextInterestingTime(latest_update_time_); sandwich->UpdateTiming(elapsed, seek_to_time);
latest_update_time_ = std::min(elapsed, interesting_time).Value();
UpdateIntervals(latest_update_time_); if (!sandwich->IsEmpty()) {
active_sandwiches_.push_back(sandwich);
}
} }
while (latest_update_time_ < elapsed) { for (auto& sandwich : active_sandwiches_) {
const SMILTime interesting_time = NextInterestingTime(latest_update_time_); sandwich->SendEvents(elapsed, seek_to_time);
latest_update_time_ = std::min(elapsed, interesting_time).Value();
UpdateIntervals(latest_update_time_);
} }
// Deliberate resetting of the flag afterwards. This is so
// we don't toggle it on again in the loop, which causes us
// to be trapped in an infinet loop.
intervals_dirty_ = false;
} }
void SMILTimeContainer::ApplyAnimationValues(double elapsed) { void SMILTimeContainer::ApplyAnimationValues(double elapsed) {
......
...@@ -57,7 +57,6 @@ class SMILTimeContainer : public GarbageCollectedFinalized<SMILTimeContainer> { ...@@ -57,7 +57,6 @@ class SMILTimeContainer : public GarbageCollectedFinalized<SMILTimeContainer> {
void NotifyIntervalsChanged(); void NotifyIntervalsChanged();
double Elapsed() const; double Elapsed() const;
double CurrentDocumentTime() const;
bool IsPaused() const; bool IsPaused() const;
bool IsStarted() const; bool IsStarted() const;
...@@ -110,11 +109,9 @@ class SMILTimeContainer : public GarbageCollectedFinalized<SMILTimeContainer> { ...@@ -110,11 +109,9 @@ class SMILTimeContainer : public GarbageCollectedFinalized<SMILTimeContainer> {
ImageAnimationPolicy AnimationPolicy() const; ImageAnimationPolicy AnimationPolicy() const;
bool HandleAnimationPolicy(AnimationPolicyOnceAction); bool HandleAnimationPolicy(AnimationPolicyOnceAction);
bool CanScheduleFrame(SMILTime earliest_fire_time) const; bool CanScheduleFrame(SMILTime earliest_fire_time) const;
void UpdateAnimationsAndScheduleFrameIfNeeded(double elapsed); void UpdateAnimationsAndScheduleFrameIfNeeded(double elapsed,
void RemoveUnusedKeys(); bool seek_to_time = false);
void UpdateIntervals(SMILTime); void UpdateAnimationTimings(double elapsed, bool seek_to_time);
SMILTime NextInterestingTime(SMILTime) const;
void UpdateAnimationTimings(SMILTime elapsed);
void ApplyAnimationValues(double elapsed); void ApplyAnimationValues(double elapsed);
void ServiceOnNextFrame(); void ServiceOnNextFrame();
void ScheduleWakeUp(double delay_time, FrameSchedulingState); void ScheduleWakeUp(double delay_time, FrameSchedulingState);
...@@ -130,15 +127,12 @@ class SMILTimeContainer : public GarbageCollectedFinalized<SMILTimeContainer> { ...@@ -130,15 +127,12 @@ class SMILTimeContainer : public GarbageCollectedFinalized<SMILTimeContainer> {
double presentation_time_; double presentation_time_;
// The time on the document timeline corresponding to |m_presentationTime|. // The time on the document timeline corresponding to |m_presentationTime|.
double reference_time_; double reference_time_;
// The state all svg_smil_elements should be at.
double latest_update_time_;
FrameSchedulingState frame_scheduling_state_; FrameSchedulingState frame_scheduling_state_;
bool started_; // The timeline has been started. bool started_; // The timeline has been started.
bool paused_; // The timeline is paused. bool paused_; // The timeline is paused.
bool document_order_indexes_dirty_; bool document_order_indexes_dirty_;
bool intervals_dirty_;
TaskRunnerTimer<SMILTimeContainer> wakeup_timer_; TaskRunnerTimer<SMILTimeContainer> wakeup_timer_;
TaskRunnerTimer<SMILTimeContainer> animation_policy_once_timer_; TaskRunnerTimer<SMILTimeContainer> animation_policy_once_timer_;
......
...@@ -618,7 +618,7 @@ void SVGSMILElement::SetTargetElement(SVGElement* target) { ...@@ -618,7 +618,7 @@ void SVGSMILElement::SetTargetElement(SVGElement* target) {
} }
SMILTime SVGSMILElement::Elapsed() const { SMILTime SVGSMILElement::Elapsed() const {
return time_container_ ? time_container_->CurrentDocumentTime() : 0; return time_container_ ? time_container_->Elapsed() : 0;
} }
bool SVGSMILElement::IsFrozen() const { bool SVGSMILElement::IsFrozen() const {
...@@ -685,18 +685,9 @@ SMILTime SVGSMILElement::SimpleDuration() const { ...@@ -685,18 +685,9 @@ SMILTime SVGSMILElement::SimpleDuration() const {
return std::min(Dur(), SMILTime::Indefinite()); return std::min(Dur(), SMILTime::Indefinite());
} }
static void InsertSortedAndUnique(Vector<SMILTimeWithOrigin>& list, static void InsertSorted(Vector<SMILTimeWithOrigin>& list,
SMILTimeWithOrigin time) { SMILTimeWithOrigin time) {
auto* position = std::lower_bound(list.begin(), list.end(), time); auto* position = std::lower_bound(list.begin(), list.end(), time);
// Don't add it if we already have one of those.
for (auto* it = position; it < list.end(); ++it) {
if (position->Time() != time.Time())
break;
// If they share both time and origin, we don't need to add it,
// we just need to react.
if (position->ShareOrigin(time))
return;
}
list.insert(position - list.begin(), time); list.insert(position - list.begin(), time);
} }
...@@ -714,7 +705,7 @@ void SVGSMILElement::AddInstanceTime(BeginOrEnd begin_or_end, ...@@ -714,7 +705,7 @@ void SVGSMILElement::AddInstanceTime(BeginOrEnd begin_or_end,
return; return;
Vector<SMILTimeWithOrigin>& list = Vector<SMILTimeWithOrigin>& list =
begin_or_end == kBegin ? begin_times_ : end_times_; begin_or_end == kBegin ? begin_times_ : end_times_;
InsertSortedAndUnique(list, time_with_origin); InsertSorted(list, time_with_origin);
if (begin_or_end == kBegin) if (begin_or_end == kBegin)
BeginListChanged(elapsed); BeginListChanged(elapsed);
else else
...@@ -858,46 +849,6 @@ base::Optional<SMILInterval> SVGSMILElement::ResolveNextInterval() { ...@@ -858,46 +849,6 @@ base::Optional<SMILInterval> SVGSMILElement::ResolveNextInterval() {
return base::nullopt; return base::nullopt;
} }
SMILTime SVGSMILElement::NextInterestingTime(SMILTime document_time) const {
// TODO(edvardt): This can probably be smarter
//
// We currently just step at a delta smaller than the instance time,
// this lets us update it in the loop, but it costs one extra cycle.
// There is probably a way to make this cleaner, and faster.
unsigned repeat;
if (interval_.begin.IsFinite())
repeat = CalculateAnimationRepeat(document_time.Value()) + 1;
else
repeat = 0;
SMILTime simple_duration = SimpleDuration();
// The comments here trick to formatter into having them
// on separate lines, which makes it a lot easier to read.
SMILTime times[] = {
//
interval_.begin + simple_duration * repeat,
// TODO(edvardt): This is a vile hack.
// However, I am removing 0.5ms, which is less than the minimum
// precision time. This is a vile hack, and I would love to see it
// gone, but it should work "as is".
//
// Fixing this "for real" would require rewriting parts of the
// FindInstanceTime and the whole "sync base loop". This is a large
// undertaking, should not be taken lightly, but is needed in my opinion.
FindInstanceTime(kBegin, document_time, false) - 0.00005,
//
interval_.begin,
//
interval_.end};
std::sort(times, times + sizeof(times) / sizeof(times[0]));
for (SMILTime time : times) {
if (!time.IsFinite())
continue;
if (document_time < time)
return time;
}
return SMILTime::Indefinite();
}
SMILTime SVGSMILElement::NextProgressTime() const { SMILTime SVGSMILElement::NextProgressTime() const {
return next_progress_time_; return next_progress_time_;
} }
...@@ -976,6 +927,63 @@ base::Optional<SMILInterval> SVGSMILElement::CheckForNewRestartInterval( ...@@ -976,6 +927,63 @@ base::Optional<SMILInterval> SVGSMILElement::CheckForNewRestartInterval(
return modified; return modified;
} }
void SVGSMILElement::SeekToIntervalCorrespondingToTime(double elapsed) {
DCHECK(!is_waiting_for_first_interval_);
DCHECK(interval_.begin.IsFinite());
// Manually seek from interval to interval, just as if the animation would run
// regulary.
while (true) {
// Figure out the next value in the begin time list after the current
// interval begin.
SMILTime next_begin = FindInstanceTime(kBegin, interval_.begin, false);
// If the 'nextBegin' time is unresolved (eg. just one defined interval),
// we're done seeking.
if (next_begin.IsUnresolved())
return;
// If the 'nextBegin' time is larger than or equal to the current interval
// end time, we're done seeking. If the 'elapsed' time is smaller than the
// next begin interval time, we're done seeking.
if (next_begin < interval_.end && elapsed >= next_begin) {
// End current interval, and start a new interval from the 'nextBegin'
// time.
interval_.end = next_begin;
base::Optional<SMILInterval> next_interval = ResolveNextInterval();
if (!next_interval)
break;
interval_ = *next_interval;
NotifyDependentsIntervalChanged(interval_);
next_progress_time_ =
next_progress_time_.IsUnresolved()
? interval_.begin
: std::min(next_progress_time_, interval_.begin);
continue;
}
// If the desired 'elapsed' time is past the current interval, advance to
// the next.
if (elapsed >= interval_.end) {
base::Optional<SMILInterval> next_interval = ResolveNextInterval();
if (!next_interval)
break;
interval_ = *next_interval;
NotifyDependentsIntervalChanged(interval_);
next_progress_time_ =
next_progress_time_.IsUnresolved()
? interval_.begin
: std::min(next_progress_time_, interval_.begin);
continue;
}
return;
}
}
unsigned SVGSMILElement::CalculateAnimationRepeat(double elapsed) const { unsigned SVGSMILElement::CalculateAnimationRepeat(double elapsed) const {
const SMILTime simple_duration = SimpleDuration(); const SMILTime simple_duration = SimpleDuration();
if (simple_duration.IsIndefinite() || !simple_duration) if (simple_duration.IsIndefinite() || !simple_duration)
...@@ -1096,6 +1104,7 @@ bool SVGSMILElement::NeedsToProgress(double elapsed) { ...@@ -1096,6 +1104,7 @@ bool SVGSMILElement::NeedsToProgress(double elapsed) {
return false; return false;
} }
if (is_waiting_for_first_interval_) { if (is_waiting_for_first_interval_) {
is_waiting_for_first_interval_ = false; is_waiting_for_first_interval_ = false;
ResolveFirstInterval(); ResolveFirstInterval();
...@@ -1128,7 +1137,18 @@ void SVGSMILElement::UpdateNextProgressTime(double elapsed) { ...@@ -1128,7 +1137,18 @@ void SVGSMILElement::UpdateNextProgressTime(double elapsed) {
next_progress_time_ = CalculateNextProgressTime(elapsed); next_progress_time_ = CalculateNextProgressTime(elapsed);
} }
void SVGSMILElement::Progress(double elapsed) { void SVGSMILElement::Progress(double elapsed, bool seek_to_time) {
// This call may obtain a new interval -- never call
// CalculateAnimation{ Percent, Repeat }() before!
if (seek_to_time) {
SeekToIntervalCorrespondingToTime(elapsed);
if (elapsed < interval_.begin) {
// elapsed is not within an interval.
next_progress_time_ = interval_.begin;
return;
}
}
float percent = CalculateAnimationPercent(elapsed); float percent = CalculateAnimationPercent(elapsed);
unsigned repeat = CalculateAnimationRepeat(elapsed); unsigned repeat = CalculateAnimationRepeat(elapsed);
...@@ -1157,8 +1177,11 @@ void SVGSMILElement::Progress(double elapsed) { ...@@ -1157,8 +1177,11 @@ void SVGSMILElement::Progress(double elapsed) {
} }
// Copy over the value from last frame // Copy over the value from last frame
// TODO: Is this needed? last_syncbase_repeat_ = last_repeat_;
// last_syncbase_repeat_ = last_repeat_; if (seek_to_time) {
interval_has_changed_ = true;
last_repeat_ = repeat;
}
ActiveState old_active_state = GetActiveState(); ActiveState old_active_state = GetActiveState();
active_state_ = DetermineActiveState(elapsed); active_state_ = DetermineActiveState(elapsed);
...@@ -1169,13 +1192,11 @@ void SVGSMILElement::Progress(double elapsed) { ...@@ -1169,13 +1192,11 @@ void SVGSMILElement::Progress(double elapsed) {
StartedActiveInterval(); StartedActiveInterval();
} }
if (repeat && repeat != last_repeat_) { if (repeat && repeat != last_repeat_)
last_repeat_ = repeat;
NotifyDependentsIntervalChanged(interval_);
ScheduleRepeatEvents(); ScheduleRepeatEvents();
}
last_percent_ = percent; last_percent_ = percent;
last_repeat_ = repeat;
} }
if ((old_active_state == kActive && GetActiveState() != kActive) || if ((old_active_state == kActive && GetActiveState() != kActive) ||
......
...@@ -84,13 +84,14 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests { ...@@ -84,13 +84,14 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests {
SMILTime PreviousIntervalBegin() const { return previous_interval_begin_; } SMILTime PreviousIntervalBegin() const { return previous_interval_begin_; }
SMILTime SimpleDuration() const; SMILTime SimpleDuration() const;
void SeekToIntervalCorrespondingToTime(double elapsed);
bool NeedsToProgress(double elapsed); bool NeedsToProgress(double elapsed);
void Progress(double elapsed); void Progress(double elapsed, bool seek_to_time);
void TriggerPendingEvents(double elapsed); void TriggerPendingEvents(double elapsed);
void UpdateSyncBases(); void UpdateSyncBases();
void UpdateNextProgressTime(double elapsed); void UpdateNextProgressTime(double elapsed);
SMILTime NextInterestingTime(SMILTime) const;
SMILTime NextProgressTime() const; SMILTime NextProgressTime() const;
void UpdateAnimatedValue(SVGSMILElement* result_element) { void UpdateAnimatedValue(SVGSMILElement* result_element) {
UpdateAnimation(last_percent_, last_repeat_, result_element); UpdateAnimation(last_percent_, last_repeat_, result_element);
......
...@@ -84,22 +84,18 @@ function runAnimationTest(t, expected) { ...@@ -84,22 +84,18 @@ function runAnimationTest(t, expected) {
function smil_async_test(func) { function smil_async_test(func) {
async_test(t => { async_test(t => {
window.onload = t.step_func(function () { window.onload = t.step_func(function () {
window.requestAnimationFrame(function () { // Pause animations, we'll drive them manually.
window.requestAnimationFrame(function () { // This also ensures that the timeline is paused before
// Pause animations, we'll drive them manually. // it starts. This should make the instance time of the below
// This also ensures that the timeline is paused before // 'click' (for instance) 0, and hence minimize rounding
// it starts. This should make the instance time of the below // errors for the addition in moveAnimationTimelineAndSample.
// 'click' (for instance) 0, and hence minimize rounding rootSVGElement.pauseAnimations();
// errors for the addition in moveAnimationTimelineAndSample.
rootSVGElement.pauseAnimations(); // If eg. an animation is running with begin="0s", and
// we want to sample the first time, before the animation
// If eg. an animation is running with begin="0s", and // starts, then we can't delay the testing by using an
// we want to sample the first time, before the animation // onclick event, as the animation would be past start time.
// starts, then we can't delay the testing by using an func(t);
// onclick event, as the animation would be past start time.
func(t);
});
});
}); });
}); });
} }
<!doctype html>
<title>Check correct event bases for onclick</title>
<meta charset="utf-8">
<link rel="help" href="https://svgwg.org/svg2-draft/single-page.html#interact-EventAttributes">
<link rel="author" title="Edvard Thörnros" href="mailto:edvardt@opera.com">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<svg width="200" height="100">
<rect x="0" y="0" width="100" height="100" id="a" fill="#0AA">
<set begin="a.click" attributeName="display" to="none" fill="freeze"/>
<set begin="b.click" attributeName="display" to="block" fill="freeze"/>
</rect>
<rect x="100" y="0" width="100" height="100" id="b" display="none" fill="#A0A">
<set begin="a.click" attributeName="display" to="block" fill="freeze"/>
<set begin="b.click" attributeName="display" to="none" fill="freeze"/>
</rect>
</svg>
<script>
let retries = 3;
let a = document.querySelector("#a");
let b = document.querySelector("#b");
let t = async_test();
let interval = setInterval(t.step_func(function() {
retries--;
if (retries == 0) {
clearInterval(interval);
assert_equals(window.getComputedStyle(a).display, "block");
assert_equals(window.getComputedStyle(b).display, "none");
t.done();
return;
}
a.dispatchEvent(new Event("click"));
t.step_timeout(function() {
b.dispatchEvent(new Event("click"));
}, 20);
}), 20 * 2);
</script>
accumulate-values-width-animation.html
additive-from-to-width-animation.html
additive-type-by-animation.html
additive-values-width-animation.html
animate-calcMode-spline-by.html
animate-calcMode-spline-from-by.html
animate-calcMode-spline-from-to.html
animate-calcMode-spline-to.html
animate-calcMode-spline-values.html
animate-color-calcMode-discrete.html
animate-color-fill-currentColor.html
animate-color-fill-from-by.html
animate-color-transparent.html
animate-css-xml-attributeType.html
animate-currentColor.html
animate-dynamic-update-attributeName.html
animate-elem-02-t-drt.html
animate-elem-14-t-drt.html
animate-elem-15-t-drt.html
animate-elem-16-t-drt.html
animate-elem-17-t-drt.html
animate-elem-18-t-drt.html
animate-elem-19-t-drt.html
animate-end-attribute-numeric-precision.html
animate-fill-freeze-with-repeatDur.html
animate-from-to-keyTimes.html
animate-gradient-transform.html
animate-inherit-css-property.html
animate-insert-begin.html
animate-insert-no-begin.html
animate-keySplines.html
animate-marker-orient-from-angle-to-angle.html
animate-marker-orient-from-angle-to-auto.html
animate-marker-orient-from-auto-to-auto-start-reverse.html
animate-marker-orient-to-angle.html
animateMotion-fill-freeze.html
animateMotion-fill-remove.html
animateMotion-multiple.html
animateMotion-still.html
animate-number-calcMode-discrete.html
animate-number-calcMode-discrete-keyTimes.html
animate-path-animation-Cc-Ss.html
animate-path-animation-cC-sS-inverse.html
animate-path-animation-Ll-Vv-Hh.html
animate-path-animation-lL-vV-hH-inverse.html
animate-path-animation-Mm-Aa-Z.html
animate-path-animation-mM-aA-Z-inverse.html
animate-path-animation-Qq-Tt.html
animate-path-animation-qQ-tT-inverse.html
animate-path-to-animation.html
animateTransform-pattern-transform.html
animVal-basics.html
attributeTypes.html
change-css-property-while-animating-fill-freeze.html
change-css-property-while-animating-fill-remove.html
change-target-while-animating-SVG-property.html
cyclic-syncbase.html
discard-on-discard.html
force-use-shadow-tree-recreation-while-animating.html
multiple-animations-ending.html
multiple-animations-fill-freeze.html
multiple-begin-additive-animation.html
non-additive-type-by-animation.html
non-additive-type-from-by-animation.html
remove-animation-element-while-animation-is-running.html
repeatn-remove-add-animation.html
single-values-animation.html
svgangle-animation-deg-to-grad.html
svgangle-animation-deg-to-rad.html
svgangle-animation-grad-to-deg.html
svgangle-animation-grad-to-rad.html
svgangle-animation-rad-to-deg.html
svgangle-animation-rad-to-grad.html
svgboolean-animation-1.html
svgenum-animation-10.html
svgenum-animation-11.html
svgenum-animation-12.html
svgenum-animation-13.html
svgenum-animation-1.html
svgenum-animation-2.html
svgenum-animation-3.html
svgenum-animation-4.html
svgenum-animation-5.html
svgenum-animation-6.html
svgenum-animation-7.html
svgenum-animation-8.html
svgenum-animation-9.html
svginteger-animation-1.html
svginteger-animation-2.html
svglength-additive-by-1.html
svglength-additive-by-2.html
svglength-additive-by-3.html
svglength-additive-by-4.html
svglength-additive-by-6.html
svglength-additive-by-7.html
svglength-additive-by-8.html
svglength-additive-from-by-1.html
svglength-additive-from-by-2.html
svglength-additive-from-by-3.html
svglength-additive-from-by-4.html
svglength-animation-invalid-value-1.html
svglength-animation-invalid-value-2.html
svglength-animation-invalid-value-3.html
svglength-animation-LengthModeHeight.html
svglength-animation-LengthModeOther.html
svglength-animation-LengthModeWidth.html
svglength-animation-number-to-number.html
svglength-animation-px-to-cm.html
svglength-animation-px-to-ems.html
svglength-animation-px-to-in.html
svglength-animation-px-to-number.html
svglength-animation-px-to-pc.html
svglength-animation-px-to-pt.html
svglength-animation-px-to-px.html
svglength-animation-unitType.html
svglength-animation-values.html
svglengthlist-animation-1.html
svglengthlist-animation-2.html
svglengthlist-animation-3.html
svglengthlist-animation-4.html
svglengthlist-animation-5.html
svgnumber-animation-1.html
svgnumber-animation-2.html
svgnumber-animation-3.html
svgnumber-animation-4.html
svgnumberlist-animation-1.html
svgnumberlist-animation-2.html
svgnumberoptionalnumber-animation-1.html
svgnumberoptionalnumber-animation-2.html
svgnumberoptionalnumber-animation-3.html
svgnumberoptionalnumber-animation-4.html
svgpath-animation-1.html
svgpointlist-animation-1.html
svgpointlist-animation-2.html
svgrect-animation-1.html
svgrect-animation-2.html
svgstring-animation-1.html
svgstring-animation-fallback-to-discrete.html
svgtransform-animation-1.html
svgtransform-animation-discrete.html
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