style: Implement ToCss for CalcNode.

We'll use `CalcNode` as the specified value representation for <length> and
<length-percentage> values, so they'll have to implement ToCss.

There's one minor issue (two calls to to_css() instead of to_css_impl() which
are addressed later in the series).

Differential Revision: https://phabricator.services.mozilla.com/D63395
This commit is contained in:
Emilio Cobos Álvarez 2020-02-21 00:46:26 +00:00
parent c52bae1923
commit 869553357d
3 changed files with 144 additions and 5 deletions

View file

@ -287,6 +287,19 @@ impl PartialOrd for CalcNode {
}
impl CalcNode {
fn is_simple_negative(&self) -> bool {
match *self {
Self::Length(ref l) => l.is_negative(),
Self::Percentage(n) |
Self::Number(n) => n < 0.,
Self::Angle(ref a) => a.degrees() < 0.,
Self::Time(ref t) => t.seconds() < 0.,
Self::MinMax(..) |
Self::Sum(..) |
Self::Clamp { .. } => false,
}
}
fn negate(&mut self) {
self.mul_by(-1.);
}
@ -1022,4 +1035,93 @@ impl CalcNode {
Err(()) => Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError)),
}
}
fn to_css_impl<W>(&self, dest: &mut CssWriter<W>, is_outermost: bool) -> fmt::Result
where
W: Write,
{
let write_closing_paren = match *self {
Self::MinMax(_, op) => {
dest.write_str(match op {
MinMaxOp::Max => "max(",
MinMaxOp::Min => "min(",
})?;
true
},
Self::Clamp { .. } => {
dest.write_str("clamp(")?;
true
},
_ => {
if is_outermost {
dest.write_str("calc(")?;
}
is_outermost
},
};
match *self {
Self::MinMax(ref children, _) => {
let mut first = true;
for child in &**children {
if !first {
dest.write_str(", ")?;
}
first = false;
child.to_css_impl(dest, false)?;
}
},
Self::Sum(ref children) => {
let mut first = true;
for child in &**children {
if !first {
if child.is_simple_negative() {
dest.write_str(" - ")?;
let mut c = child.clone();
c.negate();
c.to_css(dest)?;
} else {
dest.write_str(" + ")?;
child.to_css(dest)?;
}
} else {
first = false;
child.to_css_impl(dest, false)?;
}
}
},
Self::Clamp {
ref min,
ref center,
ref max,
} => {
min.to_css_impl(dest, false)?;
dest.write_str(", ")?;
center.to_css_impl(dest, false)?;
dest.write_str(", ")?;
max.to_css_impl(dest, false)?;
},
Self::Length(ref l) => l.to_css(dest)?,
Self::Number(ref n) => n.to_css(dest)?,
Self::Percentage(p) => crate::values::serialize_percentage(p, dest)?,
Self::Angle(ref a) => a.to_css(dest)?,
Self::Time(ref t) => t.to_css(dest)?,
}
if write_closing_paren {
dest.write_str(")")?;
}
Ok(())
}
}
impl ToCss for CalcNode {
/// <https://drafts.csswg.org/css-values/#calc-serialize>
fn to_css<W>(&self, dest: &mut CssWriter<W>) -> fmt::Result
where
W: Write,
{
self.to_css_impl(dest, /* is_outermost = */ true)
}
}