mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 03:15:11 +00:00
Bug 1429301 - Implement offset-rotate. r=emilio
This includes style system and layout update. I add 3 extra reftests because the original tests use ray() function as the offset-path, but we don't support it. It'd be better to add tests using a different type of offset-path. The spec issue about the serialization: https://github.com/w3c/fxtf-drafts/issues/340 Differential Revision: https://phabricator.services.mozilla.com/D32212 --HG-- extra : moz-landing-system : lando
This commit is contained in:
parent
234389cf17
commit
3b51b642f3
@ -210,7 +210,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
|
||||
"min-block-size",
|
||||
"-moz-min-font-size-ratio",
|
||||
"min-inline-size",
|
||||
"offset-path",
|
||||
"offset-rotate",
|
||||
"padding-block-end",
|
||||
"padding-block-start",
|
||||
"padding-inline-end",
|
||||
@ -268,6 +268,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
|
||||
"mask-position-y",
|
||||
"mask-size",
|
||||
"object-position",
|
||||
"offset-path",
|
||||
"order",
|
||||
"perspective-origin",
|
||||
"shape-outside",
|
||||
|
@ -3090,6 +3090,7 @@ exports.CSS_PROPERTIES = {
|
||||
"translate",
|
||||
"offset-path",
|
||||
"offset-distance",
|
||||
"offset-rotate",
|
||||
"scroll-behavior",
|
||||
"scroll-snap-align",
|
||||
"scroll-snap-type",
|
||||
@ -8309,6 +8310,21 @@ exports.CSS_PROPERTIES = {
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"offset-rotate": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
"offset-rotate"
|
||||
],
|
||||
"supports": [],
|
||||
"values": [
|
||||
"auto",
|
||||
"inherit",
|
||||
"initial",
|
||||
"reverse",
|
||||
"revert",
|
||||
"unset"
|
||||
]
|
||||
},
|
||||
"opacity": {
|
||||
"isInherited": false,
|
||||
"subproperties": [
|
||||
@ -10655,6 +10671,10 @@ exports.PREFERENCES = [
|
||||
"-moz-osx-font-smoothing",
|
||||
"layout.css.osx-font-smoothing.enabled"
|
||||
],
|
||||
[
|
||||
"offset-rotate",
|
||||
"layout.css.motion-path.enabled"
|
||||
],
|
||||
[
|
||||
"overflow-anchor",
|
||||
"layout.css.scroll-anchoring.enabled"
|
||||
|
@ -9951,7 +9951,7 @@ Maybe<MotionPathData> nsLayoutUtils::ResolveMotionPath(const nsIFrame* aFrame) {
|
||||
return Nothing();
|
||||
}
|
||||
|
||||
gfx::Float angle = 0.0;
|
||||
double directionAngle = 0.0;
|
||||
Point point;
|
||||
if (display->mOffsetPath.IsPath()) {
|
||||
const Span<const StylePathCommand>& path =
|
||||
@ -9999,16 +9999,22 @@ Maybe<MotionPathData> nsLayoutUtils::ResolveMotionPath(const nsIFrame* aFrame) {
|
||||
}
|
||||
Point tangent;
|
||||
point = gfxPath->ComputePointAtLength(usedDistance, &tangent);
|
||||
// Bug 1429301 - Implement offset-rotate for motion path.
|
||||
// After implement offset-rotate, |angle| will be adjusted more.
|
||||
// For now, the default value of offset-rotate is "auto", so we use the
|
||||
// directional tangent vector.
|
||||
angle = atan2(tangent.y, tangent.x);
|
||||
directionAngle = (double)atan2(tangent.y, tangent.x); // In Radian.
|
||||
} else {
|
||||
// Bug 1480665: Implement ray() function.
|
||||
NS_WARNING("Unsupported offset-path value");
|
||||
}
|
||||
|
||||
const StyleOffsetRotate& rotate = display->mOffsetRotate;
|
||||
// If |rotate.auto_| is true, the element should be rotated by the angle of
|
||||
// the direction (i.e. directional tangent vector) of the offset-path, and the
|
||||
// computed value of <angle> is added to this.
|
||||
// Otherwise, the element has a constant clockwise rotation transformation
|
||||
// applied to it by the specified rotation angle. (i.e. Don't need to
|
||||
// consider the direction of the path.)
|
||||
gfx::Float angle = static_cast<gfx::Float>(
|
||||
(rotate.auto_ ? directionAngle : 0.0) + rotate.angle.ToRadians());
|
||||
|
||||
// Compute the offset for motion path translate.
|
||||
// We need to resolve transform-origin here to calculate the correct path
|
||||
// translate. (i.e. Center transform-origin on the path.)
|
||||
|
@ -409,6 +409,7 @@ cbindgen-types = [
|
||||
{ gecko = "StyleFontFaceSourceListComponent", servo = "font_face::FontFaceSourceListComponent" },
|
||||
{ gecko = "StyleFontLanguageOverride", servo = "values::computed::font::FontLanguageOverride" },
|
||||
{ gecko = "StyleOffsetPath", servo = "values::computed::motion::OffsetPath" },
|
||||
{ gecko = "StyleOffsetRotate", servo = "values::computed::motion::OffsetRotate" },
|
||||
{ gecko = "StylePathCommand", servo = "values::specified::svg_path::PathCommand" },
|
||||
{ gecko = "StyleUnicodeRange", servo = "cssparser::UnicodeRange" },
|
||||
{ gecko = "StyleOverflowWrap", servo = "values::computed::OverflowWrap" },
|
||||
|
@ -2956,6 +2956,7 @@ nsStyleDisplay::nsStyleDisplay(const Document& aDocument)
|
||||
mTransformBox(StyleGeometryBox::BorderBox),
|
||||
mOffsetPath(StyleOffsetPath::None()),
|
||||
mOffsetDistance(LengthPercentage::Zero()),
|
||||
mOffsetRotate{true, StyleAngle{0.0}},
|
||||
mTransformOrigin{LengthPercentage::FromPercentage(0.5),
|
||||
LengthPercentage::FromPercentage(0.5),
|
||||
{0.}},
|
||||
@ -3021,6 +3022,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
|
||||
mTransformBox(aSource.mTransformBox),
|
||||
mOffsetPath(aSource.mOffsetPath),
|
||||
mOffsetDistance(aSource.mOffsetDistance),
|
||||
mOffsetRotate(aSource.mOffsetRotate),
|
||||
mTransformOrigin(aSource.mTransformOrigin),
|
||||
mChildPerspective(aSource.mChildPerspective),
|
||||
mPerspectiveOrigin(aSource.mPerspectiveOrigin),
|
||||
@ -3061,15 +3063,14 @@ static inline nsChangeHint CompareTransformValues(
|
||||
}
|
||||
|
||||
static inline nsChangeHint CompareMotionValues(
|
||||
const StyleOffsetPath& aOffsetPath, const LengthPercentage& aOffsetDistance,
|
||||
const StyleOffsetPath& aNewOffsetPath,
|
||||
const LengthPercentage& aNewOffsetDistance) {
|
||||
if (aOffsetPath == aNewOffsetPath) {
|
||||
if (aOffsetDistance == aNewOffsetDistance) {
|
||||
const nsStyleDisplay& aDisplay, const nsStyleDisplay& aNewDisplay) {
|
||||
if (aDisplay.mOffsetPath == aNewDisplay.mOffsetPath) {
|
||||
if (aDisplay.mOffsetDistance == aNewDisplay.mOffsetDistance &&
|
||||
aDisplay.mOffsetRotate == aNewDisplay.mOffsetRotate) {
|
||||
return nsChangeHint(0);
|
||||
}
|
||||
|
||||
if (aOffsetPath.IsNone()) {
|
||||
if (aDisplay.mOffsetPath.IsNone()) {
|
||||
return nsChangeHint_NeutralChange;
|
||||
}
|
||||
}
|
||||
@ -3079,7 +3080,7 @@ static inline nsChangeHint CompareMotionValues(
|
||||
// Set the same hints as what we use for transform because motion path is
|
||||
// a kind of transform and will be combined with other transforms.
|
||||
nsChangeHint result = nsChangeHint_UpdateTransformLayer;
|
||||
if (!aOffsetPath.IsNone() && !aNewOffsetPath.IsNone()) {
|
||||
if (!aDisplay.mOffsetPath.IsNone() && !aNewDisplay.mOffsetPath.IsNone()) {
|
||||
result |= nsChangeHint_UpdatePostTransformOverflow;
|
||||
} else {
|
||||
result |= nsChangeHint_UpdateOverflow;
|
||||
@ -3208,9 +3209,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(
|
||||
transformHint |= CompareTransformValues(mRotate, aNewData.mRotate);
|
||||
transformHint |= CompareTransformValues(mTranslate, aNewData.mTranslate);
|
||||
transformHint |= CompareTransformValues(mScale, aNewData.mScale);
|
||||
transformHint |=
|
||||
CompareMotionValues(mOffsetPath, mOffsetDistance, aNewData.mOffsetPath,
|
||||
aNewData.mOffsetDistance);
|
||||
transformHint |= CompareMotionValues(*this, aNewData);
|
||||
|
||||
if (mTransformOrigin != aNewData.mTransformOrigin) {
|
||||
transformHint |= nsChangeHint_UpdateTransformLayer |
|
||||
|
@ -1737,6 +1737,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
|
||||
|
||||
mozilla::StyleOffsetPath mOffsetPath;
|
||||
mozilla::LengthPercentage mOffsetDistance;
|
||||
mozilla::StyleOffsetRotate mOffsetRotate;
|
||||
|
||||
mozilla::StyleTransformOrigin mTransformOrigin;
|
||||
mozilla::StylePerspective mChildPerspective;
|
||||
|
@ -8747,6 +8747,15 @@ if (IsCSSPropertyPrefEnabled("layout.css.motion-path.enabled")) {
|
||||
other_values: [ "10px", "10%", "190%", "-280%", "calc(30px + 40%)" ],
|
||||
invalid_values: [ "none", "45deg" ]
|
||||
};
|
||||
|
||||
gCSSProperties["offset-rotate"] = {
|
||||
domProp: "offsetRotate",
|
||||
inherited: false,
|
||||
type: CSS_TYPE_LONGHAND,
|
||||
initial_values: [ "auto" ],
|
||||
other_values: [ "reverse", "0deg", "0rad reverse", "-45deg", "5turn auto" ],
|
||||
invalid_values: [ "none", "10px", "reverse 0deg reverse", "reverse auto" ]
|
||||
};
|
||||
}
|
||||
|
||||
if (IsCSSPropertyPrefEnabled("layout.css.clip-path-path.enabled")) {
|
||||
|
@ -332,6 +332,7 @@ class Longhand(object):
|
||||
"MozScriptMinSize",
|
||||
"MozScriptSizeMultiplier",
|
||||
"NonNegativeNumber",
|
||||
"OffsetRotate",
|
||||
"Opacity",
|
||||
"OutlineStyle",
|
||||
"Overflow",
|
||||
|
@ -384,6 +384,18 @@ ${helpers.predefined_type(
|
||||
servo_restyle_damage="reflow_out_of_flow"
|
||||
)}
|
||||
|
||||
// Motion Path Module Level 1
|
||||
${helpers.predefined_type(
|
||||
"offset-rotate",
|
||||
"OffsetRotate",
|
||||
"computed::OffsetRotate::auto()",
|
||||
products="gecko",
|
||||
animation_value_type="none",
|
||||
gecko_pref="layout.css.motion-path.enabled",
|
||||
spec="https://drafts.fxtf.org/motion-1/#offset-rotate-property",
|
||||
servo_restyle_damage="reflow_out_of_flow"
|
||||
)}
|
||||
|
||||
// CSSOM View Module
|
||||
// https://www.w3.org/TR/cssom-view-1/
|
||||
${helpers.single_keyword(
|
||||
|
@ -65,7 +65,7 @@ pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageO
|
||||
pub use self::list::ListStyleType;
|
||||
pub use self::list::MozListReversed;
|
||||
pub use self::list::{QuotePair, Quotes};
|
||||
pub use self::motion::OffsetPath;
|
||||
pub use self::motion::{OffsetPath, OffsetRotate};
|
||||
pub use self::outline::OutlineStyle;
|
||||
pub use self::percentage::{NonNegativePercentage, Percentage};
|
||||
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position, ZIndex};
|
||||
|
@ -4,7 +4,41 @@
|
||||
|
||||
//! Computed types for CSS values that are related to motion path.
|
||||
|
||||
use crate::values::computed::Angle;
|
||||
use crate::Zero;
|
||||
|
||||
/// A computed offset-path. The computed value is as specified value.
|
||||
///
|
||||
/// https://drafts.fxtf.org/motion-1/#offset-path-property
|
||||
pub use crate::values::specified::motion::OffsetPath;
|
||||
|
||||
#[inline]
|
||||
fn is_auto_zero_angle(auto: &bool, angle: &Angle) -> bool {
|
||||
*auto && angle.is_zero()
|
||||
}
|
||||
|
||||
/// A computed offset-rotate.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToCss, ToResolvedValue)]
|
||||
#[repr(C)]
|
||||
pub struct OffsetRotate {
|
||||
/// If auto is false, this is a fixed angle which indicates a
|
||||
/// constant clockwise rotation transformation applied to it by this
|
||||
/// specified rotation angle. Otherwise, the angle will be added to
|
||||
/// the angle of the direction in layout.
|
||||
#[css(represents_keyword)]
|
||||
pub auto: bool,
|
||||
/// The angle value.
|
||||
#[css(contextual_skip_if = "is_auto_zero_angle")]
|
||||
pub angle: Angle,
|
||||
}
|
||||
|
||||
impl OffsetRotate {
|
||||
/// Returns "auto 0deg".
|
||||
#[inline]
|
||||
pub fn auto() -> Self {
|
||||
OffsetRotate {
|
||||
auto: true,
|
||||
angle: Zero::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ pub use self::length::{NonNegativeLengthPercentage, NonNegativeLengthPercentageO
|
||||
pub use self::list::ListStyleType;
|
||||
pub use self::list::MozListReversed;
|
||||
pub use self::list::{QuotePair, Quotes};
|
||||
pub use self::motion::OffsetPath;
|
||||
pub use self::motion::{OffsetPath, OffsetRotate};
|
||||
pub use self::outline::OutlineStyle;
|
||||
pub use self::percentage::Percentage;
|
||||
pub use self::position::{GridAutoFlow, GridTemplateAreas, Position};
|
||||
|
@ -5,7 +5,10 @@
|
||||
//! Specified types for CSS values that are related to motion path.
|
||||
|
||||
use crate::parser::{Parse, ParserContext};
|
||||
use crate::values::specified::SVGPathData;
|
||||
use crate::values::computed::motion::OffsetRotate as ComputedOffsetRotate;
|
||||
use crate::values::computed::{Context, ToComputedValue};
|
||||
use crate::values::specified::{Angle, SVGPathData};
|
||||
use crate::Zero;
|
||||
use cssparser::Parser;
|
||||
use style_traits::{ParseError, StyleParseErrorKind};
|
||||
|
||||
@ -75,3 +78,104 @@ impl Parse for OffsetPath {
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// The direction of offset-rotate.
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
#[repr(u8)]
|
||||
pub enum OffsetRotateDirection {
|
||||
/// Unspecified direction keyword.
|
||||
#[css(skip)]
|
||||
None,
|
||||
/// 0deg offset (face forward).
|
||||
Auto,
|
||||
/// 180deg offset (face backward).
|
||||
Reverse,
|
||||
}
|
||||
|
||||
impl OffsetRotateDirection {
|
||||
/// Returns true if it is none (i.e. the keyword is not specified).
|
||||
#[inline]
|
||||
fn is_none(&self) -> bool {
|
||||
*self == OffsetRotateDirection::None
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn direction_specified_and_angle_is_zero(direction: &OffsetRotateDirection, angle: &Angle) -> bool {
|
||||
!direction.is_none() && angle.is_zero()
|
||||
}
|
||||
|
||||
/// The specified offset-rotate.
|
||||
/// The syntax is: "[ auto | reverse ] || <angle>"
|
||||
///
|
||||
/// https://drafts.fxtf.org/motion-1/#offset-rotate-property
|
||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||
pub struct OffsetRotate {
|
||||
/// [auto | reverse].
|
||||
#[css(skip_if = "OffsetRotateDirection::is_none")]
|
||||
direction: OffsetRotateDirection,
|
||||
/// <angle>.
|
||||
/// If direction is None, this is a fixed angle which indicates a
|
||||
/// constant clockwise rotation transformation applied to it by this
|
||||
/// specified rotation angle. Otherwise, the angle will be added to
|
||||
/// the angle of the direction in layout.
|
||||
#[css(contextual_skip_if = "direction_specified_and_angle_is_zero")]
|
||||
angle: Angle,
|
||||
}
|
||||
|
||||
impl Parse for OffsetRotate {
|
||||
fn parse<'i, 't>(
|
||||
context: &ParserContext,
|
||||
input: &mut Parser<'i, 't>,
|
||||
) -> Result<Self, ParseError<'i>> {
|
||||
let location = input.current_source_location();
|
||||
let mut direction = input.try(OffsetRotateDirection::parse);
|
||||
let angle = input.try(|i| Angle::parse(context, i));
|
||||
if direction.is_err() {
|
||||
// The direction and angle could be any order, so give it a change to parse
|
||||
// direction again.
|
||||
direction = input.try(OffsetRotateDirection::parse);
|
||||
}
|
||||
|
||||
if direction.is_err() && angle.is_err() {
|
||||
return Err(location.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||
}
|
||||
|
||||
Ok(OffsetRotate {
|
||||
direction: direction.unwrap_or(OffsetRotateDirection::None),
|
||||
angle: angle.unwrap_or(Zero::zero()),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ToComputedValue for OffsetRotate {
|
||||
type ComputedValue = ComputedOffsetRotate;
|
||||
|
||||
#[inline]
|
||||
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||
use crate::values::computed::Angle as ComputedAngle;
|
||||
|
||||
ComputedOffsetRotate {
|
||||
auto: !self.direction.is_none(),
|
||||
angle: if self.direction == OffsetRotateDirection::Reverse {
|
||||
// The computed value should always convert "reverse" into "auto".
|
||||
// e.g. "reverse calc(20deg + 10deg)" => "auto 210deg"
|
||||
self.angle.to_computed_value(context) + ComputedAngle::from_degrees(180.0)
|
||||
} else {
|
||||
self.angle.to_computed_value(context)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||
OffsetRotate {
|
||||
direction: if computed.auto {
|
||||
OffsetRotateDirection::Auto
|
||||
} else {
|
||||
OffsetRotateDirection::None
|
||||
},
|
||||
angle: ToComputedValue::from_computed_value(&computed.angle),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,6 +70,7 @@ include = [
|
||||
"OverflowWrap",
|
||||
"TimingFunction",
|
||||
"OffsetPath",
|
||||
"OffsetRotate",
|
||||
"UnicodeRange",
|
||||
"UserSelect",
|
||||
"Float",
|
||||
|
@ -1,7 +1,4 @@
|
||||
[offset-rotate-interpolation.html]
|
||||
["100deg" and "180deg" are valid offset-rotate values]
|
||||
expected: FAIL
|
||||
|
||||
[Animation between "100deg" and "180deg" at progress -1]
|
||||
expected: FAIL
|
||||
|
||||
@ -20,9 +17,6 @@
|
||||
[Animation between "100deg" and "180deg" at progress 2]
|
||||
expected: FAIL
|
||||
|
||||
["auto 100deg" and "reverse" are valid offset-rotate values]
|
||||
expected: FAIL
|
||||
|
||||
[Animation between "auto 100deg" and "reverse" at progress -1]
|
||||
expected: FAIL
|
||||
|
||||
@ -41,9 +35,6 @@
|
||||
[Animation between "auto 100deg" and "reverse" at progress 2]
|
||||
expected: FAIL
|
||||
|
||||
["reverse 90deg" and "360deg" are valid offset-rotate values]
|
||||
expected: FAIL
|
||||
|
||||
[Animation between "reverse 90deg" and "360deg" at progress -1]
|
||||
expected: FAIL
|
||||
|
||||
@ -62,9 +53,6 @@
|
||||
[Animation between "reverse 90deg" and "360deg" at progress 2]
|
||||
expected: FAIL
|
||||
|
||||
["6rad" and "auto" are valid offset-rotate values]
|
||||
expected: FAIL
|
||||
|
||||
[Animation between "6rad" and "auto" at progress -1]
|
||||
expected: FAIL
|
||||
|
||||
@ -73,13 +61,3 @@
|
||||
|
||||
[Animation between "6rad" and "auto" at progress 0.125]
|
||||
expected: FAIL
|
||||
|
||||
[Animation between "6rad" and "auto" at progress 0.875]
|
||||
expected: FAIL
|
||||
|
||||
[Animation between "6rad" and "auto" at progress 1]
|
||||
expected: FAIL
|
||||
|
||||
[Animation between "6rad" and "auto" at progress 2]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -8,9 +8,6 @@
|
||||
[offset-distance supports calc]
|
||||
expected: FAIL
|
||||
|
||||
[offset-rotate supports calc]
|
||||
expected: FAIL
|
||||
|
||||
[offset-anchor supports calc]
|
||||
expected: FAIL
|
||||
|
||||
|
@ -1,4 +0,0 @@
|
||||
[offset-rotate-computed.html]
|
||||
[Motion Path Module Level 1: getComputedValue().offsetRotate]
|
||||
expected: FAIL
|
||||
|
@ -1,43 +0,0 @@
|
||||
[offset-rotate-parsing-valid.html]
|
||||
[Serialization should round-trip after setting e.style['offset-rotate'\] = "5turn auto"]
|
||||
expected: FAIL
|
||||
|
||||
[Serialization should round-trip after setting e.style['offset-rotate'\] = "0rad reverse"]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['offset-rotate'\] = "auto" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[Serialization should round-trip after setting e.style['offset-rotate'\] = "auto"]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['offset-rotate'\] = "reverse" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[Serialization should round-trip after setting e.style['offset-rotate'\] = "reverse"]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['offset-rotate'\] = "-400deg" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[Serialization should round-trip after setting e.style['offset-rotate'\] = "-400deg"]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['offset-rotate'\] = "auto 5turn" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[Serialization should round-trip after setting e.style['offset-rotate'\] = "auto 5turn"]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['offset-rotate'\] = "reverse 0rad" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[Serialization should round-trip after setting e.style['offset-rotate'\] = "reverse 0rad"]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['offset-rotate'\] = "5turn auto" should set the property value]
|
||||
expected: FAIL
|
||||
|
||||
[e.style['offset-rotate'\] = "0rad reverse" should set the property value]
|
||||
expected: FAIL
|
||||
|
@ -19,7 +19,8 @@ assert_not_inherited('offset-anchor', 'auto', '2px 3px');
|
||||
assert_not_inherited('offset-distance', '0px', '4px');
|
||||
assert_not_inherited('offset-path', 'none', 'path("M 5 6 H 7")');
|
||||
assert_not_inherited('offset-position', 'auto', '8px 9px');
|
||||
assert_not_inherited('offset-rotate', 'auto 0deg', '90deg');
|
||||
// https://github.com/w3c/fxtf-drafts/issues/340
|
||||
assert_not_inherited('offset-rotate', ['auto 0deg', 'auto'], '90deg');
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
25
testing/web-platform/tests/css/motion/offset-rotate-003.html
Normal file
25
testing/web-platform/tests/css/motion/offset-rotate-003.html
Normal file
@ -0,0 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>CSS Motion Path: offset-rotate</title>
|
||||
<link rel="help" href="https://drafts.fxtf.org/motion-1/#offset-rotate-property">
|
||||
<link rel="match" href="offset-rotate-ref.html">
|
||||
<meta name="assert" content="This tests offset-rotate <angle>">
|
||||
<style>
|
||||
#target {
|
||||
position: absolute;
|
||||
left: 300px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-color: lime;
|
||||
transform-origin: 0px 0px;
|
||||
offset-path: path('m 0 0 v -200 -200') ;
|
||||
offset-rotate: 30deg;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
37
testing/web-platform/tests/css/motion/offset-rotate-004.html
Normal file
37
testing/web-platform/tests/css/motion/offset-rotate-004.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<title>CSS Motion Path: offset-rotate</title>
|
||||
<link rel="help" href="https://drafts.fxtf.org/motion-1/#offset-rotate-property">
|
||||
<link rel="match" href="offset-rotate-ref.html">
|
||||
<meta name="assert" content="This tests offset-rotate auto with path()">
|
||||
<style>
|
||||
#target {
|
||||
position: absolute;
|
||||
left: 300px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-color: lime;
|
||||
transform-origin: 0px 0px;
|
||||
offset-rotate: auto;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function test() {
|
||||
let target = document.getElementById('target');
|
||||
// Get a path which has the same direction as "ray(120deg ...)"
|
||||
let verticalMove = 100 * Math.tan(30 * Math.PI / 180);
|
||||
target.style.offsetPath = `path("m 0 0 l 100 ${verticalMove}")`;
|
||||
window.getComputedStyle(target).offsetPath;
|
||||
|
||||
window.requestAnimationFrame(function() {
|
||||
document.documentElement.removeAttribute('class');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload='test()'>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
37
testing/web-platform/tests/css/motion/offset-rotate-005.html
Normal file
37
testing/web-platform/tests/css/motion/offset-rotate-005.html
Normal file
@ -0,0 +1,37 @@
|
||||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<title>CSS Motion Path: offset-rotate</title>
|
||||
<link rel="help" href="https://drafts.fxtf.org/motion-1/#offset-rotate-property">
|
||||
<link rel="match" href="offset-rotate-ref.html">
|
||||
<meta name="assert" content="This tests offset-rotate reverse <angle> with path()">
|
||||
<style>
|
||||
#target {
|
||||
position: absolute;
|
||||
left: 300px;
|
||||
top: 100px;
|
||||
width: 300px;
|
||||
height: 200px;
|
||||
background-color: lime;
|
||||
transform-origin: 0px 0px;
|
||||
offset-rotate: reverse 60deg;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
function test() {
|
||||
let target = document.getElementById('target');
|
||||
// Get a path which has the same direction as "ray(-120deg ...)"
|
||||
let verticalMove = 100 * Math.tan(30 * Math.PI / 180);
|
||||
target.style.offsetPath = `path("m 0 0 l -100 ${verticalMove}")`;
|
||||
window.getComputedStyle(target).offsetPath;
|
||||
|
||||
window.requestAnimationFrame(function() {
|
||||
document.documentElement.removeAttribute('class');
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body onload='test()'>
|
||||
<div id="target"></div>
|
||||
</body>
|
||||
</html>
|
@ -13,7 +13,8 @@
|
||||
<body>
|
||||
<div id="target"></div>
|
||||
<script>
|
||||
test_computed_value("offset-rotate", "auto", "auto 0deg");
|
||||
// https://github.com/w3c/fxtf-drafts/issues/340
|
||||
test_computed_value("offset-rotate", "auto", ["auto 0deg", "auto"]);
|
||||
test_computed_value("offset-rotate", "reverse", "auto 180deg");
|
||||
test_computed_value("offset-rotate", "calc(90deg - 0.5turn - 300grad + 0rad)", "-360deg");
|
||||
test_computed_value("offset-rotate", "auto 5turn", "auto 1800deg");
|
||||
|
@ -16,9 +16,11 @@ test_valid_value("offset-rotate", "auto");
|
||||
test_valid_value("offset-rotate", "reverse");
|
||||
test_valid_value("offset-rotate", "-400deg");
|
||||
test_valid_value("offset-rotate", "auto 5turn");
|
||||
test_valid_value("offset-rotate", "reverse 0rad");
|
||||
// https://github.com/w3c/fxtf-drafts/issues/340
|
||||
test_valid_value("offset-rotate", "reverse 0rad", ["reverse 0rad", "reverse"]);
|
||||
test_valid_value("offset-rotate", "5turn auto", "auto 5turn");
|
||||
test_valid_value("offset-rotate", "0rad reverse", "reverse 0rad");
|
||||
// https://github.com/w3c/fxtf-drafts/issues/340
|
||||
test_valid_value("offset-rotate", "0rad reverse", ["reverse 0rad", "reverse"]);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
@ -6,23 +6,37 @@
|
||||
*
|
||||
* @param {string} property The name of the CSS property being tested.
|
||||
* @param {string} specified A specified value for the property.
|
||||
* @param {string} computed The expected computed value. If omitted,
|
||||
defaults to specified.
|
||||
* @param {string|array} computed The expected computed value,
|
||||
* or an array of permitted computed value.
|
||||
* If omitted, defaults to specified.
|
||||
*/
|
||||
function test_computed_value(property, specified, computed) {
|
||||
if (!computed)
|
||||
computed = specified;
|
||||
|
||||
let computedDesc = "'" + computed + "'";
|
||||
if (Array.isArray(computed))
|
||||
computedDesc = '[' + computed.map(e => "'" + e + "'").join(' or ') + ']';
|
||||
|
||||
test(() => {
|
||||
const target = document.getElementById('target');
|
||||
if (!getComputedStyle(target)[property])
|
||||
return;
|
||||
target.style[property] = '';
|
||||
target.style[property] = specified;
|
||||
assert_equals(getComputedStyle(target)[property], computed);
|
||||
if (computed !== specified) {
|
||||
target.style[property] = '';
|
||||
target.style[property] = computed;
|
||||
assert_equals(getComputedStyle(target)[property], computed, 'computed value should round-trip');
|
||||
|
||||
let readValue = getComputedStyle(target)[property];
|
||||
if (Array.isArray(computed)) {
|
||||
assert_in_array(readValue, computed);
|
||||
} else {
|
||||
assert_equals(readValue, computed);
|
||||
}
|
||||
}, "Property " + property + " value '" + specified + "' computes to '" + computed + "'");
|
||||
if (readValue !== specified) {
|
||||
target.style[property] = '';
|
||||
target.style[property] = readValue;
|
||||
assert_equals(getComputedStyle(target)[property], readValue,
|
||||
'computed value should round-trip');
|
||||
}
|
||||
}, "Property " + property + " value '" + specified + "' computes to " +
|
||||
computedDesc);
|
||||
}
|
||||
|
@ -3,14 +3,22 @@
|
||||
(function() {
|
||||
|
||||
function assert_initial(property, initial) {
|
||||
let initialDesc = initial;
|
||||
if (Array.isArray(initial))
|
||||
initialDesc = '[' + initial.map(e => "'" + e + "'").join(' or ') + ']';
|
||||
|
||||
test(() => {
|
||||
const target = document.getElementById('target');
|
||||
if (!getComputedStyle(target)[property])
|
||||
return;
|
||||
target.style[property] = 'initial';
|
||||
assert_equals(getComputedStyle(target)[property], initial);
|
||||
if (Array.isArray(initial)) {
|
||||
assert_in_array(getComputedStyle(target)[property], initial);
|
||||
} else {
|
||||
assert_equals(getComputedStyle(target)[property], initial);
|
||||
}
|
||||
target.style[property] = '';
|
||||
}, 'Property ' + property + ' has initial value ' + initial);
|
||||
}, 'Property ' + property + ' has initial value ' + initialDesc);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -18,10 +26,12 @@ function assert_initial(property, initial) {
|
||||
*
|
||||
* The current document must have an element #target within element #container.
|
||||
*
|
||||
* @param {string} property The name of the CSS property being tested.
|
||||
* @param {string} initial The computed value for 'initial'.
|
||||
* @param {string} other An arbitrary value for the property that round
|
||||
* trips and is distinct from the initial value.
|
||||
* @param {string} property The name of the CSS property being tested.
|
||||
* @param {string|array} initial The computed value for 'initial' or a list
|
||||
* of acceptable computed value serializations.
|
||||
* @param {string} other An arbitrary value for the property that
|
||||
* round trips and is distinct from the initial
|
||||
* value.
|
||||
*/
|
||||
function assert_inherited(property, initial, other) {
|
||||
assert_initial(property, initial);
|
||||
@ -54,10 +64,12 @@ function assert_inherited(property, initial, other) {
|
||||
*
|
||||
* The current document must have an element #target within element #container.
|
||||
*
|
||||
* @param {string} property The name of the CSS property being tested.
|
||||
* @param {string} initial The computed value for 'initial'.
|
||||
* @param {string} other An arbitrary value for the property that round
|
||||
* trips and is distinct from the initial value.
|
||||
* @param {string} property The name of the CSS property being tested.
|
||||
* @param {string|array} initial The computed value for 'initial' or a list
|
||||
* of acceptable computed value serializations.
|
||||
* @param {string} other An arbitrary value for the property that
|
||||
* round trips and is distinct from the initial
|
||||
* value.
|
||||
*/
|
||||
function assert_not_inherited(property, initial, other) {
|
||||
assert_initial(property, initial);
|
||||
|
Loading…
Reference in New Issue
Block a user