style: Merge ImageLayer and Image.

ImageLayer is almost the only usage of Image, so keeping them in the same enum
makes the resulting C++ struct smaller, and makes it map more cleanly to
nsStyleImage.

Differential Revision: https://phabricator.services.mozilla.com/D62161
This commit is contained in:
Emilio Cobos Álvarez 2020-02-10 20:02:31 +00:00
parent c0d67f796c
commit 149cb5f5f1
12 changed files with 62 additions and 112 deletions

View file

@ -23,6 +23,9 @@ impl nsStyleImage {
/// Set a given Servo `Image` value into this `nsStyleImage`. /// Set a given Servo `Image` value into this `nsStyleImage`.
pub fn set(&mut self, image: Image) { pub fn set(&mut self, image: Image) {
match image { match image {
GenericImage::None => unsafe {
bindings::Gecko_SetNullImageValue(self);
},
GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient), GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient),
GenericImage::Url(ref url) => unsafe { GenericImage::Url(ref url) => unsafe {
bindings::Gecko_SetLayerImageImageValue(self, url); bindings::Gecko_SetLayerImageImageValue(self, url);
@ -55,35 +58,35 @@ impl nsStyleImage {
} }
/// Converts into Image. /// Converts into Image.
pub unsafe fn into_image(self: &nsStyleImage) -> Option<Image> { pub unsafe fn to_image(&self) -> Image {
use crate::gecko_bindings::structs::nsStyleImageType; use crate::gecko_bindings::structs::nsStyleImageType;
use crate::values::computed::MozImageRect; use crate::values::computed::MozImageRect;
match self.mType { match self.mType {
nsStyleImageType::eStyleImageType_Null => None, nsStyleImageType::eStyleImageType_Null => GenericImage::None,
nsStyleImageType::eStyleImageType_Image => { nsStyleImageType::eStyleImageType_Image => {
let url = self.__bindgen_anon_1.mImage.as_ref().clone(); let url = self.__bindgen_anon_1.mImage.as_ref().clone();
if self.mCropRect.mPtr.is_null() { if self.mCropRect.mPtr.is_null() {
Some(GenericImage::Url(url)) GenericImage::Url(url)
} else { } else {
let rect = &*self.mCropRect.mPtr; let rect = &*self.mCropRect.mPtr;
Some(GenericImage::Rect(Box::new(MozImageRect { GenericImage::Rect(Box::new(MozImageRect {
url, url,
top: rect.0, top: rect.0,
right: rect.1, right: rect.1,
bottom: rect.2, bottom: rect.2,
left: rect.3, left: rect.3,
}))) }))
} }
}, },
nsStyleImageType::eStyleImageType_Gradient => { nsStyleImageType::eStyleImageType_Gradient => {
let gradient: &Gradient = &**self.__bindgen_anon_1.mGradient.as_ref(); let gradient: &Gradient = &**self.__bindgen_anon_1.mGradient.as_ref();
Some(GenericImage::Gradient(Box::new(gradient.clone()))) GenericImage::Gradient(Box::new(gradient.clone()))
}, },
nsStyleImageType::eStyleImageType_Element => { nsStyleImageType::eStyleImageType_Element => {
use crate::gecko_string_cache::Atom; use crate::gecko_string_cache::Atom;
let atom = bindings::Gecko_GetImageElement(self); let atom = bindings::Gecko_GetImageElement(self);
Some(GenericImage::Element(Atom::from_raw(atom))) GenericImage::Element(Atom::from_raw(atom))
}, },
} }
} }
@ -102,7 +105,7 @@ pub mod basic_shape {
impl StyleShapeSource { impl StyleShapeSource {
/// Convert StyleShapeSource to ShapeSource except URL and Image /// Convert StyleShapeSource to ShapeSource except URL and Image
/// types. /// types.
fn into_shape_source<ReferenceBox, ImageOrUrl>( fn to_shape_source<ReferenceBox, ImageOrUrl>(
&self, &self,
) -> Option<ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>> ) -> Option<ShapeSource<BasicShape, ReferenceBox, ImageOrUrl>>
where where
@ -149,14 +152,14 @@ pub mod basic_shape {
use crate::values::generics::image::Image as GenericImage; use crate::values::generics::image::Image as GenericImage;
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let image = shape_image.into_image().expect("Cannot convert to Image"); let image = shape_image.to_image();
match image { match image {
GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0), GenericImage::Url(url) => ShapeSource::ImageOrUrl(url.0),
_ => panic!("ClippingShape doesn't support non-url images"), _ => panic!("ClippingShape doesn't support non-url images"),
} }
}, },
_ => other _ => other
.into_shape_source() .to_shape_source()
.expect("Couldn't convert to StyleSource!"), .expect("Couldn't convert to StyleSource!"),
} }
} }
@ -167,11 +170,11 @@ pub mod basic_shape {
match other.mType { match other.mType {
StyleShapeSourceType::Image => unsafe { StyleShapeSourceType::Image => unsafe {
let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr; let shape_image = &*other.__bindgen_anon_1.mShapeImage.as_ref().mPtr;
let image = shape_image.into_image().expect("Cannot convert to Image"); let image = shape_image.to_image();
ShapeSource::ImageOrUrl(image) ShapeSource::ImageOrUrl(image)
}, },
_ => other _ => other
.into_shape_source() .to_shape_source()
.expect("Couldn't convert to StyleSource!"), .expect("Couldn't convert to StyleSource!"),
} }
} }

