diff --git a/components/style/values/specified/calc.rs b/components/style/values/specified/calc.rs index 9736491adce..f20230b2f76 100644 --- a/components/style/values/specified/calc.rs +++ b/components/style/values/specified/calc.rs @@ -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(&self, dest: &mut CssWriter, 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 { + /// + fn to_css(&self, dest: &mut CssWriter) -> fmt::Result + where + W: Write, + { + self.to_css_impl(dest, /* is_outermost = */ true) + } } diff --git a/components/style/values/specified/length.rs b/components/style/values/specified/length.rs index 16b9bf003e6..7bc6ed80587 100644 --- a/components/style/values/specified/length.rs +++ b/components/style/values/specified/length.rs @@ -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 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, diff --git a/components/style/values/specified/percentage.rs b/components/style/values/specified/percentage.rs index 75549dca3be..eac4d91cf8f 100644 --- a/components/style/values/specified/percentage.rs +++ b/components/style/values/specified/percentage.rs @@ -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),