style: Support offset-position in the style system

Also, we make it animatable but don't apply it to the motion transform and
don't run it on the compositor for now (so it works for getComputedStyle but
doesn't have rendering result).

Per spec: https://w3c.github.io/csswg-drafts/css-values/#calc-serialize,
we tweak the WPT to let calc() serialize the percentage first, and maintain
zero-valued terms, i.e. 0%. (We are doing the same thing as
offset-anchor, so it should be fine with other browsers.)

Besides, I tweak the serialization of shorthand a little bit so we match
the implementation of WebKit.

Differential Revision: https://phabricator.services.mozilla.com/D170972
This commit is contained in:
Boris Chiou 2023-03-03 23:10:34 +00:00 committed by Martin Robinson
parent 1b40d30f88
commit 0b20b343e6
2 changed files with 63 additions and 19 deletions

View file

@ -255,6 +255,19 @@ ${helpers.predefined_type(
boxed=True boxed=True
)} )}
// Motion Path Module Level 1
${helpers.predefined_type(
"offset-position",
"PositionOrAuto",
"computed::PositionOrAuto::auto()",
engines="gecko",
animation_value_type="ComputedValue",
gecko_pref="layout.css.motion-path-offset-position.enabled",
spec="https://drafts.fxtf.org/motion-1/#offset-position-property",
servo_restyle_damage="reflow_out_of_flow",
boxed=True
)}
// CSSOM View Module // CSSOM View Module
// https://www.w3.org/TR/cssom-view-1/ // https://www.w3.org/TR/cssom-view-1/
${helpers.single_keyword( ${helpers.single_keyword(

View file

@ -147,7 +147,8 @@ ${helpers.two_properties_shorthand(
<%helpers:shorthand name="offset" <%helpers:shorthand name="offset"
engines="gecko" engines="gecko"
sub_properties="offset-path offset-distance offset-rotate offset-anchor" sub_properties="offset-path offset-distance offset-rotate offset-anchor
offset-position"
gecko_pref="layout.css.motion-path.enabled", gecko_pref="layout.css.motion-path.enabled",
spec="https://drafts.fxtf.org/motion-1/#offset-shorthand"> spec="https://drafts.fxtf.org/motion-1/#offset-shorthand">
use crate::parser::Parse; use crate::parser::Parse;
@ -160,27 +161,39 @@ ${helpers.two_properties_shorthand(
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Longhands, ParseError<'i>> { ) -> Result<Longhands, ParseError<'i>> {
// FIXME: Bug 1559232: Support offset-position. let offset_position =
// Per the spec, this must have offet-position and/or offset-path. However, we don't if static_prefs::pref!("layout.css.motion-path-offset-position.enabled") {
// support offset-position, so offset-path is necessary now. input.try_parse(|i| PositionOrAuto::parse(context, i)).ok()
let offset_path = OffsetPath::parse(context, input)?; } else {
None
};
let offset_path = input.try_parse(|i| OffsetPath::parse(context, i)).ok();
// Must have one of [offset-position, offset-path].
if offset_position.is_none() && offset_path.is_none() {
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
}
let mut offset_distance = None; let mut offset_distance = None;
let mut offset_rotate = None; let mut offset_rotate = None;
loop { // offset-distance and offset-rotate are grouped with offset-path.
if offset_distance.is_none() { if offset_path.is_some() {
if let Ok(value) = input.try_parse(|i| LengthPercentage::parse(context, i)) { loop {
offset_distance = Some(value); if offset_distance.is_none() {
if let Ok(value) = input.try_parse(|i| LengthPercentage::parse(context, i)) {
offset_distance = Some(value);
}
} }
}
if offset_rotate.is_none() { if offset_rotate.is_none() {
if let Ok(value) = input.try_parse(|i| OffsetRotate::parse(context, i)) { if let Ok(value) = input.try_parse(|i| OffsetRotate::parse(context, i)) {
offset_rotate = Some(value); offset_rotate = Some(value);
continue; continue;
}
} }
break;
} }
break;
} }
let offset_anchor = input.try_parse(|i| { let offset_anchor = input.try_parse(|i| {
@ -189,7 +202,8 @@ ${helpers.two_properties_shorthand(
}).ok(); }).ok();
Ok(expanded! { Ok(expanded! {
offset_path: offset_path, offset_position: offset_position.unwrap_or(PositionOrAuto::auto()),
offset_path: offset_path.unwrap_or(OffsetPath::none()),
offset_distance: offset_distance.unwrap_or(LengthPercentage::zero()), offset_distance: offset_distance.unwrap_or(LengthPercentage::zero()),
offset_rotate: offset_rotate.unwrap_or(OffsetRotate::auto()), offset_rotate: offset_rotate.unwrap_or(OffsetRotate::auto()),
offset_anchor: offset_anchor.unwrap_or(PositionOrAuto::auto()), offset_anchor: offset_anchor.unwrap_or(PositionOrAuto::auto()),
@ -198,9 +212,26 @@ ${helpers.two_properties_shorthand(
impl<'a> ToCss for LonghandsToSerialize<'a> { impl<'a> ToCss for LonghandsToSerialize<'a> {
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write { fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result where W: fmt::Write {
// FIXME: Bug 1559232: Support offset-position. We don't support offset-position, if let Some(offset_position) = self.offset_position {
// so always serialize offset-path now. // The basic concept is: we must serialize offset-position or offset-path group.
self.offset_path.to_css(dest)?; // offset-path group means "offset-path offset-distance offset-rotate".
let must_serialize_path = *self.offset_path != OffsetPath::None
|| (!self.offset_distance.is_zero() || !self.offset_rotate.is_auto());
let position_is_default = *offset_position == PositionOrAuto::auto();
if !position_is_default || !must_serialize_path {
offset_position.to_css(dest)?;
}
if must_serialize_path {
if !position_is_default {
dest.write_char(' ')?;
}
self.offset_path.to_css(dest)?;
}
} else {
// If the pref is off, we always show offset-path.
self.offset_path.to_css(dest)?;
}
if !self.offset_distance.is_zero() { if !self.offset_distance.is_zero() {
dest.write_char(' ')?; dest.write_char(' ')?;