View file

@ -47,7 +47,6 @@ use crate::values::computed::url::ComputedImageUrl;
use crate::values::computed::BorderStyle; use crate::values::computed::BorderStyle;
use crate::values::computed::font::FontSize; use crate::values::computed::font::FontSize;
use crate::values::generics::column::ColumnCount; use crate::values::generics::column::ColumnCount;
use crate::values::generics::image::ImageLayer;
pub mod style_structs { pub mod style_structs {
@ -849,14 +848,7 @@ fn static_assert() {
% endfor % endfor
pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) { pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) {
unsafe { self.gecko.mBorderImageSource.set(image);
// Prevent leaking of the last elements we did set
Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
}
if let ImageLayer::Image(image) = image {
self.gecko.mBorderImageSource.set(image);
}
} }
pub fn copy_border_image_source_from(&mut self, other: &Self) { pub fn copy_border_image_source_from(&mut self, other: &Self) {
@ -871,10 +863,7 @@ fn static_assert() {
} }
pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T { pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T {
match unsafe { self.gecko.mBorderImageSource.into_image() } { unsafe { self.gecko.mBorderImageSource.to_image() }
Some(image) => ImageLayer::Image(image),
None => ImageLayer::None,
}
} }
<% <%
@ -2042,9 +2031,7 @@ fn static_assert() {
for (image, geckoimage) in images.zip(self.gecko.${image_layers_field} for (image, geckoimage) in images.zip(self.gecko.${image_layers_field}
.mLayers.iter_mut()) { .mLayers.iter_mut()) {
if let ImageLayer::Image(image) = image { geckoimage.mImage.set(image)
geckoimage.mImage.set(image)
}
} }
} }
@ -2052,12 +2039,8 @@ fn static_assert() {
longhands::${shorthand}_image::computed_value::List( longhands::${shorthand}_image::computed_value::List(
self.gecko.${image_layers_field}.mLayers.iter() self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mImageCount as usize) .take(self.gecko.${image_layers_field}.mImageCount as usize)
.map(|ref layer| { .map(|layer| unsafe { layer.mImage.to_image() })
match unsafe { layer.mImage.into_image() } { .collect()
Some(image) => ImageLayer::Image(image),
None => ImageLayer::None,
}
}).collect()
) )
} }

View file

