Bug 1837305 - Part 6: Update AnimationValue for offset-path. r=emilio

We are using NonNegative now for offset-path, so just like clip-path, we
have to make sure we don't get the negative radius for circle and ellipse,
and don't get the negative border-radius for inset. Therefore, we have to
convert the computed value into animated value when doing interpolation,
and then clamp the value to make sure it is always >= 0 when converting
it back to computed value, just like what we do for clip-path in Bug 1512883.

Also drop the normalization of SVGPathData in AnimationInfo when
preparing offset-path for compositor animations. It's useless because we
"always" do normalization in SVGPathData::animate().

Differential Revision: https://phabricator.services.mozilla.com/D180284
This commit is contained in:
Boris Chiou 2023-06-15 00:04:00 +00:00
parent 0307742927
commit 4b8c77479a
13 changed files with 33 additions and 88 deletions

View File

@ -20,9 +20,11 @@
#include "mozilla/layers/APZSampler.h" // for APZSampler
#include "mozilla/layers/CompositorThread.h" // for CompositorThreadHolder
#include "mozilla/LayerAnimationInfo.h" // for GetCSSPropertiesFor()
#include "mozilla/Maybe.h" // for Maybe<>
#include "mozilla/MotionPathUtils.h" // for ResolveMotionPath()
#include "mozilla/ServoBindings.h" // for Servo_ComposeAnimationSegment, etc
#include "mozilla/StyleAnimationValue.h" // for StyleAnimationValue, etc
#include "nsCSSPropertyID.h" // for eCSSProperty_offset_path, etc
#include "nsDeviceContext.h" // for AppUnitsPerCSSPixel
#include "nsDisplayList.h" // for nsDisplayTransform, etc
@ -498,8 +500,8 @@ AnimationStorageData AnimationHelper::ExtractAnimations(
"Fixed offset-path should have base style");
MOZ_ASSERT(HasTransformLikeAnimations(aAnimations));
AnimationValue value{currData->mBaseStyle};
const StyleOffsetPath& offsetPath = value.GetOffsetPathProperty();
const StyleOffsetPath& offsetPath =
animation.baseStyle().get_StyleOffsetPath();
// FIXME: Bug 1837042. Cache all basic shapes.
if (offsetPath.IsOffsetPath() &&
offsetPath.AsOffsetPath().path->IsShape() &&
@ -618,7 +620,7 @@ gfx::Matrix4x4 AnimationHelper::ServoAnimationValueToMatrix4x4(
const StyleRotate* rotate = nullptr;
const StyleScale* scale = nullptr;
const StyleTransform* transform = nullptr;
const StyleOffsetPath* path = nullptr;
Maybe<StyleOffsetPath> path;
const StyleLengthPercentage* distance = nullptr;
const StyleOffsetRotate* offsetRotate = nullptr;
const StylePositionOrAuto* anchor = nullptr;
@ -646,7 +648,8 @@ gfx::Matrix4x4 AnimationHelper::ServoAnimationValueToMatrix4x4(
break;
case eCSSProperty_offset_path:
MOZ_ASSERT(!path);
path = Servo_AnimationValue_GetOffsetPath(value);
path.emplace(StyleOffsetPath::None());
Servo_AnimationValue_GetOffsetPath(value, path.ptr());
break;
case eCSSProperty_offset_distance:
MOZ_ASSERT(!distance);
@ -671,7 +674,7 @@ gfx::Matrix4x4 AnimationHelper::ServoAnimationValueToMatrix4x4(
TransformReferenceBox refBox(nullptr, aTransformData.bounds());
Maybe<ResolvedMotionPathData> motion = MotionPathUtils::ResolveMotionPath(
path, distance, offsetRotate, anchor, position,
path.ptrOr(nullptr), distance, offsetRotate, anchor, position,
aTransformData.motionPathData(), refBox, aCachedMotionPath);
// We expect all our transform data to arrive in device pixels

View File

@ -333,18 +333,6 @@ static Maybe<ScrollTimelineOptions> GetScrollTimelineOptions(
return Some(ScrollTimelineOptions(source, timeline->Axis()));
}
static StyleOffsetPath NormalizeOffsetPath(const StyleOffsetPath& aOffsetPath) {
// Named Return Value Optimization.
StyleOffsetPath result(aOffsetPath);
if (aOffsetPath.IsOffsetPath() &&
aOffsetPath.AsOffsetPath().path->IsShape() &&
aOffsetPath.AsOffsetPath().path->AsShape().IsPath()) {
result.UpdateShapePath(MotionPathUtils::NormalizeSVGPathData(
aOffsetPath.AsOffsetPath().path->AsShape().AsPath().path));
}
return result;
}
static void SetAnimatable(nsCSSPropertyID aProperty,
const AnimationValue& aAnimationValue,
nsIFrame* aFrame, TransformReferenceBox& aRefBox,
@ -383,8 +371,8 @@ static void SetAnimatable(nsCSSPropertyID aProperty,
aAnimationValue.GetTransformProperty(), aRefBox);
break;
case eCSSProperty_offset_path:
aAnimatable =
NormalizeOffsetPath(aAnimationValue.GetOffsetPathProperty());
aAnimatable = StyleOffsetPath::None();
aAnimationValue.GetOffsetPathProperty(aAnimatable.get_StyleOffsetPath());
break;
case eCSSProperty_offset_distance:
aAnimatable = aAnimationValue.GetOffsetDistanceProperty();
@ -866,7 +854,7 @@ void AnimationInfo::AddNonAnimatingTransformLikePropertiesStyles(
break;
case eCSSProperty_offset_path:
if (!display->mOffsetPath.IsNone()) {
appendFakeAnimation(id, NormalizeOffsetPath(display->mOffsetPath));
appendFakeAnimation(id, display->mOffsetPath);
}
break;
case eCSSProperty_offset_distance:

View File

@ -486,14 +486,6 @@ Maybe<ResolvedMotionPathData> MotionPathUtils::ResolveMotionPath(
aRefBox, aMotionPathData->anchorAdjustment());
}
/* static */
StyleSVGPathData MotionPathUtils::NormalizeSVGPathData(
const StyleSVGPathData& aPath) {
StyleSVGPathData n;
Servo_SVGPathData_Normalize(&aPath, &n);
return n;
}
/* static */
already_AddRefed<gfx::Path> MotionPathUtils::BuildPath(
const StyleSVGPathData& aPath, gfx::PathBuilder* aPathBuilder) {

View File

@ -204,17 +204,6 @@ class MotionPathUtils final {
const Maybe<layers::MotionPathData>& aMotionPathData,
TransformReferenceBox&, gfx::Path* aCachedMotionPath);
/**
* Normalize StyleSVGPathData.
*
* The algorithm of normalization is the same as normalize() in
* servo/components/style/values/specified/svg_path.rs
* FIXME: Bug 1489392: We don't have to normalize the path here if we accept
* the spec issue which would like to normalize svg paths at computed time.
* https://github.com/w3c/svgwg/issues/321
*/
static StyleSVGPathData NormalizeSVGPathData(const StyleSVGPathData& aPath);
/**
* Build a gfx::Path from the computed svg path. We should give it a path
* builder. If |aPathBuilder| is nullptr, we return null path.

View File

@ -87,9 +87,9 @@ const StyleTransform& AnimationValue::GetTransformProperty() const {
return *Servo_AnimationValue_GetTransform(mServo);
}
const mozilla::StyleOffsetPath& AnimationValue::GetOffsetPathProperty() const {
void AnimationValue::GetOffsetPathProperty(StyleOffsetPath& aOffsetPath) const {
MOZ_ASSERT(mServo);
return *Servo_AnimationValue_GetOffsetPath(mServo);
Servo_AnimationValue_GetOffsetPath(mServo, &aOffsetPath);
}
const mozilla::LengthPercentage& AnimationValue::GetOffsetDistanceProperty()

View File

@ -77,7 +77,10 @@ struct AnimationValue {
const mozilla::StyleRotate& GetRotateProperty() const;
// Motion path properties.
const mozilla::StyleOffsetPath& GetOffsetPathProperty() const;
// Note: This clones the StyleOffsetPath object from its AnimatedValue, so
// this may be expensive if the path is a complex SVG path or polygon. The
// caller should be aware of this performance impact.
void GetOffsetPathProperty(StyleOffsetPath& aOffsetPath) const;
const mozilla::LengthPercentage& GetOffsetDistanceProperty() const;
const mozilla::StyleOffsetRotate& GetOffsetRotateProperty() const;
const mozilla::StylePositionOrAuto& GetOffsetAnchorProperty() const;

View File

@ -216,7 +216,7 @@ ${helpers.predefined_type(
"OffsetPath",
"computed::OffsetPath::none()",
engines="gecko",
animation_value_type="ComputedValue",
animation_value_type="motion::OffsetPath",
gecko_pref="layout.css.motion-path.enabled",
flags="CAN_ANIMATE_ON_COMPOSITOR",
spec="https://drafts.fxtf.org/motion-1/#offset-path-property",

View File

@ -367,7 +367,9 @@ pub struct PolygonCoord<LengthPercentage>(pub LengthPercentage, pub LengthPercen
#[allow(missing_docs)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(
Animate,
Clone,
ComputeSquaredDistance,
Copy,
Debug,
Deserialize,
@ -413,7 +415,6 @@ pub enum FillRule {
pub struct Path {
/// The filling rule for the svg path.
#[css(skip_if = "is_default")]
#[animation(constant)]
pub fill: FillRule,
/// The svg path data.
pub path: SVGPathData,

View File

@ -26,6 +26,7 @@ use style_traits::{CssWriter, ToCss};
PartialEq,
Serialize,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
ToResolvedValue,
@ -53,6 +54,7 @@ pub enum RaySize {
PartialEq,
Serialize,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToResolvedValue,
ToShmem,
@ -118,6 +120,7 @@ where
PartialEq,
Serialize,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
ToResolvedValue,
@ -150,6 +153,7 @@ pub use self::GenericOffsetPathFunction as OffsetPathFunction;
PartialEq,
Serialize,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
ToResolvedValue,

View File

@ -45,6 +45,7 @@ pub type OffsetPosition = generics::GenericOffsetPosition<HorizontalPosition, Ve
PartialEq,
Serialize,
SpecifiedValueInfo,
ToAnimatedValue,
ToComputedValue,
ToCss,
ToResolvedValue,

View File

@ -975,12 +975,3 @@ renaming_overrides_prefixing = true
return StyleFontPalette{StyleAtom(nsGkAtoms::normal->ToAddRefed())};
}
"""
"GenericOffsetPath" = """
void UpdateShapePath(const StyleSVGPathData& aPath) {
MOZ_ASSERT(IsOffsetPath() && AsOffsetPath().path->IsShape() &&
AsOffsetPath().path->AsShape().IsPath(),
"Only for path()");
offset_path.path->shape._0.path._0.path = aPath;
}
"""

View File

@ -816,9 +816,13 @@ pub unsafe extern "C" fn Servo_AnimationValue_GetTransform(
#[no_mangle]
pub unsafe extern "C" fn Servo_AnimationValue_GetOffsetPath(
value: &AnimationValue,
) -> *const computed::motion::OffsetPath {
output: &mut computed::motion::OffsetPath,
) {
use style::values::animated::ToAnimatedValue;
match *value {
AnimationValue::OffsetPath(ref value) => value,
AnimationValue::OffsetPath(ref value) => {
*output = ToAnimatedValue::from_animated_value(value.clone())
},
_ => unreachable!("Expected offset-path"),
}
}
@ -893,7 +897,8 @@ pub unsafe extern "C" fn Servo_AnimationValue_Transform(
pub unsafe extern "C" fn Servo_AnimationValue_OffsetPath(
p: &computed::motion::OffsetPath,
) -> Strong<AnimationValue> {
Arc::new(AnimationValue::OffsetPath(p.clone())).into()
use style::values::animated::ToAnimatedValue;
Arc::new(AnimationValue::OffsetPath(p.clone().to_animated_value())).into()
}
#[no_mangle]
@ -1054,14 +1059,6 @@ impl_basic_serde_funcs!(
ComputedTimingFunction
);
#[no_mangle]
pub extern "C" fn Servo_SVGPathData_Normalize(
input: &specified::SVGPathData,
output: &mut specified::SVGPathData,
) {
*output = input.normalize();
}
// Return the ComputedValues by a base ComputedValues and the rules.
fn resolve_rules_for_element_with_context<'a>(
element: GeckoElement<'a>,

View File

@ -26,18 +26,6 @@
[CSS Transitions: property <offset-path> from [initial\] to [ellipse()\] at (0.3) should be [initial\]]
expected: FAIL
[CSS Transitions: property <offset-path> from [inherit\] to [ellipse(40% 50% at 25% 25%)\] at (-0.3) should be [ellipse(1% 0% at 57.5% 57.5%)\]]
expected: FAIL
[CSS Transitions with transition: all: property <offset-path> from [inherit\] to [ellipse(40% 50% at 25% 25%)\] at (-0.3) should be [ellipse(1% 0% at 57.5% 57.5%)\]]
expected: FAIL
[CSS Animations: property <offset-path> from [inherit\] to [ellipse(40% 50% at 25% 25%)\] at (-0.3) should be [ellipse(1% 0% at 57.5% 57.5%)\]]
expected: FAIL
[Web Animations: property <offset-path> from [inherit\] to [ellipse(40% 50% at 25% 25%)\] at (-0.3) should be [ellipse(1% 0% at 57.5% 57.5%)\]]
expected: FAIL
[CSS Transitions: property <offset-path> from [unset\] to [inset(10%)\] at (-0.3) should be [unset\]]
expected: FAIL
@ -131,18 +119,6 @@
[Web Animations: property <offset-path> from [none\] to [rect(10px 10px 10px 10px)\] at (1.5) should be [rect(10px 10px 10px 10px)\]]
expected: FAIL
[CSS Transitions: property <offset-path> from [inset(10px)\] to [inset(20px round 50%)\] at (-1) should be [inset(0px round 0%)\]]
expected: FAIL
[CSS Transitions with transition: all: property <offset-path> from [inset(10px)\] to [inset(20px round 50%)\] at (-1) should be [inset(0px round 0%)\]]
expected: FAIL
[CSS Animations: property <offset-path> from [inset(10px)\] to [inset(20px round 50%)\] at (-1) should be [inset(0px round 0%)\]]
expected: FAIL
[Web Animations: property <offset-path> from [inset(10px)\] to [inset(20px round 50%)\] at (-1) should be [inset(0px round 0%)\]]
expected: FAIL
[CSS Transitions: property <offset-path> from [xywh(5px 5px 150% 150%)\] to [xywh(10px 10px 100% 100%)\] at (-1) should be [xywh(0px 0px 200% 200%)\]]
expected: FAIL