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.

<!-- 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. -->

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
This commit is contained in:
Ethan Glasser-Camp 2017-02-24 14:08:58 -08:00
Родитель 428143ec78
Коммит 633be3efd1
9 изменённых файлов: 349 добавлений и 17 удалений

Просмотреть файл

@ -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<T: CoordDataMut>(&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<T: CoordData>(coord: &T) -> Option<Self> {
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<T: CoordDataMut>(&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<T: CoordData>(coord: &T) -> Option<Self> {
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<T: CoordDataMut>(&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<T: CoordData>(coord: &T) -> Option<Self> {
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) |

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

@ -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",

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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

Просмотреть файл

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