Commit 826db82c authored by Fredrik Söderqvist's avatar Fredrik Söderqvist Committed by Commit Bot

Remove SMILAnimationEffectParameters::is_to_animation

The effect of this parameter can be described using the other
parameters (is_additive = is_cumulative = false).

For list types it was previously used to avoid copying a list into
itself (clobbering it in the process), but that can achieved by
just comparing objects.
Similar techniques were applied in SVGPath and SVGTransformList, but
those classes could deal with the issue differently.

Rewrite SVGPath::CalculateAnimatedValue() to eliminate the extra
copy which should (no longer) be needed.

Change SVGTransformList::CalculateAnimatedValue() to compute the
transform first and then handle addition.

Also re-order the computations to try to get a somewhat canonical
order: interpolation, accumulation, addition.

In SVGAnimateMotionElement, always set |to_point_at_end_of_duration_|
instead of setting and checking a separate bool.
AnimateAdditiveNumber() handles the accumulation if required.

Bug: 1017723
Change-Id: I8adb2a7ad415a2d00aa057bfb93f55953450dd07
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2382111
Commit-Queue: Fredrik Söderquist <fs@opera.com>
Reviewed-by: default avatarStephen Chenney <schenney@chromium.org>
Cr-Commit-Position: refs/heads/master@{#803060}
parent 955a1c4f
...@@ -12,7 +12,6 @@ namespace blink { ...@@ -12,7 +12,6 @@ namespace blink {
// https://www.w3.org/TR/SMIL/smil-animation.html#animationNS-AnimationEffectFcn // https://www.w3.org/TR/SMIL/smil-animation.html#animationNS-AnimationEffectFcn
struct SMILAnimationEffectParameters { struct SMILAnimationEffectParameters {
bool is_discrete = false; bool is_discrete = false;
bool is_to_animation = false;
bool is_additive = false; bool is_additive = false;
bool is_cumulative = false; bool is_cumulative = false;
}; };
...@@ -31,12 +30,10 @@ inline void AnimateAdditiveNumber( ...@@ -31,12 +30,10 @@ inline void AnimateAdditiveNumber(
number = percentage < 0.5 ? from_number : to_number; number = percentage < 0.5 ? from_number : to_number;
else else
number = (to_number - from_number) * percentage + from_number; number = (to_number - from_number) * percentage + from_number;
if (!parameters.is_to_animation) {
if (repeat_count && parameters.is_cumulative) if (repeat_count && parameters.is_cumulative)
number += to_at_end_of_duration_number * repeat_count; number += to_at_end_of_duration_number * repeat_count;
if (parameters.is_additive) if (parameters.is_additive)
number += animated_number; number += animated_number;
}
animated_number = number; animated_number = number;
} }
......
...@@ -119,8 +119,7 @@ class SVGListPropertyHelper : public SVGListPropertyBase { ...@@ -119,8 +119,7 @@ class SVGListPropertyHelper : public SVGListPropertyBase {
bool AdjustFromToListValues(Derived* from_list, bool AdjustFromToListValues(Derived* from_list,
Derived* to_list, Derived* to_list,
float percentage, float percentage);
bool is_to_animation);
virtual ItemPropertyType* CreatePaddingItem() const { virtual ItemPropertyType* CreatePaddingItem() const {
return MakeGarbageCollected<ItemPropertyType>(); return MakeGarbageCollected<ItemPropertyType>();
...@@ -139,8 +138,7 @@ template <typename Derived, typename ItemProperty> ...@@ -139,8 +138,7 @@ template <typename Derived, typename ItemProperty>
bool SVGListPropertyHelper<Derived, ItemProperty>::AdjustFromToListValues( bool SVGListPropertyHelper<Derived, ItemProperty>::AdjustFromToListValues(
Derived* from_list, Derived* from_list,
Derived* to_list, Derived* to_list,
float percentage, float percentage) {
bool is_to_animation) {
// If no 'to' value is given, nothing to animate. // If no 'to' value is given, nothing to animate.
uint32_t to_list_size = to_list->length(); uint32_t to_list_size = to_list->length();
if (!to_list_size) if (!to_list_size)
...@@ -150,12 +148,12 @@ bool SVGListPropertyHelper<Derived, ItemProperty>::AdjustFromToListValues( ...@@ -150,12 +148,12 @@ bool SVGListPropertyHelper<Derived, ItemProperty>::AdjustFromToListValues(
// list length, fallback to a discrete animation. // list length, fallback to a discrete animation.
uint32_t from_list_size = from_list->length(); uint32_t from_list_size = from_list->length();
if (from_list_size != to_list_size && from_list_size) { if (from_list_size != to_list_size && from_list_size) {
if (percentage < 0.5) { const Derived* result = percentage < 0.5 ? from_list : to_list;
if (!is_to_animation) // If this is a 'to' animation, the "from" value will be the same
DeepCopy(from_list); // list as this list, so avoid the copy in that case since it
} else { // would clobber the list.
DeepCopy(to_list); if (result != this)
} DeepCopy(result);
return false; return false;
} }
......
...@@ -58,8 +58,7 @@ bool TargetCanHaveMotionTransform(const SVGElement& target) { ...@@ -58,8 +58,7 @@ bool TargetCanHaveMotionTransform(const SVGElement& target) {
} }
SVGAnimateMotionElement::SVGAnimateMotionElement(Document& document) SVGAnimateMotionElement::SVGAnimateMotionElement(Document& document)
: SVGAnimationElement(svg_names::kAnimateMotionTag, document), : SVGAnimationElement(svg_names::kAnimateMotionTag, document) {
has_to_point_at_end_of_duration_(false) {
SetCalcMode(kCalcModePaced); SetCalcMode(kCalcModePaced);
} }
...@@ -177,16 +176,17 @@ void SVGAnimateMotionElement::ClearAnimatedType() { ...@@ -177,16 +176,17 @@ void SVGAnimateMotionElement::ClearAnimatedType() {
bool SVGAnimateMotionElement::CalculateToAtEndOfDurationValue( bool SVGAnimateMotionElement::CalculateToAtEndOfDurationValue(
const String& to_at_end_of_duration_string) { const String& to_at_end_of_duration_string) {
ParsePoint(to_at_end_of_duration_string, to_point_at_end_of_duration_); ParsePoint(to_at_end_of_duration_string, to_point_at_end_of_duration_);
has_to_point_at_end_of_duration_ = true;
return true; return true;
} }
bool SVGAnimateMotionElement::CalculateFromAndToValues( bool SVGAnimateMotionElement::CalculateFromAndToValues(
const String& from_string, const String& from_string,
const String& to_string) { const String& to_string) {
has_to_point_at_end_of_duration_ = false;
ParsePoint(from_string, from_point_); ParsePoint(from_string, from_point_);
ParsePoint(to_string, to_point_); ParsePoint(to_string, to_point_);
// TODO(fs): Looks like this would clobber the at-end-of-duration
// value for a cumulative 'values' animation.
to_point_at_end_of_duration_ = to_point_;
return true; return true;
} }
...@@ -198,6 +198,7 @@ bool SVGAnimateMotionElement::CalculateFromAndByValues( ...@@ -198,6 +198,7 @@ bool SVGAnimateMotionElement::CalculateFromAndByValues(
// is 'by', |from_string| will be the empty string and yield a point // is 'by', |from_string| will be the empty string and yield a point
// of (0,0). // of (0,0).
to_point_ += from_point_; to_point_ += from_point_;
to_point_at_end_of_duration_ = to_point_;
return true; return true;
} }
...@@ -216,22 +217,14 @@ void SVGAnimateMotionElement::CalculateAnimatedValue(float percentage, ...@@ -216,22 +217,14 @@ void SVGAnimateMotionElement::CalculateAnimatedValue(float percentage,
transform->MakeIdentity(); transform->MakeIdentity();
if (GetAnimationMode() != kPathAnimation) { if (GetAnimationMode() != kPathAnimation) {
FloatPoint to_point_at_end_of_duration = to_point_;
if (!parameters.is_to_animation) {
if (repeat_count && parameters.is_cumulative &&
has_to_point_at_end_of_duration_) {
to_point_at_end_of_duration = to_point_at_end_of_duration_;
}
}
float animated_x = 0; float animated_x = 0;
AnimateAdditiveNumber(parameters, percentage, repeat_count, from_point_.X(), AnimateAdditiveNumber(parameters, percentage, repeat_count, from_point_.X(),
to_point_.X(), to_point_at_end_of_duration.X(), to_point_.X(), to_point_at_end_of_duration_.X(),
animated_x); animated_x);
float animated_y = 0; float animated_y = 0;
AnimateAdditiveNumber(parameters, percentage, repeat_count, from_point_.Y(), AnimateAdditiveNumber(parameters, percentage, repeat_count, from_point_.Y(),
to_point_.Y(), to_point_at_end_of_duration.Y(), to_point_.Y(), to_point_at_end_of_duration_.Y(),
animated_y); animated_y);
transform->Translate(animated_x, animated_y); transform->Translate(animated_x, animated_y);
......
...@@ -60,8 +60,6 @@ class SVGAnimateMotionElement final : public SVGAnimationElement { ...@@ -60,8 +60,6 @@ class SVGAnimateMotionElement final : public SVGAnimationElement {
enum RotateMode { kRotateAngle, kRotateAuto, kRotateAutoReverse }; enum RotateMode { kRotateAngle, kRotateAuto, kRotateAutoReverse };
RotateMode GetRotateMode() const; RotateMode GetRotateMode() const;
bool has_to_point_at_end_of_duration_;
void UpdateAnimationMode() override; void UpdateAnimationMode() override;
void InvalidateForAnimateMotionTransformChange(LayoutObject& target); void InvalidateForAnimateMotionTransformChange(LayoutObject& target);
......
...@@ -653,9 +653,11 @@ SMILAnimationEffectParameters SVGAnimationElement::ComputeEffectParameters() ...@@ -653,9 +653,11 @@ SMILAnimationEffectParameters SVGAnimationElement::ComputeEffectParameters()
const { const {
SMILAnimationEffectParameters parameters; SMILAnimationEffectParameters parameters;
parameters.is_discrete = GetCalcMode() == kCalcModeDiscrete; parameters.is_discrete = GetCalcMode() == kCalcModeDiscrete;
parameters.is_to_animation = GetAnimationMode() == kToAnimation; // 'to'-animations are neither additive nor cumulative.
if (GetAnimationMode() != kToAnimation) {
parameters.is_additive = IsAdditive() || GetAnimationMode() == kByAnimation; parameters.is_additive = IsAdditive() || GetAnimationMode() == kByAnimation;
parameters.is_cumulative = IsAccumulated(); parameters.is_cumulative = IsAccumulated();
}
return parameters; return parameters;
} }
......
...@@ -121,8 +121,7 @@ void SVGLengthList::CalculateAnimatedValue( ...@@ -121,8 +121,7 @@ void SVGLengthList::CalculateAnimatedValue(
uint32_t to_at_end_of_duration_list_size = uint32_t to_at_end_of_duration_list_size =
to_at_end_of_duration_list->length(); to_at_end_of_duration_list->length();
if (!AdjustFromToListValues(from_list, to_list, percentage, if (!AdjustFromToListValues(from_list, to_list, percentage))
parameters.is_to_animation))
return; return;
for (uint32_t i = 0; i < to_length_list_size; ++i) { for (uint32_t i = 0; i < to_length_list_size; ++i) {
......
...@@ -91,8 +91,7 @@ void SVGNumberList::CalculateAnimatedValue( ...@@ -91,8 +91,7 @@ void SVGNumberList::CalculateAnimatedValue(
uint32_t to_at_end_of_duration_list_size = uint32_t to_at_end_of_duration_list_size =
to_at_end_of_duration_list->length(); to_at_end_of_duration_list->length();
if (!AdjustFromToListValues(from_list, to_list, percentage, if (!AdjustFromToListValues(from_list, to_list, percentage))
parameters.is_to_animation))
return; return;
for (uint32_t i = 0; i < to_list_size; ++i) { for (uint32_t i = 0; i < to_list_size; ++i) {
......
...@@ -139,37 +139,25 @@ void SVGPath::CalculateAnimatedValue( ...@@ -139,37 +139,25 @@ void SVGPath::CalculateAnimatedValue(
return; return;
const auto& from = To<SVGPath>(*from_value); const auto& from = To<SVGPath>(*from_value);
const SVGPathByteStream* from_stream = &from.ByteStream(); const SVGPathByteStream& from_stream = from.ByteStream();
std::unique_ptr<SVGPathByteStream> copy;
if (parameters.is_to_animation) {
copy = ByteStream().Clone();
from_stream = copy.get();
}
// If the 'from' value is given and it's length doesn't match the 'to' value // If the 'from' value is given and it's length doesn't match the 'to' value
// list length, fallback to a discrete animation. // list length, fallback to a discrete animation.
if (from_stream->size() != to_stream.size() && from_stream->size()) { if (from_stream.size() != to_stream.size() && from_stream.size()) {
if (percentage < 0.5) { // If this is a 'to' animation, the "from" value will be the same
if (!parameters.is_to_animation) { // object as this object, so this will be a no-op but shouldn't
path_value_ = from.PathValue(); // clobber the object.
path_value_ = percentage < 0.5 ? from.PathValue() : to.PathValue();
return; return;
} }
} else {
path_value_ = to.PathValue();
return;
}
}
// If this is a 'to' animation, the "from" value will be the same
// object as this object, so make sure to update the state of this
// object as the last thing to avoid clobbering the result. As long
// as all intermediate results are computed into |new_stream| that
// should be unproblematic.
std::unique_ptr<SVGPathByteStream> new_stream = std::unique_ptr<SVGPathByteStream> new_stream =
BlendPathByteStreams(*from_stream, to_stream, percentage); BlendPathByteStreams(from_stream, to_stream, percentage);
if (!parameters.is_to_animation) {
// Handle additive='sum'.
if (parameters.is_additive) {
new_stream =
ConditionallyAddPathByteStreams(std::move(new_stream), ByteStream());
}
// Handle accumulate='sum'. // Handle accumulate='sum'.
if (repeat_count && parameters.is_cumulative) { if (repeat_count && parameters.is_cumulative) {
...@@ -177,7 +165,13 @@ void SVGPath::CalculateAnimatedValue( ...@@ -177,7 +165,13 @@ void SVGPath::CalculateAnimatedValue(
std::move(new_stream), std::move(new_stream),
To<SVGPath>(to_at_end_of_duration_value)->ByteStream(), repeat_count); To<SVGPath>(to_at_end_of_duration_value)->ByteStream(), repeat_count);
} }
// Handle additive='sum'.
if (parameters.is_additive) {
new_stream =
ConditionallyAddPathByteStreams(std::move(new_stream), ByteStream());
} }
path_value_ = MakeGarbageCollected<CSSPathValue>(std::move(new_stream)); path_value_ = MakeGarbageCollected<CSSPathValue>(std::move(new_stream));
} }
......
...@@ -105,8 +105,7 @@ void SVGPointList::CalculateAnimatedValue( ...@@ -105,8 +105,7 @@ void SVGPointList::CalculateAnimatedValue(
uint32_t to_at_end_of_duration_list_size = uint32_t to_at_end_of_duration_list_size =
to_at_end_of_duration_list->length(); to_at_end_of_duration_list->length();
if (!AdjustFromToListValues(from_list, to_list, percentage, if (!AdjustFromToListValues(from_list, to_list, percentage))
parameters.is_to_animation))
return; return;
for (uint32_t i = 0; i < to_point_list_size; ++i) { for (uint32_t i = 0; i < to_point_list_size; ++i) {
......
...@@ -468,10 +468,17 @@ void SVGTransformList::CalculateAnimatedValue( ...@@ -468,10 +468,17 @@ void SVGTransformList::CalculateAnimatedValue(
SVGTransformDistance(effective_from, to_transform) SVGTransformDistance(effective_from, to_transform)
.ScaledDistance(percentage) .ScaledDistance(percentage)
.AddToSVGTransform(effective_from); .AddToSVGTransform(effective_from);
if (parameters.is_to_animation) {
Clear(); // Handle accumulation.
Append(current_transform); if (repeat_count && parameters.is_cumulative) {
return; SVGTransform* effective_to_at_end =
!to_at_end_of_duration_list->IsEmpty()
? to_at_end_of_duration_list->at(0)
: MakeGarbageCollected<SVGTransform>(
to_transform->TransformType(),
SVGTransform::kConstructZeroTransform);
current_transform = SVGTransformDistance::AddSVGTransforms(
current_transform, effective_to_at_end, repeat_count);
} }
// If additive, we accumulate into (append to) the underlying value. // If additive, we accumulate into (append to) the underlying value.
...@@ -482,18 +489,7 @@ void SVGTransformList::CalculateAnimatedValue( ...@@ -482,18 +489,7 @@ void SVGTransformList::CalculateAnimatedValue(
Clear(); Clear();
} }
if (repeat_count && parameters.is_cumulative) {
SVGTransform* effective_to_at_end =
!to_at_end_of_duration_list->IsEmpty()
? to_at_end_of_duration_list->at(0)
: MakeGarbageCollected<SVGTransform>(
to_transform->TransformType(),
SVGTransform::kConstructZeroTransform);
Append(SVGTransformDistance::AddSVGTransforms(
current_transform, effective_to_at_end, repeat_count));
} else {
Append(current_transform); Append(current_transform);
}
} }
float SVGTransformList::CalculateDistance(SVGPropertyBase* to_value, float SVGTransformList::CalculateDistance(SVGPropertyBase* to_value,
......
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