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