Commit 9fb6874b authored by Fredrik Söderquist's avatar Fredrik Söderquist Committed by Commit Bot

Cache the next "interesting" time for a timed element

Keep a cached value for the next "interesting"[1] time in a timed
element. This cache is updated every time we get a new interval, change
the end of an interval or trigger a repeat.
This reduces the time spent in SMILTimeContainer::NextInterestingTime(),
and lays the foundation for improved scheduling of interval updates in
the future.
The term "interesting" is replaced by "interval" in related function
names and variables.

[1] The next time that an interval either starts, ends or repeats.

Bug: 998526
Change-Id: I082d37b2000bc8d691363d87c22309013823664b
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1844818
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarPhilip Rogers <pdr@chromium.org>
Cr-Commit-Position: refs/heads/master@{#703672}
parent 42c775b9
...@@ -76,14 +76,14 @@ void SMILAnimationSandwich::UpdateTiming(SMILTime elapsed) { ...@@ -76,14 +76,14 @@ void SMILAnimationSandwich::UpdateTiming(SMILTime elapsed) {
} }
} }
SMILTime SMILAnimationSandwich::NextInterestingTime( SMILTime SMILAnimationSandwich::NextIntervalTime(
SMILTime presentation_time) const { SMILTime presentation_time) const {
SMILTime interesting_time = SMILTime::Indefinite(); SMILTime interval_time = SMILTime::Indefinite();
for (const auto& animation : sandwich_) { for (const auto& animation : sandwich_) {
interesting_time = std::min( interval_time =
interesting_time, animation->NextInterestingTime(presentation_time)); std::min(interval_time, animation->NextIntervalTime(presentation_time));
} }
return interesting_time; return interval_time;
} }
SMILTime SMILAnimationSandwich::NextProgressTime( SMILTime SMILAnimationSandwich::NextProgressTime(
......
...@@ -113,7 +113,7 @@ class SMILAnimationSandwich : public GarbageCollected<SMILAnimationSandwich> { ...@@ -113,7 +113,7 @@ class SMILAnimationSandwich : public GarbageCollected<SMILAnimationSandwich> {
void UpdateActiveAnimationStack(SMILTime presentation_time); void UpdateActiveAnimationStack(SMILTime presentation_time);
SVGSMILElement* ApplyAnimationValues(); SVGSMILElement* ApplyAnimationValues();
SMILTime NextInterestingTime(SMILTime presentation_time) const; SMILTime NextIntervalTime(SMILTime presentation_time) const;
SMILTime NextProgressTime(SMILTime presentation_time) const; SMILTime NextProgressTime(SMILTime presentation_time) const;
bool IsEmpty() { return sandwich_.IsEmpty(); } bool IsEmpty() { return sandwich_.IsEmpty(); }
......
...@@ -458,18 +458,17 @@ void SMILTimeContainer::UpdateAnimationsAndScheduleFrameIfNeeded( ...@@ -458,18 +458,17 @@ void SMILTimeContainer::UpdateAnimationsAndScheduleFrameIfNeeded(
} }
// A helper function to fetch the next interesting time after document_time // A helper function to fetch the next interesting time after document_time
SMILTime SMILTimeContainer::NextInterestingTime( SMILTime SMILTimeContainer::NextIntervalTime(SMILTime presentation_time) const {
SMILTime presentation_time) const {
DCHECK_GE(presentation_time, SMILTime()); DCHECK_GE(presentation_time, SMILTime());
SMILTime next_interesting_time = SMILTime::Indefinite(); SMILTime next_interval_time = SMILTime::Indefinite();
for (const auto& sandwich : scheduled_animations_) { for (const auto& sandwich : scheduled_animations_) {
next_interesting_time = next_interval_time =
std::min(next_interesting_time, std::min(next_interval_time,
sandwich.value->NextInterestingTime(presentation_time)); sandwich.value->NextIntervalTime(presentation_time));
} }
DCHECK(!next_interesting_time.IsFinite() || DCHECK(!next_interval_time.IsFinite() ||
presentation_time < next_interesting_time); presentation_time < next_interval_time);
return next_interesting_time; return next_interval_time;
} }
void SMILTimeContainer::RemoveUnusedKeys() { void SMILTimeContainer::RemoveUnusedKeys() {
...@@ -512,9 +511,9 @@ void SMILTimeContainer::UpdateAnimationTimings(SMILTime presentation_time) { ...@@ -512,9 +511,9 @@ void SMILTimeContainer::UpdateAnimationTimings(SMILTime presentation_time) {
UpdateIntervals(latest_update_time_); UpdateIntervals(latest_update_time_);
while (latest_update_time_ < presentation_time) { while (latest_update_time_ < presentation_time) {
const SMILTime interesting_time = NextInterestingTime(latest_update_time_); const SMILTime interval_time = NextIntervalTime(latest_update_time_);
if (interesting_time <= presentation_time) { if (interval_time <= presentation_time) {
latest_update_time_ = interesting_time; latest_update_time_ = interval_time;
UpdateIntervals(latest_update_time_); UpdateIntervals(latest_update_time_);
} else { } else {
latest_update_time_ = presentation_time; latest_update_time_ = presentation_time;
......
...@@ -118,7 +118,7 @@ class SMILTimeContainer final : public GarbageCollected<SMILTimeContainer> { ...@@ -118,7 +118,7 @@ class SMILTimeContainer final : public GarbageCollected<SMILTimeContainer> {
void UpdateAnimationsAndScheduleFrameIfNeeded(SMILTime elapsed); void UpdateAnimationsAndScheduleFrameIfNeeded(SMILTime elapsed);
void RemoveUnusedKeys(); void RemoveUnusedKeys();
void UpdateIntervals(SMILTime); void UpdateIntervals(SMILTime);
SMILTime NextInterestingTime(SMILTime elapsed) const; SMILTime NextIntervalTime(SMILTime elapsed) const;
void UpdateAnimationTimings(SMILTime elapsed); void UpdateAnimationTimings(SMILTime elapsed);
void ApplyAnimationValues(SMILTime elapsed); void ApplyAnimationValues(SMILTime elapsed);
void ServiceOnNextFrame(); void ServiceOnNextFrame();
......
...@@ -188,6 +188,7 @@ SVGSMILElement::SVGSMILElement(const QualifiedName& tag_name, Document& doc) ...@@ -188,6 +188,7 @@ SVGSMILElement::SVGSMILElement(const QualifiedName& tag_name, Document& doc)
is_scheduled_(false), is_scheduled_(false),
interval_{SMILTime::Unresolved(), SMILTime::Unresolved()}, interval_{SMILTime::Unresolved(), SMILTime::Unresolved()},
previous_interval_{SMILTime::Unresolved(), SMILTime::Unresolved()}, previous_interval_{SMILTime::Unresolved(), SMILTime::Unresolved()},
next_interval_time_(SMILTime::Unresolved()),
active_state_(kInactive), active_state_(kInactive),
restart_(kRestartAlways), restart_(kRestartAlways),
fill_(kFillRemove), fill_(kFillRemove),
...@@ -256,8 +257,9 @@ void SVGSMILElement::Reset() { ...@@ -256,8 +257,9 @@ void SVGSMILElement::Reset() {
is_waiting_for_first_interval_ = true; is_waiting_for_first_interval_ = true;
interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()}; interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()};
previous_interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()}; previous_interval_ = {SMILTime::Unresolved(), SMILTime::Unresolved()};
next_interval_time_ = SMILTime::Unresolved();
last_progress_ = {0.0f, 0}; last_progress_ = {0.0f, 0};
ResolveFirstInterval(); ResolveFirstInterval(SMILTime());
} }
Node::InsertionNotificationRequest SVGSMILElement::InsertedInto( Node::InsertionNotificationRequest SVGSMILElement::InsertedInto(
...@@ -817,46 +819,65 @@ SMILInterval SVGSMILElement::ResolveInterval(SMILTime begin_after, ...@@ -817,46 +819,65 @@ SMILInterval SVGSMILElement::ResolveInterval(SMILTime begin_after,
return SMILInterval(SMILTime::Unresolved(), SMILTime::Unresolved()); return SMILInterval(SMILTime::Unresolved(), SMILTime::Unresolved());
} }
bool SVGSMILElement::ResolveFirstInterval() { bool SVGSMILElement::ResolveFirstInterval(SMILTime presentation_time) {
SMILInterval first_interval = SMILInterval first_interval =
ResolveInterval(SMILTime::Earliest(), SMILTime()); ResolveInterval(SMILTime::Earliest(), presentation_time);
if (!first_interval.IsResolved() || first_interval == interval_) if (!first_interval.IsResolved() || first_interval == interval_)
return false; return false;
interval_ = first_interval; SetNewInterval(first_interval, presentation_time);
NotifyDependentsOnNewInterval(interval_);
return true; return true;
} }
SMILTime SVGSMILElement::NextInterestingTime(SMILTime presentation_time) const { void SVGSMILElement::SetNewInterval(const SMILInterval& interval,
SMILTime presentation_time) {
interval_ = interval;
next_interval_time_ = ComputeNextIntervalTime(presentation_time);
NotifyDependentsOnNewInterval(interval_);
}
void SVGSMILElement::SetNewIntervalEnd(SMILTime new_end,
SMILTime presentation_time) {
interval_.end = new_end;
next_interval_time_ = ComputeNextIntervalTime(presentation_time);
NotifyDependentsOnNewInterval(interval_);
}
SMILTime SVGSMILElement::NextIntervalTime(SMILTime presentation_time) const {
if (presentation_time < next_interval_time_)
return next_interval_time_;
return SMILTime::Unresolved();
}
SMILTime SVGSMILElement::ComputeNextIntervalTime(
SMILTime presentation_time) const {
DCHECK_GE(presentation_time, SMILTime()); DCHECK_GE(presentation_time, SMILTime());
SMILTime next_interesting_interval_time = SMILTime::Indefinite(); SMILTime next_interval_time = SMILTime::Unresolved();
if (interval_.BeginsAfter(presentation_time)) { if (interval_.BeginsAfter(presentation_time)) {
next_interesting_interval_time = interval_.begin; next_interval_time = interval_.begin;
} else if (interval_.EndsAfter(presentation_time)) { } else if (interval_.EndsAfter(presentation_time)) {
if (SMILTime simple_duration = SimpleDuration()) { if (SMILTime simple_duration = SimpleDuration()) {
SMILTime next_repeat_time = ComputeNextRepeatTime( SMILTime next_repeat_time = ComputeNextRepeatTime(
interval_.begin, simple_duration, presentation_time); interval_.begin, simple_duration, presentation_time);
DCHECK(next_repeat_time.IsFinite()); DCHECK(next_repeat_time.IsFinite());
next_interesting_interval_time = next_interval_time = std::min(next_repeat_time, interval_.end);
std::min(next_repeat_time, interval_.end);
} else { } else {
next_interesting_interval_time = interval_.end; next_interval_time = interval_.end;
} }
} }
return std::min(next_interesting_interval_time, return std::min(next_interval_time,
FindInstanceTime(kBegin, presentation_time, false)); FindInstanceTime(kBegin, presentation_time, false));
} }
void SVGSMILElement::InstanceListChanged() { void SVGSMILElement::InstanceListChanged() {
DCHECK(instance_lists_have_changed_); DCHECK(instance_lists_have_changed_);
SMILTime current_presentation_time =
time_container_ ? time_container_->CurrentDocumentTime() : SMILTime();
DCHECK(!current_presentation_time.IsUnresolved());
if (is_waiting_for_first_interval_) { if (is_waiting_for_first_interval_) {
instance_lists_have_changed_ = false; instance_lists_have_changed_ = false;
ResolveFirstInterval(); ResolveFirstInterval(current_presentation_time);
return; return;
} }
SMILTime current_presentation_time =
time_container_ ? time_container_->CurrentDocumentTime() : SMILTime();
DCHECK(!current_presentation_time.IsUnresolved());
SMILInterval old_interval = interval_; SMILInterval old_interval = interval_;
UpdateInterval(current_presentation_time); UpdateInterval(current_presentation_time);
if (interval_ != old_interval) { if (interval_ != old_interval) {
...@@ -886,10 +907,8 @@ void SVGSMILElement::DiscardOrRevalidateCurrentInterval( ...@@ -886,10 +907,8 @@ void SVGSMILElement::DiscardOrRevalidateCurrentInterval(
SMILTime new_end = FindInstanceTime(kEnd, interval_.begin, false); SMILTime new_end = FindInstanceTime(kEnd, interval_.begin, false);
DCHECK(!new_end.IsUnresolved()); DCHECK(!new_end.IsUnresolved());
new_end = ResolveActiveEnd(interval_.begin, new_end); new_end = ResolveActiveEnd(interval_.begin, new_end);
if (new_end != interval_.end) { if (new_end != interval_.end)
interval_.end = new_end; SetNewIntervalEnd(new_end, presentation_time);
NotifyDependentsOnNewInterval(interval_);
}
} }
} }
...@@ -902,8 +921,7 @@ bool SVGSMILElement::HandleIntervalRestart(SMILTime presentation_time) { ...@@ -902,8 +921,7 @@ bool SVGSMILElement::HandleIntervalRestart(SMILTime presentation_time) {
if (restart == kRestartAlways) { if (restart == kRestartAlways) {
SMILTime next_begin = FindInstanceTime(kBegin, interval_.begin, false); SMILTime next_begin = FindInstanceTime(kBegin, interval_.begin, false);
if (interval_.EndsAfter(next_begin)) { if (interval_.EndsAfter(next_begin)) {
interval_.end = next_begin; SetNewIntervalEnd(next_begin, presentation_time);
NotifyDependentsOnNewInterval(interval_);
return interval_.EndsBefore(presentation_time); return interval_.EndsBefore(presentation_time);
} }
} }
...@@ -925,17 +943,16 @@ void SVGSMILElement::UpdateInterval(SMILTime presentation_time) { ...@@ -925,17 +943,16 @@ void SVGSMILElement::UpdateInterval(SMILTime presentation_time) {
return; return;
if (interval_.IsResolved()) if (interval_.IsResolved())
previous_interval_ = interval_; previous_interval_ = interval_;
interval_ = next_interval; SetNewInterval(next_interval, presentation_time);
NotifyDependentsOnNewInterval(interval_);
interval_has_changed_ = true; interval_has_changed_ = true;
} }
void SVGSMILElement::AddedToTimeContainer() { void SVGSMILElement::AddedToTimeContainer() {
DCHECK(time_container_); DCHECK(time_container_);
SMILTime current_presentation_time = time_container_->CurrentDocumentTime();
if (is_waiting_for_first_interval_) if (is_waiting_for_first_interval_)
ResolveFirstInterval(); ResolveFirstInterval(current_presentation_time);
SMILTime current_presentation_time = time_container_->CurrentDocumentTime();
if (IntervalBegin() <= current_presentation_time || if (IntervalBegin() <= current_presentation_time ||
NextProgressTime(current_presentation_time).IsFinite()) { NextProgressTime(current_presentation_time).IsFinite()) {
time_container_->MarkIntervalsDirty(); time_container_->MarkIntervalsDirty();
...@@ -1078,7 +1095,7 @@ bool SVGSMILElement::CurrentIntervalIsActive(SMILTime elapsed) { ...@@ -1078,7 +1095,7 @@ bool SVGSMILElement::CurrentIntervalIsActive(SMILTime elapsed) {
if (is_waiting_for_first_interval_) { if (is_waiting_for_first_interval_) {
// The current internal must be the first, and has started, so clear the flag and (re)resolve. // The current internal must be the first, and has started, so clear the flag and (re)resolve.
is_waiting_for_first_interval_ = false; is_waiting_for_first_interval_ = false;
if (ResolveFirstInterval()) if (ResolveFirstInterval(elapsed))
time_container_->MarkIntervalsDirty(); time_container_->MarkIntervalsDirty();
} }
return true; return true;
...@@ -1109,6 +1126,7 @@ void SVGSMILElement::UpdateActiveState(SMILTime elapsed) { ...@@ -1109,6 +1126,7 @@ void SVGSMILElement::UpdateActiveState(SMILTime elapsed) {
NotifyDependentsOnRepeat(progress_state.repeat, elapsed); NotifyDependentsOnRepeat(progress_state.repeat, elapsed);
ScheduleRepeatEvents(); ScheduleRepeatEvents();
} }
next_interval_time_ = ComputeNextIntervalTime(elapsed);
last_progress_ = progress_state; last_progress_ = progress_state;
} }
} }
......
...@@ -91,7 +91,8 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests { ...@@ -91,7 +91,8 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests {
bool IsHigherPriorityThan(const SVGSMILElement* other, bool IsHigherPriorityThan(const SVGSMILElement* other,
SMILTime presentation_time) const; SMILTime presentation_time) const;
SMILTime NextInterestingTime(SMILTime elapsed) const; SMILTime NextIntervalTime(SMILTime presentation_time) const;
SMILTime ComputeNextIntervalTime(SMILTime presentation_time) const;
SMILTime NextProgressTime(SMILTime elapsed) const; SMILTime NextProgressTime(SMILTime elapsed) const;
void UpdateAnimatedValue(SVGSMILElement* result_element) { void UpdateAnimatedValue(SVGSMILElement* result_element) {
UpdateAnimation(last_progress_.progress, last_progress_.repeat, UpdateAnimation(last_progress_.progress, last_progress_.repeat,
...@@ -163,7 +164,7 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests { ...@@ -163,7 +164,7 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests {
SMILTime BeginTimeForPrioritization(SMILTime presentation_time) const; SMILTime BeginTimeForPrioritization(SMILTime presentation_time) const;
SMILInterval ResolveInterval(SMILTime begin_after, SMILTime end_after) const; SMILInterval ResolveInterval(SMILTime begin_after, SMILTime end_after) const;
bool ResolveFirstInterval(); bool ResolveFirstInterval(SMILTime presentation_time);
// Check if the current interval is still current, and apply restart // Check if the current interval is still current, and apply restart
// semantics. Returns true if a new interval should be resolved. // semantics. Returns true if a new interval should be resolved.
bool HandleIntervalRestart(SMILTime presentation_time); bool HandleIntervalRestart(SMILTime presentation_time);
...@@ -172,6 +173,8 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests { ...@@ -172,6 +173,8 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests {
SMILTime resolved_end) const; SMILTime resolved_end) const;
SMILTime RepeatingDuration() const; SMILTime RepeatingDuration() const;
const SMILInterval& GetActiveInterval(SMILTime elapsed) const; const SMILInterval& GetActiveInterval(SMILTime elapsed) const;
void SetNewInterval(const SMILInterval&, SMILTime presentation_time);
void SetNewIntervalEnd(SMILTime new_end, SMILTime presentation_time);
void AddInstanceTime(BeginOrEnd begin_or_end, void AddInstanceTime(BeginOrEnd begin_or_end,
SMILTime time, SMILTime time,
...@@ -275,6 +278,7 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests { ...@@ -275,6 +278,7 @@ class CORE_EXPORT SVGSMILElement : public SVGElement, public SVGTests {
// This is the previous interval. It should always be non-overlapping and // This is the previous interval. It should always be non-overlapping and
// "before" |interval_|. // "before" |interval_|.
SMILInterval previous_interval_; SMILInterval previous_interval_;
SMILTime next_interval_time_;
unsigned active_state_ : 2; unsigned active_state_ : 2;
unsigned restart_ : 2; unsigned restart_ : 2;
......
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