From 633be3efd1229b2489419580b203d6f0ed83c932 Mon Sep 17 00:00:00 2001 From: Ethan Glasser-Camp Date: Fri, 24 Feb 2017 14:08:58 -0800 Subject: [PATCH] servo: Merge #14740 - Add support for keyword values for min-width and max-width (from glasserc:extremum-length); r=Manishearth This is a follow-up to #14432 which got closed and can no longer be re-opened. This PR aims to add support for keyword-values max-content, min-content, fit-content, and fill-available to the properties that use them, namely min-width, min-height, max-width, and max-height. It's still untested because I still haven't figured out how to do that. I guess I should write or find some web page that uses these properties. Refs #13821. --- - [ ] `./mach build -d` does not report any errors - [ ] `./mach test-tidy` does not report any errors - [ ] These changes fix #13821 (github issue number if applicable). - [ ] There are tests for these changes OR - [ ] These changes do not require tests because _____ Source-Repo: https://github.com/servo/servo Source-Revision: 26de7c6bc48affbc2087b32649850f0733e567f0 --HG-- extra : subtree_source : https%3A//hg.mozilla.org/projects/converted-servo-linear extra : subtree_revision : 5ad2826be45174e7a1ceaa739d0fc5ce1e3975be --- servo/components/style/gecko/values.rs | 71 ++++++++++- .../components/style/properties/gecko.mako.rs | 2 + .../helpers/animated_properties.mako.rs | 29 +++++ .../properties/longhand/position.mako.rs | 47 +++++--- .../style/values/computed/length.rs | 112 +++++++++++++++++- servo/components/style/values/computed/mod.rs | 1 + servo/components/style/values/mod.rs | 8 ++ .../style/values/specified/length.rs | 95 +++++++++++++++ .../components/style/values/specified/mod.rs | 1 + 9 files changed, 349 insertions(+), 17 deletions(-) diff --git a/servo/components/style/gecko/values.rs b/servo/components/style/gecko/values.rs index 6d3f374c4306..cccb5ca697f3 100644 --- a/servo/components/style/gecko/values.rs +++ b/servo/components/style/gecko/values.rs @@ -11,9 +11,10 @@ use cssparser::RGBA; use gecko_bindings::structs::{nsStyleCoord, StyleGridTrackBreadth, StyleShapeRadius}; use gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue}; use std::cmp::max; -use values::{Auto, Either, None_, Normal}; +use values::{Auto, Either, ExtremumLength, None_, Normal}; use values::computed::{Angle, LengthOrPercentageOrNone, Number}; use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto}; +use values::computed::{MaxLength, MinLength}; use values::computed::basic_shape::ShapeRadius; use values::specified::grid::{TrackBreadth, TrackKeyword}; @@ -271,6 +272,74 @@ impl GeckoStyleCoordConvertible for Normal { } } +impl GeckoStyleCoordConvertible for ExtremumLength { + fn to_gecko_style_coord(&self, coord: &mut T) { + use gecko_bindings::structs::{NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT}; + use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT}; + coord.set_value(CoordDataValue::Enumerated( + match *self { + ExtremumLength::MaxContent => NS_STYLE_WIDTH_MAX_CONTENT, + ExtremumLength::MinContent => NS_STYLE_WIDTH_MIN_CONTENT, + ExtremumLength::FitContent => NS_STYLE_WIDTH_FIT_CONTENT, + ExtremumLength::FillAvailable => NS_STYLE_WIDTH_AVAILABLE, + } + )) + } + + fn from_gecko_style_coord(coord: &T) -> Option { + use gecko_bindings::structs::{NS_STYLE_WIDTH_AVAILABLE, NS_STYLE_WIDTH_FIT_CONTENT}; + use gecko_bindings::structs::{NS_STYLE_WIDTH_MAX_CONTENT, NS_STYLE_WIDTH_MIN_CONTENT}; + match coord.as_value() { + CoordDataValue::Enumerated(NS_STYLE_WIDTH_MAX_CONTENT) => + Some(ExtremumLength::MaxContent), + CoordDataValue::Enumerated(NS_STYLE_WIDTH_MIN_CONTENT) => + Some(ExtremumLength::MinContent), + CoordDataValue::Enumerated(NS_STYLE_WIDTH_FIT_CONTENT) => + Some(ExtremumLength::FitContent), + CoordDataValue::Enumerated(NS_STYLE_WIDTH_AVAILABLE) => Some(ExtremumLength::FillAvailable), + _ => None, + } + } +} + +impl GeckoStyleCoordConvertible for MinLength { + fn to_gecko_style_coord(&self, coord: &mut T) { + match *self { + MinLength::LengthOrPercentage(ref lop) => lop.to_gecko_style_coord(coord), + MinLength::Auto => coord.set_value(CoordDataValue::Auto), + MinLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord), + } + } + + fn from_gecko_style_coord(coord: &T) -> Option { + LengthOrPercentage::from_gecko_style_coord(coord).map(MinLength::LengthOrPercentage) + .or_else(|| ExtremumLength::from_gecko_style_coord(coord).map(MinLength::ExtremumLength)) + .or_else(|| match coord.as_value() { + CoordDataValue::Auto => Some(MinLength::Auto), + _ => None, + }) + } +} + +impl GeckoStyleCoordConvertible for MaxLength { + fn to_gecko_style_coord(&self, coord: &mut T) { + match *self { + MaxLength::LengthOrPercentage(ref lop) => lop.to_gecko_style_coord(coord), + MaxLength::None => coord.set_value(CoordDataValue::None), + MaxLength::ExtremumLength(ref e) => e.to_gecko_style_coord(coord), + } + } + + fn from_gecko_style_coord(coord: &T) -> Option { + LengthOrPercentage::from_gecko_style_coord(coord).map(MaxLength::LengthOrPercentage) + .or_else(|| ExtremumLength::from_gecko_style_coord(coord).map(MaxLength::ExtremumLength)) + .or_else(|| match coord.as_value() { + CoordDataValue::None => Some(MaxLength::None), + _ => None, + }) + } +} + /// Convert a given RGBA value to `nscolor`. pub fn convert_rgba_to_nscolor(rgba: &RGBA) -> u32 { ((rgba.alpha as u32) << 24) | diff --git a/servo/components/style/properties/gecko.mako.rs b/servo/components/style/properties/gecko.mako.rs index c50c51e75b99..ba834f0141ad 100644 --- a/servo/components/style/properties/gecko.mako.rs +++ b/servo/components/style/properties/gecko.mako.rs @@ -635,6 +635,8 @@ impl Debug for ${style_struct.gecko_struct_name} { "LengthOrPercentageOrAuto": impl_style_coord, "LengthOrPercentageOrNone": impl_style_coord, "LengthOrNone": impl_style_coord, + "MaxLength": impl_style_coord, + "MinLength": impl_style_coord, "Number": impl_simple, "Opacity": impl_simple, "CSSColor": impl_color, diff --git a/servo/components/style/properties/helpers/animated_properties.mako.rs b/servo/components/style/properties/helpers/animated_properties.mako.rs index 0c2b59eb2dab..e145420befdb 100644 --- a/servo/components/style/properties/helpers/animated_properties.mako.rs +++ b/servo/components/style/properties/helpers/animated_properties.mako.rs @@ -33,6 +33,7 @@ use values::Either; use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone}; use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone}; use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage}; +use values::computed::{MaxLength, MinLength}; use values::computed::position::{HorizontalPosition, Position, VerticalPosition}; use values::computed::ToComputedValue; use values::specified::Angle as SpecifiedAngle; @@ -630,6 +631,34 @@ impl Interpolate for LengthOrPercentageOrNone { } } +/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc +impl Interpolate for MinLength { + #[inline] + fn interpolate(&self, other: &Self, progress: f64) -> Result { + match (*self, *other) { + (MinLength::LengthOrPercentage(ref this), + MinLength::LengthOrPercentage(ref other)) => { + this.interpolate(other, progress).map(MinLength::LengthOrPercentage) + } + _ => Err(()), + } + } +} + +/// https://drafts.csswg.org/css-transitions/#animtype-lpcalc +impl Interpolate for MaxLength { + #[inline] + fn interpolate(&self, other: &Self, progress: f64) -> Result { + match (*self, *other) { + (MaxLength::LengthOrPercentage(ref this), + MaxLength::LengthOrPercentage(ref other)) => { + this.interpolate(other, progress).map(MaxLength::LengthOrPercentage) + } + _ => Err(()), + } + } +} + /// https://drafts.csswg.org/css-transitions/#animtype-number /// https://drafts.csswg.org/css-transitions/#animtype-length impl Interpolate for LineHeight { diff --git a/servo/components/style/properties/longhand/position.mako.rs b/servo/components/style/properties/longhand/position.mako.rs index 97b8d150365a..c9431031b3f0 100644 --- a/servo/components/style/properties/longhand/position.mako.rs +++ b/servo/components/style/properties/longhand/position.mako.rs @@ -218,23 +218,40 @@ ${helpers.predefined_type("flex-basis", spec=spec % size, animatable=True, logical = logical)} - // min-width, min-height, min-block-size, min-inline-size - ${helpers.predefined_type("min-%s" % size, - "LengthOrPercentage", - "computed::LengthOrPercentage::Length(Au(0))", - "parse_non_negative", - needs_context=False, - spec=spec % ("min-%s" % size), - animatable=True, logical = logical)} + % if product == "gecko": + // min-width, min-height, min-block-size, min-inline-size + ${helpers.predefined_type("min-%s" % size, + "MinLength", + "computed::MinLength::LengthOrPercentage(" + + "computed::LengthOrPercentage::Length(Au(0)))", + spec=spec % ("min-%s" % size), + animatable=True, logical = logical)} + % else: + ${helpers.predefined_type("min-%s" % size, + "LengthOrPercentage", + "computed::LengthOrPercentage::Length(Au(0))", + "parse_non_negative", + needs_context=False, + spec=spec % ("min-%s" % size), + animatable=True, logical = logical)} + % endif // max-width, max-height, max-block-size, max-inline-size - ${helpers.predefined_type("max-%s" % size, - "LengthOrPercentageOrNone", - "computed::LengthOrPercentageOrNone::None", - "parse_non_negative", - needs_context=False, - spec=spec % ("max-%s" % size), - animatable=True, logical = logical)} + % if product == "gecko": + ${helpers.predefined_type("max-%s" % size, + "MaxLength", + "computed::MaxLength::None", + spec=spec % ("max-%s" % size), + animatable=True, logical = logical)} + % else: + ${helpers.predefined_type("max-%s" % size, + "LengthOrPercentageOrNone", + "computed::LengthOrPercentageOrNone::None", + "parse_non_negative", + needs_context=False, + spec=spec % ("max-%s" % size), + animatable=True, logical = logical)} + % endif % endfor ${helpers.single_keyword("box-sizing", diff --git a/servo/components/style/values/computed/length.rs b/servo/components/style/values/computed/length.rs index 492bbfb4bc0b..e512a6234924 100644 --- a/servo/components/style/values/computed/length.rs +++ b/servo/components/style/values/computed/length.rs @@ -9,7 +9,7 @@ use ordered_float::NotNaN; use std::fmt; use style_traits::ToCss; use super::{Number, ToComputedValue, Context}; -use values::{Auto, CSSFloat, Either, None_, Normal, specified}; +use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified}; use values::specified::length::{FontRelativeLength, ViewportPercentageLength}; pub use cssparser::Color as CSSColor; @@ -546,3 +546,113 @@ pub type LengthOrNumber = Either; /// Either a computed `` or the `normal` keyword. pub type LengthOrNormal = Either; + +/// A value suitable for a `min-width` or `min-height` property. +/// See specified/values/length.rs for more details. +#[derive(Debug, Copy, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +pub enum MinLength { + LengthOrPercentage(LengthOrPercentage), + Auto, + ExtremumLength(ExtremumLength), +} + +impl ToComputedValue for specified::MinLength { + type ComputedValue = MinLength; + + #[inline] + fn to_computed_value(&self, context: &Context) -> MinLength { + match *self { + specified::MinLength::LengthOrPercentage(ref lop) => { + MinLength::LengthOrPercentage(lop.to_computed_value(context)) + } + specified::MinLength::Auto => { + MinLength::Auto + } + specified::MinLength::ExtremumLength(ref ext) => { + MinLength::ExtremumLength(ext.clone()) + } + } + } + + #[inline] + fn from_computed_value(computed: &MinLength) -> Self { + match *computed { + MinLength::Auto => + specified::MinLength::Auto, + MinLength::LengthOrPercentage(ref lop) => + specified::MinLength::LengthOrPercentage(specified::LengthOrPercentage::from_computed_value(&lop)), + MinLength::ExtremumLength(ref ext) => + specified::MinLength::ExtremumLength(ext.clone()), + } + } +} + +impl ToCss for MinLength { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + MinLength::LengthOrPercentage(lop) => + lop.to_css(dest), + MinLength::Auto => + dest.write_str("auto"), + MinLength::ExtremumLength(ext) => + ext.to_css(dest), + } + } +} + +/// A value suitable for a `max-width` or `max-height` property. +/// See specified/values/length.rs for more details. +#[derive(Debug, Copy, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +pub enum MaxLength { + LengthOrPercentage(LengthOrPercentage), + None, + ExtremumLength(ExtremumLength), +} + +impl ToComputedValue for specified::MaxLength { + type ComputedValue = MaxLength; + + #[inline] + fn to_computed_value(&self, context: &Context) -> MaxLength { + match *self { + specified::MaxLength::LengthOrPercentage(ref lop) => { + MaxLength::LengthOrPercentage(lop.to_computed_value(context)) + } + specified::MaxLength::None => { + MaxLength::None + } + specified::MaxLength::ExtremumLength(ref ext) => { + MaxLength::ExtremumLength(ext.clone()) + } + } + } + + #[inline] + fn from_computed_value(computed: &MaxLength) -> Self { + match *computed { + MaxLength::None => + specified::MaxLength::None, + MaxLength::LengthOrPercentage(ref lop) => + specified::MaxLength::LengthOrPercentage(specified::LengthOrPercentage::from_computed_value(&lop)), + MaxLength::ExtremumLength(ref ext) => + specified::MaxLength::ExtremumLength(ext.clone()), + } + } +} + +impl ToCss for MaxLength { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + MaxLength::LengthOrPercentage(lop) => + lop.to_css(dest), + MaxLength::None => + dest.write_str("none"), + MaxLength::ExtremumLength(ext) => + ext.to_css(dest), + } + } +} diff --git a/servo/components/style/values/computed/mod.rs b/servo/components/style/values/computed/mod.rs index dbc537c621a3..7a52ebd1d7fb 100644 --- a/servo/components/style/values/computed/mod.rs +++ b/servo/components/style/values/computed/mod.rs @@ -23,6 +23,7 @@ pub use super::specified::{Angle, BorderStyle, GridLine, Time, UrlOrNone}; pub use super::specified::url::{SpecifiedUrl, UrlExtraData}; pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone}; +pub use self::length::{MaxLength, MinLength}; pub use self::position::Position; pub mod basic_shape; diff --git a/servo/components/style/values/mod.rs b/servo/components/style/values/mod.rs index 88867af58f95..f30c3e2f44b7 100644 --- a/servo/components/style/values/mod.rs +++ b/servo/components/style/values/mod.rs @@ -185,3 +185,11 @@ impl ToComputedValue for Either { } } } + +// A type for possible values for min- and max- flavors of width, +// height, block-size, and inline-size. +define_css_keyword_enum!(ExtremumLength: + "max-content" => MaxContent, + "min-content" => MinContent, + "fit-content" => FitContent, + "fill-available" => FillAvailable); diff --git a/servo/components/style/values/specified/length.rs b/servo/components/style/values/specified/length.rs index 0744aa9aafba..ba344eff300d 100644 --- a/servo/components/style/values/specified/length.rs +++ b/servo/components/style/values/specified/length.rs @@ -18,6 +18,7 @@ use style_traits::ToCss; use style_traits::values::specified::AllowedNumericType; use super::{Angle, Number, SimplifiedValueNode, SimplifiedSumNode, Time}; use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal}; +use values::ExtremumLength; use values::computed::Context; pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient}; @@ -1304,3 +1305,97 @@ impl LengthOrNumber { } } } + +/// A value suitable for a `min-width` or `min-height` property. +/// Unlike `max-width` or `max-height` properties, a MinLength can be +/// `auto`, and cannot be `none`. +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +pub enum MinLength { + LengthOrPercentage(LengthOrPercentage), + Auto, + ExtremumLength(ExtremumLength), +} + +impl HasViewportPercentage for MinLength { + fn has_viewport_percentage(&self) -> bool { + match *self { + MinLength::LengthOrPercentage(ref lop) => lop.has_viewport_percentage(), + _ => false + } + } +} + +impl ToCss for MinLength { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + MinLength::LengthOrPercentage(ref lop) => + lop.to_css(dest), + MinLength::Auto => + dest.write_str("auto"), + MinLength::ExtremumLength(ref ext) => + ext.to_css(dest), + } + } +} + +impl Parse for MinLength { + fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + input.try(ExtremumLength::parse).map(MinLength::ExtremumLength) + .or_else(|()| input.try(LengthOrPercentage::parse_non_negative).map(MinLength::LengthOrPercentage)) + .or_else(|()| { + match_ignore_ascii_case! { try!(input.expect_ident()), + "auto" => + Ok(MinLength::Auto), + _ => Err(()) + } + }) + } +} + +/// A value suitable for a `max-width` or `max-height` property. +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[allow(missing_docs)] +pub enum MaxLength { + LengthOrPercentage(LengthOrPercentage), + None, + ExtremumLength(ExtremumLength), +} + +impl HasViewportPercentage for MaxLength { + fn has_viewport_percentage(&self) -> bool { + match *self { + MaxLength::LengthOrPercentage(ref lop) => lop.has_viewport_percentage(), + _ => false + } + } +} + +impl ToCss for MaxLength { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + MaxLength::LengthOrPercentage(ref lop) => + lop.to_css(dest), + MaxLength::None => + dest.write_str("none"), + MaxLength::ExtremumLength(ref ext) => + ext.to_css(dest), + } + } +} + +impl Parse for MaxLength { + fn parse(_context: &ParserContext, input: &mut Parser) -> Result { + input.try(ExtremumLength::parse).map(MaxLength::ExtremumLength) + .or_else(|()| input.try(LengthOrPercentage::parse_non_negative).map(MaxLength::LengthOrPercentage)) + .or_else(|()| { + match_ignore_ascii_case! { try!(input.expect_ident()), + "none" => + Ok(MaxLength::None), + _ => Err(()) + } + }) + } +} diff --git a/servo/components/style/values/specified/mod.rs b/servo/components/style/values/specified/mod.rs index d440636138c4..81c3f5e7a792 100644 --- a/servo/components/style/values/specified/mod.rs +++ b/servo/components/style/values/specified/mod.rs @@ -30,6 +30,7 @@ pub use self::image::{SizeKeyword, VerticalDirection}; pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage}; pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit}; +pub use self::length::{MaxLength, MinLength}; pub use self::position::{HorizontalPosition, Position, VerticalPosition}; #[cfg(feature = "gecko")]