Commit 71ac8aaf authored by alancutter's avatar alancutter Committed by Commit bot

Add additive animation support for CSS property motion-rotation

This patch adds support for composite modes on motion-rotation
CSS animations via element.animate().

BUG=437696

Review URL: https://codereview.chromium.org/1645913002

Cr-Commit-Position: refs/heads/master@{#376149}
parent c78e9708
<!DOCTYPE html>
<body>
<script src="../interpolation/resources/interpolation-test.js"></script>
<script>
assertComposition({
property: 'motion-rotation',
underlying: '20deg',
addFrom: '10deg',
addTo: '20deg',
}, [
{at: -0.3, is: '27deg'},
{at: 0, is: '30deg'},
{at: 0.3, is: '33deg'},
{at: 0.6, is: '36deg'},
{at: 1, is: '40deg'},
{at: 1.5, is: '45deg'},
]);
assertComposition({
property: 'motion-rotation',
underlying: 'auto 20deg',
addFrom: '10deg',
addTo: '20deg',
}, [
{at: -0.3, is: '7deg'},
{at: 0, is: '10deg'},
{at: 0.3, is: '13deg'},
{at: 0.6, is: '16deg'},
{at: 1, is: '20deg'},
{at: 1.5, is: '25deg'},
]);
assertComposition({
property: 'motion-rotation',
underlying: 'auto 20deg',
addFrom: 'reverse 10deg',
addTo: 'auto 20deg',
}, [
{at: -0.3, is: 'auto 261deg'},
{at: 0, is: 'auto 210deg'},
{at: 0.3, is: 'auto 159deg'},
{at: 0.6, is: 'auto 108deg'},
{at: 1, is: 'auto 40deg'},
{at: 1.5, is: 'auto -45deg'},
]);
assertComposition({
property: 'motion-rotation',
underlying: '20deg',
addFrom: 'reverse 10deg',
addTo: '20deg',
}, [
{at: -0.3, is: 'auto 190deg'},
{at: 0, is: 'auto 190deg'},
{at: 0.3, is: 'auto 190deg'},
{at: 0.6, is: '40deg'},
{at: 1, is: '40deg'},
{at: 1.5, is: '40deg'},
]);
assertComposition({
property: 'motion-rotation',
underlying: '20deg',
replaceFrom: 'reverse 10deg',
addTo: '20deg',
}, [
{at: -0.3, is: 'auto 190deg'},
{at: 0, is: 'auto 190deg'},
{at: 0.3, is: 'auto 190deg'},
{at: 0.6, is: '40deg'},
{at: 1, is: '40deg'},
{at: 1.5, is: '40deg'},
]);
assertComposition({
property: 'motion-rotation',
underlying: '20deg',
addFrom: '10deg',
replaceTo: '10deg',
}, [
{at: -0.3, is: '36deg'},
{at: 0, is: '30deg'},
{at: 0.3, is: '24deg'},
{at: 0.6, is: '18deg'},
{at: 1, is: '10deg'},
{at: 1.5, is: '0deg'},
]);
</script>
</body>
<!DOCTYPE html>
<script src="resources/responsive-test.js"></script>
<script>
assertCSSResponsive({
property: 'motion-rotation',
from: 'inherit',
to: 'auto 40deg',
configurations: [{
state: {inherited: '50deg'},
expect: [
{at: 0.25, is: '50deg'},
{at: 0.75, is: 'auto 40deg'},
],
}, {
state: {inherited: 'auto 20deg'},
expect: [
{at: 0.25, is: 'auto 25deg'},
{at: 0.75, is: 'auto 35deg'},
],
}],
});
assertCSSResponsive({
property: 'motion-rotation',
from: neutralKeyframe,
to: '80deg',
configurations: [{
state: {underlying: 'auto 50deg'},
expect: [
{at: 0.25, is: 'auto 50deg'},
{at: 0.75, is: '80deg'},
],
}, {
state: {underlying: '40deg'},
expect: [
{at: 0.25, is: '50deg'},
{at: 0.75, is: '70deg'},
],
}],
});
</script>
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "core/animation/CSSMotionRotationInterpolationType.h"
#include "core/css/resolver/StyleBuilderConverter.h"
#include "core/style/StyleMotionRotation.h"
namespace blink {
class CSSMotionRotationNonInterpolableValue : public NonInterpolableValue {
public:
~CSSMotionRotationNonInterpolableValue() {}
static PassRefPtr<CSSMotionRotationNonInterpolableValue> create(MotionRotationType rotationType)
{
return adoptRef(new CSSMotionRotationNonInterpolableValue(rotationType));
}
MotionRotationType rotationType() const { return m_rotationType; }
DECLARE_NON_INTERPOLABLE_VALUE_TYPE();
private:
CSSMotionRotationNonInterpolableValue(MotionRotationType rotationType)
: m_rotationType(rotationType)
{ }
MotionRotationType m_rotationType;
};
DEFINE_NON_INTERPOLABLE_VALUE_TYPE(CSSMotionRotationNonInterpolableValue);
DEFINE_NON_INTERPOLABLE_VALUE_TYPE_CASTS(CSSMotionRotationNonInterpolableValue);
namespace {
class UnderlyingRotationTypeChecker : public InterpolationType::ConversionChecker {
public:
static PassOwnPtr<UnderlyingRotationTypeChecker> create(MotionRotationType underlyingRotationType)
{
return adoptPtr(new UnderlyingRotationTypeChecker(underlyingRotationType));
}
bool isValid(const InterpolationEnvironment&, const InterpolationValue& underlying) const final
{
return m_underlyingRotationType == toCSSMotionRotationNonInterpolableValue(*underlying.nonInterpolableValue).rotationType();
}
private:
UnderlyingRotationTypeChecker(MotionRotationType underlyingRotationType)
: m_underlyingRotationType(underlyingRotationType)
{ }
MotionRotationType m_underlyingRotationType;
};
class InheritedRotationTypeChecker : public InterpolationType::ConversionChecker {
public:
static PassOwnPtr<InheritedRotationTypeChecker> create(MotionRotationType inheritedRotationType)
{
return adoptPtr(new InheritedRotationTypeChecker(inheritedRotationType));
}
bool isValid(const InterpolationEnvironment& environment, const InterpolationValue& underlying) const final
{
return m_inheritedRotationType == environment.state().parentStyle()->motionRotation().type;
}
private:
InheritedRotationTypeChecker(MotionRotationType inheritedRotationType)
: m_inheritedRotationType(inheritedRotationType)
{ }
MotionRotationType m_inheritedRotationType;
};
InterpolationValue convertMotionRotation(const StyleMotionRotation& rotation)
{
return InterpolationValue(
InterpolableNumber::create(rotation.angle),
CSSMotionRotationNonInterpolableValue::create(rotation.type));
}
} // namespace
InterpolationValue CSSMotionRotationInterpolationType::maybeConvertNeutral(const InterpolationValue& underlying, ConversionCheckers& conversionCheckers) const
{
MotionRotationType underlyingRotationType = toCSSMotionRotationNonInterpolableValue(*underlying.nonInterpolableValue).rotationType();
conversionCheckers.append(UnderlyingRotationTypeChecker::create(underlyingRotationType));
return convertMotionRotation(StyleMotionRotation(0, underlyingRotationType));
}
InterpolationValue CSSMotionRotationInterpolationType::maybeConvertInitial() const
{
return convertMotionRotation(StyleMotionRotation(0, MotionRotationAuto));
}
InterpolationValue CSSMotionRotationInterpolationType::maybeConvertInherit(const StyleResolverState& state, ConversionCheckers& conversionCheckers) const
{
MotionRotationType inheritedRotationType = state.parentStyle()->motionRotation().type;
conversionCheckers.append(InheritedRotationTypeChecker::create(inheritedRotationType));
return convertMotionRotation(state.parentStyle()->motionRotation());
}
InterpolationValue CSSMotionRotationInterpolationType::maybeConvertValue(const CSSValue& value, const StyleResolverState&, ConversionCheckers&) const
{
return convertMotionRotation(StyleBuilderConverter::convertMotionRotation(value));
}
PairwiseInterpolationValue CSSMotionRotationInterpolationType::mergeSingleConversions(InterpolationValue& start, InterpolationValue& end) const
{
const MotionRotationType& startType = toCSSMotionRotationNonInterpolableValue(*start.nonInterpolableValue).rotationType();
const MotionRotationType& endType = toCSSMotionRotationNonInterpolableValue(*end.nonInterpolableValue).rotationType();
if (startType != endType)
return nullptr;
return PairwiseInterpolationValue(
start.interpolableValue.release(),
end.interpolableValue.release(),
start.nonInterpolableValue.release());
}
InterpolationValue CSSMotionRotationInterpolationType::maybeConvertUnderlyingValue(const InterpolationEnvironment& environment) const
{
return convertMotionRotation(environment.state().style()->motionRotation());
}
void CSSMotionRotationInterpolationType::composite(UnderlyingValueOwner& underlyingValueOwner, double underlyingFraction, const InterpolationValue& value) const
{
const MotionRotationType& underlyingType = toCSSMotionRotationNonInterpolableValue(*underlyingValueOwner.value().nonInterpolableValue).rotationType();
const MotionRotationType& rotationType = toCSSMotionRotationNonInterpolableValue(*value.nonInterpolableValue).rotationType();
if (underlyingType == rotationType)
underlyingValueOwner.mutableValue().interpolableValue->scaleAndAdd(underlyingFraction, *value.interpolableValue);
else
underlyingValueOwner.set(*this, value);
}
void CSSMotionRotationInterpolationType::apply(const InterpolableValue& interpolableValue, const NonInterpolableValue* nonInterpolableValue, InterpolationEnvironment& environment) const
{
environment.state().style()->setMotionRotation(StyleMotionRotation(
toInterpolableNumber(interpolableValue).value(),
toCSSMotionRotationNonInterpolableValue(*nonInterpolableValue).rotationType()));
}
} // namespace blink
// Copyright 2016 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CSSMotionRotationInterpolationType_h
#define CSSMotionRotationInterpolationType_h
#include "core/animation/CSSInterpolationType.h"
namespace blink {
class CSSMotionRotationInterpolationType : public CSSInterpolationType {
public:
CSSMotionRotationInterpolationType(CSSPropertyID property)
: CSSInterpolationType(property)
{
ASSERT(property == CSSPropertyMotionRotation);
}
InterpolationValue maybeConvertUnderlyingValue(const InterpolationEnvironment&) const final;
void composite(UnderlyingValueOwner&, double underlyingFraction, const InterpolationValue&) const final;
void apply(const InterpolableValue&, const NonInterpolableValue*, InterpolationEnvironment&) const final;
private:
InterpolationValue maybeConvertNeutral(const InterpolationValue& underlying, ConversionCheckers&) const final;
InterpolationValue maybeConvertInitial() const final;
InterpolationValue maybeConvertInherit(const StyleResolverState&, ConversionCheckers&) const final;
InterpolationValue maybeConvertValue(const CSSValue&, const StyleResolverState&, ConversionCheckers&) const final;
PairwiseInterpolationValue mergeSingleConversions(InterpolationValue& start, InterpolationValue& end) const final;
};
} // namespace blink
#endif // CSSMotionRotationInterpolationType_h
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "core/animation/CSSImageListInterpolationType.h" #include "core/animation/CSSImageListInterpolationType.h"
#include "core/animation/CSSLengthInterpolationType.h" #include "core/animation/CSSLengthInterpolationType.h"
#include "core/animation/CSSLengthListInterpolationType.h" #include "core/animation/CSSLengthListInterpolationType.h"
#include "core/animation/CSSMotionRotationInterpolationType.h"
#include "core/animation/CSSNumberInterpolationType.h" #include "core/animation/CSSNumberInterpolationType.h"
#include "core/animation/CSSPaintInterpolationType.h" #include "core/animation/CSSPaintInterpolationType.h"
#include "core/animation/CSSPathInterpolationType.h" #include "core/animation/CSSPathInterpolationType.h"
...@@ -170,6 +171,9 @@ const InterpolationTypes* PropertyInterpolationTypesMapping::get(const PropertyH ...@@ -170,6 +171,9 @@ const InterpolationTypes* PropertyInterpolationTypesMapping::get(const PropertyH
case CSSPropertyClip: case CSSPropertyClip:
applicableTypes->append(adoptPtr(new CSSClipInterpolationType(cssProperty))); applicableTypes->append(adoptPtr(new CSSClipInterpolationType(cssProperty)));
break; break;
case CSSPropertyMotionRotation:
applicableTypes->append(adoptPtr(new CSSMotionRotationInterpolationType(cssProperty)));
break;
default: default:
// TODO(alancutter): Support all interpolable CSS properties here so we can stop falling back to the old StyleInterpolation implementation. // TODO(alancutter): Support all interpolable CSS properties here so we can stop falling back to the old StyleInterpolation implementation.
if (CSSPropertyMetadata::isInterpolableProperty(cssProperty)) if (CSSPropertyMetadata::isInterpolableProperty(cssProperty))
......
...@@ -175,13 +175,6 @@ PassRefPtr<Interpolation> StringKeyframe::CSSPropertySpecificKeyframe::maybeCrea ...@@ -175,13 +175,6 @@ PassRefPtr<Interpolation> StringKeyframe::CSSPropertySpecificKeyframe::maybeCrea
break; break;
case CSSPropertyMotionRotation: {
RefPtr<Interpolation> interpolation = DoubleStyleInterpolation::maybeCreateFromMotionRotation(*fromCSSValue, *toCSSValue, property);
if (interpolation)
return interpolation.release();
break;
}
case CSSPropertyBorderBottomLeftRadius: case CSSPropertyBorderBottomLeftRadius:
case CSSPropertyBorderBottomRightRadius: case CSSPropertyBorderBottomRightRadius:
case CSSPropertyBorderTopLeftRadius: case CSSPropertyBorderTopLeftRadius:
......
...@@ -866,6 +866,8 @@ ...@@ -866,6 +866,8 @@
'animation/CSSLengthListInterpolationType.h', 'animation/CSSLengthListInterpolationType.h',
'animation/CSSNumberInterpolationType.cpp', 'animation/CSSNumberInterpolationType.cpp',
'animation/CSSNumberInterpolationType.h', 'animation/CSSNumberInterpolationType.h',
'animation/CSSMotionRotationInterpolationType.cpp',
'animation/CSSMotionRotationInterpolationType.h',
'animation/CSSPaintInterpolationType.cpp', 'animation/CSSPaintInterpolationType.cpp',
'animation/CSSPaintInterpolationType.h', 'animation/CSSPaintInterpolationType.h',
'animation/CSSPathInterpolationType.cpp', 'animation/CSSPathInterpolationType.cpp',
......
...@@ -629,6 +629,11 @@ float StyleBuilderConverter::convertNumberOrPercentage(StyleResolverState& state ...@@ -629,6 +629,11 @@ float StyleBuilderConverter::convertNumberOrPercentage(StyleResolverState& state
} }
StyleMotionRotation StyleBuilderConverter::convertMotionRotation(StyleResolverState&, const CSSValue& value) StyleMotionRotation StyleBuilderConverter::convertMotionRotation(StyleResolverState&, const CSSValue& value)
{
return convertMotionRotation(value);
}
StyleMotionRotation StyleBuilderConverter::convertMotionRotation(const CSSValue& value)
{ {
StyleMotionRotation result(0, MotionRotationFixed); StyleMotionRotation result(0, MotionRotationFixed);
......
...@@ -109,6 +109,7 @@ public: ...@@ -109,6 +109,7 @@ public:
static RespectImageOrientationEnum convertImageOrientation(StyleResolverState&, const CSSValue&); static RespectImageOrientationEnum convertImageOrientation(StyleResolverState&, const CSSValue&);
static PassRefPtr<StylePath> convertPath(StyleResolverState&, const CSSValue&); static PassRefPtr<StylePath> convertPath(StyleResolverState&, const CSSValue&);
static PassRefPtr<StylePath> convertPathOrNone(StyleResolverState&, const CSSValue&); static PassRefPtr<StylePath> convertPathOrNone(StyleResolverState&, const CSSValue&);
static StyleMotionRotation convertMotionRotation(const CSSValue&);
}; };
template <typename T> template <typename T>
......
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