Auto merge of #14740 - glasserc:extremum-length, r=Manishearth

Add support for keyword values for min-width and max-width

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.

<!-- Please describe your changes on the following line: -->

---
<!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: -->
- [ ] `./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).

<!-- Either: -->
- [ ] There are tests for these changes OR
- [ ] These changes do not require tests because _____

<!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. -->

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/14740)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-02-24 14:08:58 -08:00 committed by GitHub
commit 26de7c6bc4
9 changed files with 349 additions and 17 deletions

View file

@ -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<Length, Number>;
/// Either a computed `<length>` or the `normal` keyword.
pub type LengthOrNormal = Either<Length, Normal>;
/// 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<W>(&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<W>(&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),
}
}
}

View file

@ -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;

View file

@ -185,3 +185,11 @@ impl<A: ToComputedValue, B: ToComputedValue> ToComputedValue for Either<A, B> {
}
}
}
// 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);

View file

@ -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<W>(&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<Self, ()> {
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<W>(&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<Self, ()> {
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(())
}
})
}
}

View file

@ -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")]