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)
}
}

View file

@ -92,7 +92,16 @@ impl FontRelativeLength {
FontRelativeLength::Em(v) |
FontRelativeLength::Ex(v) |
FontRelativeLength::Ch(v) |
FontRelativeLength::Rem(v) => v == 0.0,
FontRelativeLength::Rem(v) => v == 0.,
}
}
fn is_negative(&self) -> bool {
match *self {
FontRelativeLength::Em(v) |
FontRelativeLength::Ex(v) |
FontRelativeLength::Ch(v) |
FontRelativeLength::Rem(v) => v < 0.,
}
}
@ -266,7 +275,16 @@ impl ViewportPercentageLength {
ViewportPercentageLength::Vw(v) |
ViewportPercentageLength::Vh(v) |
ViewportPercentageLength::Vmin(v) |
ViewportPercentageLength::Vmax(v) => v == 0.0,
ViewportPercentageLength::Vmax(v) => v == 0.,
}
}
fn is_negative(&self) -> bool {
match *self {
ViewportPercentageLength::Vw(v) |
ViewportPercentageLength::Vh(v) |
ViewportPercentageLength::Vmin(v) |
ViewportPercentageLength::Vmax(v) => v < 0.,
}
}
@ -370,6 +388,18 @@ impl AbsoluteLength {
}
}
fn is_negative(&self) -> bool {
match *self {
AbsoluteLength::Px(v) |
AbsoluteLength::In(v) |
AbsoluteLength::Cm(v) |
AbsoluteLength::Mm(v) |
AbsoluteLength::Q(v) |
AbsoluteLength::Pt(v) |
AbsoluteLength::Pc(v) => v < 0.,
}
}
/// Convert this into a pixel value.
#[inline]
pub fn to_px(&self) -> CSSFloat {
@ -484,6 +514,16 @@ impl Mul<CSSFloat> for NoCalcLength {
}
impl NoCalcLength {
/// Returns whether the value of this length without unit is less than zero.
pub fn is_negative(&self) -> bool {
match *self {
NoCalcLength::Absolute(v) => v.is_negative(),
NoCalcLength::FontRelative(v) => v.is_negative(),
NoCalcLength::ViewportPercentage(v) => v.is_negative(),
NoCalcLength::ServoCharacterWidth(c) => c.0 < 0,
}
}
/// Parse a given absolute or relative dimension.
pub fn parse_dimension(
context: &ParserContext,

View file

@ -120,9 +120,6 @@ impl Percentage {
Token::Function(ref name) => {
let function = CalcNode::math_function(name, location)?;
let value = CalcNode::parse_percentage(context, input, function)?;
// TODO(emilio): -moz-image-rect is the only thing that uses
// the clamping mode... I guess we could disallow it...
Ok(Percentage {
value,
calc_clamping_mode: Some(num_context),