Commit 4a69c4cc authored by ericwilligers's avatar ericwilligers Committed by Commit bot

CSS Motion Path: animate offset-anchor and offset-position

offset-position and offset-anchor are both animatable as
<position>.
https://drafts.fxtf.org/motion-1/#offset-position-property
https://drafts.fxtf.org/motion-1/#offset-anchor-property

BUG=638055

Review-Url: https://codereview.chromium.org/2364503002
Cr-Commit-Position: refs/heads/master@{#420581}
parent c76a2dea
<!DOCTYPE html>
<style>
.target {
width: 200px;
height: 200px;
}
</style>
<body>
<script src="../interpolation/resources/interpolation-test.js"></script>
<script>
assertComposition({
property: 'offset-anchor',
underlying: '40px 60px',
addFrom: '60px 40px',
addTo: '160px 140px',
}, [
{at: -0.25, is: '75px 75px'},
{at: 0, is: '100px 100px'},
{at: 0.25, is: '125px 125px'},
{at: 0.5, is: '150px 150px'},
{at: 0.75, is: '175px 175px'},
{at: 1, is: '200px 200px'},
{at: 1.25, is: '225px 225px'},
]);
assertComposition({
property: 'offset-anchor',
underlying: 'top 20% left 40%',
addFrom: 'left 60% top 80%',
addTo: 'right 80% bottom 40%',
}, [
{at: -0.25, is: '110% 105%'},
{at: 0, is: '100% 100%'},
{at: 0.25, is: '90% 95%'},
{at: 0.5, is: '80% 90%'},
{at: 0.75, is: '70% 85%'},
{at: 1, is: '60% 80%'},
{at: 1.25, is: '50% 75%'},
]);
assertComposition({
property: 'offset-anchor',
underlying: '40px 60px',
replaceFrom: '100px 200px',
addTo: '160px 40px',
}, [
{at: -0.25, is: '75px 225px'},
{at: 0, is: '100px 200px'},
{at: 0.25, is: '125px 175px'},
{at: 0.5, is: '150px 150px'},
{at: 0.75, is: '175px 125px'},
{at: 1, is: '200px 100px'},
{at: 1.25, is: '225px 75px'},
]);
assertComposition({
property: 'offset-anchor',
underlying: '40px 60px',
addFrom: '60px 140px',
replaceTo: '200px 100px',
}, [
{at: -0.25, is: '75px 225px'},
{at: 0, is: '100px 200px'},
{at: 0.25, is: '125px 175px'},
{at: 0.5, is: '150px 150px'},
{at: 0.75, is: '175px 125px'},
{at: 1, is: '200px 100px'},
{at: 1.25, is: '225px 75px'},
]);
</script>
</body>
<!DOCTYPE html>
<style>
.target {
width: 200px;
height: 200px;
}
</style>
<body>
<script src="../interpolation/resources/interpolation-test.js"></script>
<script>
assertComposition({
property: 'offset-position',
underlying: '40px 60px',
addFrom: '60px 40px',
addTo: '160px 140px',
}, [
{at: -0.25, is: '75px 75px'},
{at: 0, is: '100px 100px'},
{at: 0.25, is: '125px 125px'},
{at: 0.5, is: '150px 150px'},
{at: 0.75, is: '175px 175px'},
{at: 1, is: '200px 200px'},
{at: 1.25, is: '225px 225px'},
]);
assertComposition({
property: 'offset-position',
underlying: 'top 20% left 40%',
addFrom: 'left 60% top 80%',
addTo: 'right 80% bottom 40%',
}, [
{at: -0.25, is: '110% 105%'},
{at: 0, is: '100% 100%'},
{at: 0.25, is: '90% 95%'},
{at: 0.5, is: '80% 90%'},
{at: 0.75, is: '70% 85%'},
{at: 1, is: '60% 80%'},
{at: 1.25, is: '50% 75%'},
]);
assertComposition({
property: 'offset-position',
underlying: '40px 60px',
replaceFrom: '100px 200px',
addTo: '160px 40px',
}, [
{at: -0.25, is: '75px 225px'},
{at: 0, is: '100px 200px'},
{at: 0.25, is: '125px 175px'},
{at: 0.5, is: '150px 150px'},
{at: 0.75, is: '175px 125px'},
{at: 1, is: '200px 100px'},
{at: 1.25, is: '225px 75px'},
]);
assertComposition({
property: 'offset-position',
underlying: '40px 60px',
addFrom: '60px 140px',
replaceTo: '200px 100px',
}, [
{at: -0.25, is: '75px 225px'},
{at: 0, is: '100px 200px'},
{at: 0.25, is: '125px 175px'},
{at: 0.5, is: '150px 150px'},
{at: 0.75, is: '175px 125px'},
{at: 1, is: '200px 100px'},
{at: 1.25, is: '225px 75px'},
]);
</script>
</body>
<!DOCTYPE html>
<meta charset="UTF-8">
<style>
.parent {
offset-anchor: 30px 10px;
}
.target {
offset-anchor: 10px 30px;
}
</style>
<body>
<template id="target-template">
<div><div class="transformed"></div></div>
</template>
<script src="resources/interpolation-test.js"></script>
<script>
assertInterpolation({
property: 'offset-anchor',
from: neutralKeyframe,
to: '20px 20px',
}, [
{at: -0.3, is: '7px 33px'},
{at: 0, is: '10px 30px'},
{at: 0.3, is: '13px 27px'},
{at: 0.6, is: '16px 24px'},
{at: 1, is: '20px 20px'},
{at: 1.5, is: '25px 15px'},
]);
assertInterpolation({
property: 'offset-anchor',
from: 'initial',
to: '60% 40%',
}, [
{at: -0.3, is: '47% 53%'},
{at: 0, is: '50% 50%'},
{at: 0.3, is: '53% 47%'},
{at: 0.6, is: '56% 44%'},
{at: 1, is: '60% 40%'},
{at: 1.5, is: '65% 35%'},
]);
assertInterpolation({
property: 'offset-anchor',
from: 'inherit',
to: '20px 20px',
}, [
{at: -0.3, is: '33px 7px'},
{at: 0, is: '30px 10px'},
{at: 0.3, is: '27px 13px'},
{at: 0.6, is: '24px 16px'},
{at: 1, is: '20px 20px'},
{at: 1.5, is: '15px 25px'},
]);
assertInterpolation({
property: 'offset-anchor',
from: 'unset',
to: '50% 10px',
}, [
{at: -0.3, is: '50% calc(-3px + 65%)'},
{at: 0, is: '50% 50%'},
{at: 0.3, is: '50% calc(3px + 35%)'},
{at: 0.6, is: '50% calc(6px + 20%)'},
{at: 1, is: '50% 10px'},
{at: 1.5, is: '50% calc(15px - 25%)'},
]);
assertInterpolation({
property: 'offset-anchor',
from: '0% 50%',
to: '100% 150%'
}, [
{at: -0.3, is: '-30% 20%'},
{at: 0, is: '0% 50%'},
{at: 0.3, is: '30% 80%'},
{at: 0.6, is: '60% 110%'},
{at: 1, is: '100% 150%'},
{at: 1.5, is: '150% 200%'}
]);
assertNoInterpolation({
property: 'offset-anchor',
from: 'auto',
to: '20px 20px',
});
</script>
</body>
<!DOCTYPE html>
<meta charset="UTF-8">
<style>
.parent {
offset-position: 30px 10px;
}
.target {
offset-position: 10px 30px;
}
</style>
<body>
<template id="target-template">
<div><div class="transformed"></div></div>
</template>
<script src="resources/interpolation-test.js"></script>
<script>
assertInterpolation({
property: 'offset-position',
from: neutralKeyframe,
to: '20px 20px',
}, [
{at: -0.3, is: '7px 33px'},
{at: 0, is: '10px 30px'},
{at: 0.3, is: '13px 27px'},
{at: 0.6, is: '16px 24px'},
{at: 1, is: '20px 20px'},
{at: 1.5, is: '25px 15px'},
]);
assertNoInterpolation({
property: 'offset-position',
from: 'initial',
to: '20px 20px',
});
assertInterpolation({
property: 'offset-position',
from: 'inherit',
to: '20px 20px',
}, [
{at: -0.3, is: '33px 7px'},
{at: 0, is: '30px 10px'},
{at: 0.3, is: '27px 13px'},
{at: 0.6, is: '24px 16px'},
{at: 1, is: '20px 20px'},
{at: 1.5, is: '15px 25px'},
]);
assertNoInterpolation({
property: 'offset-position',
from: 'unset',
to: '20px 20px',
});
assertInterpolation({
property: 'offset-position',
from: '0% 50%',
to: '100% 150%'
}, [
{at: -0.3, is: '-30% 20%'},
{at: 0, is: '0% 50%'},
{at: 0.3, is: '30% 80%'},
{at: 0.6, is: '60% 110%'},
{at: 1, is: '100% 150%'},
{at: 1.5, is: '150% 200%'}
]);
assertNoInterpolation({
property: 'offset-position',
from: 'auto',
to: '20px 20px',
});
</script>
</body>
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#include "core/animation/CSSPositionAxisListInterpolationType.h" #include "core/animation/CSSPositionAxisListInterpolationType.h"
#include "core/animation/ListInterpolationFunctions.h" #include "core/animation/ListInterpolationFunctions.h"
#include "core/css/CSSPrimitiveValue.h"
#include "core/css/CSSValuePair.h" #include "core/css/CSSValuePair.h"
namespace blink { namespace blink {
...@@ -22,6 +23,9 @@ public: ...@@ -22,6 +23,9 @@ public:
private: private:
InterpolationValue maybeConvertValue(const CSSValue& value, const StyleResolverState&, ConversionCheckers&) const final InterpolationValue maybeConvertValue(const CSSValue& value, const StyleResolverState&, ConversionCheckers&) const final
{ {
if (!value.isValuePair()) {
return nullptr;
}
const CSSValuePair& pair = toCSSValuePair(value); const CSSValuePair& pair = toCSSValuePair(value);
return ListInterpolationFunctions::createList(2, [&pair](size_t index) { return ListInterpolationFunctions::createList(2, [&pair](size_t index) {
return CSSPositionAxisListInterpolationType::convertPositionAxisCSSValue(index == 0 ? pair.first() : pair.second()); return CSSPositionAxisListInterpolationType::convertPositionAxisCSSValue(index == 0 ? pair.first() : pair.second());
......
...@@ -82,6 +82,8 @@ ValueRange LengthListPropertyFunctions::getValueRange(CSSPropertyID property) ...@@ -82,6 +82,8 @@ ValueRange LengthListPropertyFunctions::getValueRange(CSSPropertyID property)
case CSSPropertyBackgroundPositionX: case CSSPropertyBackgroundPositionX:
case CSSPropertyBackgroundPositionY: case CSSPropertyBackgroundPositionY:
case CSSPropertyObjectPosition: case CSSPropertyObjectPosition:
case CSSPropertyOffsetAnchor:
case CSSPropertyOffsetPosition:
case CSSPropertyPerspectiveOrigin: case CSSPropertyPerspectiveOrigin:
case CSSPropertyTransformOrigin: case CSSPropertyTransformOrigin:
case CSSPropertyWebkitMaskPositionX: case CSSPropertyWebkitMaskPositionX:
...@@ -141,6 +143,10 @@ bool LengthListPropertyFunctions::getLengthList(CSSPropertyID property, const Co ...@@ -141,6 +143,10 @@ bool LengthListPropertyFunctions::getLengthList(CSSPropertyID property, const Co
case CSSPropertyObjectPosition: case CSSPropertyObjectPosition:
return appendToVector(style.objectPosition(), result); return appendToVector(style.objectPosition(), result);
case CSSPropertyOffsetAnchor:
return appendToVector(style.offsetAnchor(), result);
case CSSPropertyOffsetPosition:
return appendToVector(style.offsetPosition(), result);
case CSSPropertyPerspectiveOrigin: case CSSPropertyPerspectiveOrigin:
return appendToVector(style.perspectiveOrigin(), result); return appendToVector(style.perspectiveOrigin(), result);
case CSSPropertyBorderBottomLeftRadius: case CSSPropertyBorderBottomLeftRadius:
...@@ -201,6 +207,12 @@ void LengthListPropertyFunctions::setLengthList(CSSPropertyID property, Computed ...@@ -201,6 +207,12 @@ void LengthListPropertyFunctions::setLengthList(CSSPropertyID property, Computed
case CSSPropertyObjectPosition: case CSSPropertyObjectPosition:
style.setObjectPosition(pointFromVector(lengthList)); style.setObjectPosition(pointFromVector(lengthList));
return; return;
case CSSPropertyOffsetAnchor:
style.setOffsetAnchor(pointFromVector(lengthList));
return;
case CSSPropertyOffsetPosition:
style.setOffsetPosition(pointFromVector(lengthList));
return;
case CSSPropertyPerspectiveOrigin: case CSSPropertyPerspectiveOrigin:
style.setPerspectiveOrigin(pointFromVector(lengthList)); style.setPerspectiveOrigin(pointFromVector(lengthList));
return; return;
......
...@@ -197,6 +197,8 @@ const InterpolationTypes& PropertyInterpolationTypesMapping::get(const PropertyH ...@@ -197,6 +197,8 @@ const InterpolationTypes& PropertyInterpolationTypesMapping::get(const PropertyH
applicableTypes->append(wrapUnique(new CSSPositionAxisListInterpolationType(cssProperty))); applicableTypes->append(wrapUnique(new CSSPositionAxisListInterpolationType(cssProperty)));
break; break;
case CSSPropertyObjectPosition: case CSSPropertyObjectPosition:
case CSSPropertyOffsetAnchor:
case CSSPropertyOffsetPosition:
case CSSPropertyPerspectiveOrigin: case CSSPropertyPerspectiveOrigin:
applicableTypes->append(wrapUnique(new CSSPositionInterpolationType(cssProperty))); applicableTypes->append(wrapUnique(new CSSPositionInterpolationType(cssProperty)));
break; break;
......
...@@ -32,6 +32,12 @@ ...@@ -32,6 +32,12 @@
namespace blink { namespace blink {
bool AnimatableLengthPoint::usesDefaultInterpolationWith(const AnimatableValue* value) const
{
const AnimatableLengthPoint* other = toAnimatableLengthPoint(value);
return this->x()->isUnknown() || other->x()->isUnknown();
}
PassRefPtr<AnimatableValue> AnimatableLengthPoint::interpolateTo(const AnimatableValue* value, double fraction) const PassRefPtr<AnimatableValue> AnimatableLengthPoint::interpolateTo(const AnimatableValue* value, double fraction) const
{ {
const AnimatableLengthPoint* lengthPoint = toAnimatableLengthPoint(value); const AnimatableLengthPoint* lengthPoint = toAnimatableLengthPoint(value);
......
...@@ -47,6 +47,7 @@ public: ...@@ -47,6 +47,7 @@ public:
protected: protected:
PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const override; PassRefPtr<AnimatableValue> interpolateTo(const AnimatableValue*, double fraction) const override;
bool usesDefaultInterpolationWith(const AnimatableValue*) const override;
private: private:
AnimatableLengthPoint(PassRefPtr<AnimatableValue> x, PassRefPtr<AnimatableValue> y) AnimatableLengthPoint(PassRefPtr<AnimatableValue> x, PassRefPtr<AnimatableValue> y)
......
...@@ -550,12 +550,16 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop ...@@ -550,12 +550,16 @@ PassRefPtr<AnimatableValue> CSSAnimatableValueFactory::create(CSSPropertyID prop
DEFINE_STATIC_REF(ScaleTransformOperation, initialScale, ScaleTransformOperation::create(1, 1, 1, TransformOperation::Scale3D)); DEFINE_STATIC_REF(ScaleTransformOperation, initialScale, ScaleTransformOperation::create(1, 1, 1, TransformOperation::Scale3D));
return createFromTransformProperties(style.scale(), style.effectiveZoom(), initialScale); return createFromTransformProperties(style.scale(), style.effectiveZoom(), initialScale);
} }
case CSSPropertyTransformOrigin: case CSSPropertyOffsetAnchor:
return createFromTransformOrigin(style.transformOrigin(), style); return createFromLengthPoint(style.offsetAnchor(), style);
case CSSPropertyOffsetDistance: case CSSPropertyOffsetDistance:
return createFromLength(style.offsetDistance(), style); return createFromLength(style.offsetDistance(), style);
case CSSPropertyOffsetPosition:
return createFromLengthPoint(style.offsetPosition(), style);
case CSSPropertyOffsetRotation: case CSSPropertyOffsetRotation:
return createFromDoubleAndBool(style.offsetRotation().angle, style.offsetRotation().type == OffsetRotationAuto, style); return createFromDoubleAndBool(style.offsetRotation().angle, style.offsetRotation().type == OffsetRotationAuto, style);
case CSSPropertyTransformOrigin:
return createFromTransformOrigin(style.transformOrigin(), style);
case CSSPropertyWebkitPerspectiveOriginX: case CSSPropertyWebkitPerspectiveOriginX:
return createFromLength(style.perspectiveOriginX(), style); return createFromLength(style.perspectiveOriginX(), style);
case CSSPropertyWebkitPerspectiveOriginY: case CSSPropertyWebkitPerspectiveOriginY:
......
...@@ -275,10 +275,10 @@ motion-path alias_for=offset-path ...@@ -275,10 +275,10 @@ motion-path alias_for=offset-path
motion-rotation alias_for=offset-rotation motion-rotation alias_for=offset-rotation
object-fit type_name=ObjectFit object-fit type_name=ObjectFit
object-position interpolable, converter=convertPosition object-position interpolable, converter=convertPosition
offset-anchor runtime_flag=CSSOffsetPositionAnchor, converter=convertPositionOrAuto offset-anchor runtime_flag=CSSOffsetPositionAnchor, interpolable, converter=convertPositionOrAuto
offset-distance interpolable, converter=convertLength offset-distance interpolable, converter=convertLength
offset-path converter=convertPathOrNone offset-path converter=convertPathOrNone
offset-position runtime_flag=CSSOffsetPositionAnchor, converter=convertPositionOrAuto offset-position runtime_flag=CSSOffsetPositionAnchor, interpolable, converter=convertPositionOrAuto
offset-rotation interpolable, converter=convertOffsetRotation offset-rotation interpolable, converter=convertOffsetRotation
opacity interpolable, type_name=float opacity interpolable, type_name=float
order type_name=int order type_name=int
......
...@@ -175,12 +175,16 @@ bool CSSPropertyEquality::propertiesEqual(CSSPropertyID prop, const ComputedStyl ...@@ -175,12 +175,16 @@ bool CSSPropertyEquality::propertiesEqual(CSSPropertyID prop, const ComputedStyl
return a.minHeight() == b.minHeight(); return a.minHeight() == b.minHeight();
case CSSPropertyMinWidth: case CSSPropertyMinWidth:
return a.minWidth() == b.minWidth(); return a.minWidth() == b.minWidth();
case CSSPropertyObjectPosition:
return a.objectPosition() == b.objectPosition();
case CSSPropertyOffsetAnchor:
return a.offsetAnchor() == b.offsetAnchor();
case CSSPropertyOffsetDistance: case CSSPropertyOffsetDistance:
return a.offsetDistance() == b.offsetDistance(); return a.offsetDistance() == b.offsetDistance();
case CSSPropertyOffsetPosition:
return a.offsetPosition() == b.offsetPosition();
case CSSPropertyOffsetRotation: case CSSPropertyOffsetRotation:
return a.offsetRotation() == b.offsetRotation(); return a.offsetRotation() == b.offsetRotation();
case CSSPropertyObjectPosition:
return a.objectPosition() == b.objectPosition();
case CSSPropertyOpacity: case CSSPropertyOpacity:
return a.opacity() == b.opacity(); return a.opacity() == b.opacity();
case CSSPropertyOrphans: case CSSPropertyOrphans:
......
...@@ -641,9 +641,15 @@ void AnimatedStyleBuilder::applyProperty(CSSPropertyID property, StyleResolverSt ...@@ -641,9 +641,15 @@ void AnimatedStyleBuilder::applyProperty(CSSPropertyID property, StyleResolverSt
case CSSPropertyTransformOrigin: case CSSPropertyTransformOrigin:
style->setTransformOrigin(animatableValueToTransformOrigin(value, state)); style->setTransformOrigin(animatableValueToTransformOrigin(value, state));
return; return;
case CSSPropertyOffsetAnchor:
style->setOffsetAnchor(animatableValueToLengthPoint(value, state));
return;
case CSSPropertyOffsetDistance: case CSSPropertyOffsetDistance:
style->setOffsetDistance(animatableValueToLength(value, state)); style->setOffsetDistance(animatableValueToLength(value, state));
return; return;
case CSSPropertyOffsetPosition:
style->setOffsetPosition(animatableValueToLengthPoint(value, state));
return;
case CSSPropertyOffsetRotation: case CSSPropertyOffsetRotation:
style->setOffsetRotation(StyleOffsetRotation( style->setOffsetRotation(StyleOffsetRotation(
toAnimatableDoubleAndBool(value)->toDouble(), toAnimatableDoubleAndBool(value)->toDouble(),
......
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