@ -21,10 +21,10 @@ ${helpers.predefined_type(
${helpers.predefined_type( ${helpers.predefined_type(
"background-image", "background-image",
"ImageLayer", "Image",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
initial_value="computed::ImageLayer::none()", initial_value="computed::Image::None",
initial_specified_value="specified::ImageLayer::none()", initial_specified_value="specified::Image::None",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
vector="True", vector="True",
animation_value_type="discrete", animation_value_type="discrete",

View file

@ -106,10 +106,10 @@ ${helpers.single_keyword(
${helpers.predefined_type( ${helpers.predefined_type(
"border-image-source", "border-image-source",
"ImageLayer", "Image",
engines="gecko servo-2013 servo-2020", engines="gecko servo-2013 servo-2020",
initial_value="computed::ImageLayer::none()", initial_value="computed::Image::None",
initial_specified_value="specified::ImageLayer::none()", initial_specified_value="specified::Image::None",
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
vector=False, vector=False,
animation_value_type="discrete", animation_value_type="discrete",

View file

@ -172,10 +172,10 @@ ${helpers.single_keyword(
${helpers.predefined_type( ${helpers.predefined_type(
"mask-image", "mask-image",
"ImageLayer", "Image",
engines="gecko", engines="gecko",
initial_value="computed::ImageLayer::none()", initial_value="computed::Image::None",
initial_specified_value="specified::ImageLayer::none()", initial_specified_value="specified::Image::None",
parse_method="parse_with_cors_anonymous", parse_method="parse_with_cors_anonymous",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image", spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
vector=True, vector=True,

View file

@ -684,7 +684,7 @@ fn notify_paint_worklet<E>(context: &StyleContext<E>, data: &ElementData)
where where
E: TElement, E: TElement,
{ {
use crate::values::generics::image::{GenericImageLayer, Image}; use crate::values::generics::image::Image;
use style_traits::ToCss; use style_traits::ToCss;
// We speculatively evaluate any paint worklets during styling. // We speculatively evaluate any paint worklets during styling.
@ -694,7 +694,7 @@ where
if let Some(ref values) = data.styles.primary { if let Some(ref values) = data.styles.primary {
for image in &values.get_background().background_image.0 { for image in &values.get_background().background_image.0 {
let (name, arguments) = match *image { let (name, arguments) = match *image {
GenericImageLayer::Image(Image::PaintWorklet(ref worklet)) => { Image::PaintWorklet(ref worklet) => {
(&worklet.name, &worklet.arguments) (&worklet.name, &worklet.arguments)
}, },
_ => continue, _ => continue,

View file

@ -22,9 +22,6 @@ use std::f32::consts::PI;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
/// A computed image layer.
pub type ImageLayer = generic::GenericImageLayer<Image>;
/// Computed values for an image according to CSS-IMAGES. /// Computed values for an image according to CSS-IMAGES.
/// <https://drafts.csswg.org/css-images/#image-values> /// <https://drafts.csswg.org/css-images/#image-values>
pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl>; pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl>;
@ -65,7 +62,7 @@ pub type ColorStop = generic::ColorStop<Color, LengthPercentage>;
/// Computed values for `-moz-image-rect(...)`. /// Computed values for `-moz-image-rect(...)`.
#[cfg(feature = "gecko")] #[cfg(feature = "gecko")]
pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, ComputedImageUrl>; pub type MozImageRect = generic::GenericMozImageRect<NumberOrPercentage, ComputedImageUrl>;
/// Empty enum on non-gecko /// Empty enum on non-gecko
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]

View file

@ -57,7 +57,7 @@ pub use self::font::{FontSize, FontSizeAdjust, FontStretch, FontSynthesis};
pub use self::font::{FontVariantAlternates, FontWeight}; pub use self::font::{FontVariantAlternates, FontWeight};
pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{FontVariantEastAsian, FontVariationSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
pub use self::image::{Gradient, GradientItem, Image, ImageLayer, LineDirection, MozImageRect}; pub use self::image::{Gradient, GradientItem, Image, LineDirection, MozImageRect};
pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength}; pub use self::length::{CSSPixelLength, ExtremumLength, NonNegativeLength};
pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber}; pub use self::length::{Length, LengthOrNumber, LengthPercentage, NonNegativeLengthOrNumber};
pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size}; pub use self::length::{LengthOrAuto, LengthPercentageOrAuto, MaxSize, Size};

View file

@ -13,51 +13,22 @@ use servo_arc::Arc;
use std::fmt::{self, Write}; use std::fmt::{self, Write};
use style_traits::{CssWriter, ToCss}; use style_traits::{CssWriter, ToCss};
/// An <image> | <none> (for background-image, for example). /// An `<image> | none` value.
#[derive(
Clone,
Debug,
MallocSizeOf,
Parse,
PartialEq,
SpecifiedValueInfo,
ToComputedValue,
ToCss,
ToResolvedValue,
ToShmem,
)]
pub enum GenericImageLayer<Image> {
/// The `none` value.
None,
/// The `<image>` value.
Image(Image),
}
pub use self::GenericImageLayer as ImageLayer;
impl<I> ImageLayer<I> {
/// Returns `none`.
#[inline]
pub fn none() -> Self {
ImageLayer::None
}
}
/// An [image].
/// ///
/// [image]: https://drafts.csswg.org/css-images/#image-values /// https://drafts.csswg.org/css-images/#image-values
#[derive( #[derive(
Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem, Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem,
)] )]
#[repr(C, u8)] #[repr(C, u8)]
pub enum GenericImage<Gradient, MozImageRect, ImageUrl> { pub enum GenericImage<G, MozImageRect, ImageUrl> {
/// `none` variant.
None,
/// A `<url()>` image. /// A `<url()>` image.
Url(ImageUrl), Url(ImageUrl),
/// A `<gradient>` image. Gradients are rather large, and not nearly as /// A `<gradient>` image. Gradients are rather large, and not nearly as
/// common as urls, so we box them here to keep the size of this enum sane. /// common as urls, so we box them here to keep the size of this enum sane.
Gradient(Box<Gradient>), Gradient(Box<G>),
/// A `-moz-image-rect` image. Also fairly large and rare. /// A `-moz-image-rect` image. Also fairly large and rare.
// not cfged out on non-Gecko to avoid `error[E0392]: parameter `MozImageRect` is never used` // not cfged out on non-Gecko to avoid `error[E0392]: parameter `MozImageRect` is never used`
// Instead we make MozImageRect an empty enum // Instead we make MozImageRect an empty enum
@ -285,7 +256,7 @@ impl ToCss for PaintWorklet {
/// ///
/// `-moz-image-rect(<uri>, top, right, bottom, left);` /// `-moz-image-rect(<uri>, top, right, bottom, left);`
#[allow(missing_docs)] #[allow(missing_docs)]
#[css(comma, function)] #[css(comma, function = "-moz-image-rect")]
#[derive( #[derive(
Clone, Clone,
Debug, Debug,
@ -297,7 +268,8 @@ impl ToCss for PaintWorklet {
ToResolvedValue, ToResolvedValue,
ToShmem, ToShmem,
)] )]
pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> { #[repr(C)]
pub struct GenericMozImageRect<NumberOrPercentage, MozImageRectUrl> {
pub url: MozImageRectUrl, pub url: MozImageRectUrl,
pub top: NumberOrPercentage, pub top: NumberOrPercentage,
pub right: NumberOrPercentage, pub right: NumberOrPercentage,
@ -305,6 +277,8 @@ pub struct MozImageRect<NumberOrPercentage, MozImageRectUrl> {
pub left: NumberOrPercentage, pub left: NumberOrPercentage,
} }
pub use self::GenericMozImageRect as MozImageRect;
impl<G, R, U> fmt::Debug for Image<G, R, U> impl<G, R, U> fmt::Debug for Image<G, R, U>
where where
G: ToCss, G: ToCss,
@ -327,6 +301,7 @@ where
W: Write, W: Write,
{ {
match *self { match *self {
Image::None => dest.write_str("none"),
Image::Url(ref url) => url.to_css(dest), Image::Url(ref url) => url.to_css(dest),
Image::Gradient(ref gradient) => gradient.to_css(dest), Image::Gradient(ref gradient) => gradient.to_css(dest),
Image::Rect(ref rect) => rect.to_css(dest), Image::Rect(ref rect) => rect.to_css(dest),

View file

@ -71,6 +71,10 @@ impl Parse for ClippingShape {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(ShapeSource::None);
}
if is_clip_path_path_enabled(context) { if is_clip_path_path_enabled(context) {
if let Ok(p) = input.try(|i| Path::parse(context, i)) { if let Ok(p) = input.try(|i| Path::parse(context, i)) {
return Ok(ShapeSource::Path(p)); return Ok(ShapeSource::Path(p));
@ -91,7 +95,14 @@ impl Parse for FloatAreaShape {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
// Need to parse this here so that `Image::parse_with_cors_anonymous`
// doesn't parse it.
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(ShapeSource::None);
}
if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) { if let Ok(image) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) {
debug_assert_ne!(image, Image::None);
return Ok(ShapeSource::ImageOrUrl(image)); return Ok(ShapeSource::ImageOrUrl(image));
} }
@ -108,10 +119,6 @@ where
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> { ) -> Result<Self, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(ShapeSource::None);
}
fn parse_component<U: Parse>( fn parse_component<U: Parse>(
context: &ParserContext, context: &ParserContext,
input: &mut Parser, input: &mut Parser,

View file

@ -32,24 +32,6 @@ use std::fmt::{self, Write};
use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError}; use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError};
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss}; use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
/// A specified image layer.
pub type ImageLayer = generic::GenericImageLayer<Image>;
impl ImageLayer {
/// This is a specialization of Either with an alternative parse
/// method to provide anonymous CORS headers for the Image url fetch.
pub fn parse_with_cors_anonymous<'i, 't>(
context: &ParserContext,
input: &mut Parser<'i, 't>,
) -> Result<Self, ParseError<'i>> {
if let Ok(v) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) {
return Ok(generic::GenericImageLayer::Image(v));
}
input.expect_ident_matching("none")?;
Ok(generic::GenericImageLayer::None)
}
}
/// Specified values for an image according to CSS-IMAGES. /// Specified values for an image according to CSS-IMAGES.
/// <https://drafts.csswg.org/css-images/#image-values> /// <https://drafts.csswg.org/css-images/#image-values>
pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl>; pub type Image = generic::Image<Gradient, MozImageRect, SpecifiedImageUrl>;
@ -118,8 +100,8 @@ pub type ColorStop = generic::ColorStop<Color, LengthPercentage>;
/// Specified values for `moz-image-rect` /// Specified values for `moz-image-rect`
/// -moz-image-rect(<uri>, top, right, bottom, left); /// -moz-image-rect(<uri>, top, right, bottom, left);
#[cfg(feature = "gecko")] #[cfg(all(feature = "gecko", not(feature = "cbindgen")))]
pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, SpecifiedImageUrl>; pub type MozImageRect = generic::GenericMozImageRect<NumberOrPercentage, SpecifiedImageUrl>;
#[cfg(not(feature = "gecko"))] #[cfg(not(feature = "gecko"))]
#[derive( #[derive(
@ -141,6 +123,9 @@ impl Parse for Image {
context: &ParserContext, context: &ParserContext,
input: &mut Parser<'i, 't>, input: &mut Parser<'i, 't>,
) -> Result<Image, ParseError<'i>> { ) -> Result<Image, ParseError<'i>> {
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
return Ok(generic::Image::None);
}
if let Ok(url) = input.try(|input| SpecifiedImageUrl::parse(context, input)) { if let Ok(url) = input.try(|input| SpecifiedImageUrl::parse(context, input)) {
return Ok(generic::Image::Url(url)); return Ok(generic::Image::Url(url));
} }

View file

@ -56,7 +56,7 @@ pub use self::font::{FontVariantAlternates, FontWeight};
pub use self::font::{FontVariantEastAsian, FontVariationSettings}; pub use self::font::{FontVariantEastAsian, FontVariationSettings};
pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom}; pub use self::font::{MozScriptLevel, MozScriptMinSize, MozScriptSizeMultiplier, XLang, XTextZoom};
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient}; pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
pub use self::image::{GradientItem, GradientKind, Image, ImageLayer, MozImageRect}; pub use self::image::{GradientItem, GradientKind, Image, MozImageRect};
pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth}; pub use self::length::{AbsoluteLength, CalcLengthPercentage, CharacterWidth};
pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber}; pub use self::length::{FontRelativeLength, Length, LengthOrNumber, NonNegativeLengthOrNumber};
pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto}; pub use self::length::{LengthOrAuto, LengthPercentage, LengthPercentageOrAuto};