mirror of
https://github.com/servo/servo.git
synced 2025-08-06 22:15:33 +01:00
Introduce style::values::generics::rect ▭
This defines a single type Rect<T> which allows us to abstract over CSS values made of four sides top, right, bottom and left.
This commit is contained in:
parent
e9c5860808
commit
7a214831f0
10 changed files with 169 additions and 105 deletions
|
@ -959,8 +959,7 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn set_border_image_outset(&mut self, v: longhands::border_image_outset::computed_value::T) {
|
pub fn set_border_image_outset(&mut self, v: longhands::border_image_outset::computed_value::T) {
|
||||||
% for side in SIDES:
|
% for side in SIDES:
|
||||||
v.${side.index}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset
|
v.${side.ident}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset.data_at_mut(${side.index}));
|
||||||
.data_at_mut(${side.index}));
|
|
||||||
% endfor
|
% endfor
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -200,109 +200,13 @@ ${helpers.predefined_type("border-image-source", "ImageLayer",
|
||||||
has_uncacheable_values=False,
|
has_uncacheable_values=False,
|
||||||
boxed="True")}
|
boxed="True")}
|
||||||
|
|
||||||
<%helpers:longhand name="border-image-outset" animation_value_type="none"
|
${helpers.predefined_type("border-image-outset", "LengthOrNumberRect",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset">
|
parse_method="parse_non_negative",
|
||||||
use std::fmt;
|
initial_value="computed::LengthOrNumber::zero().into()",
|
||||||
use style_traits::ToCss;
|
initial_specified_value="specified::LengthOrNumber::zero().into()",
|
||||||
use values::specified::{LengthOrNumber, Number};
|
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
|
||||||
|
animation_value_type="none",
|
||||||
pub mod computed_value {
|
boxed=True)}
|
||||||
use values::computed::LengthOrNumber;
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct T(pub LengthOrNumber, pub LengthOrNumber,
|
|
||||||
pub LengthOrNumber, pub LengthOrNumber);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, HasViewportPercentage, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct SpecifiedValue(pub Vec<LengthOrNumber>);
|
|
||||||
|
|
||||||
impl ToCss for computed_value::T {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(self.0.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.1.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.2.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
self.3.to_css(dest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl ToCss for SpecifiedValue {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(self.0[0].to_css(dest));
|
|
||||||
for value in self.0.iter().skip(1) {
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(value.to_css(dest));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
computed_value::T(Either::Second(0.0), Either::Second(0.0),
|
|
||||||
Either::Second(0.0), Either::Second(0.0))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
|
||||||
SpecifiedValue(vec![Either::Second(Number::new(0.0))])
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for SpecifiedValue {
|
|
||||||
type ComputedValue = computed_value::T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
|
||||||
let length = self.0.len();
|
|
||||||
match length {
|
|
||||||
4 => computed_value::T(self.0[0].to_computed_value(context),
|
|
||||||
self.0[1].to_computed_value(context),
|
|
||||||
self.0[2].to_computed_value(context),
|
|
||||||
self.0[3].to_computed_value(context)),
|
|
||||||
3 => computed_value::T(self.0[0].to_computed_value(context),
|
|
||||||
self.0[1].to_computed_value(context),
|
|
||||||
self.0[2].to_computed_value(context),
|
|
||||||
self.0[1].to_computed_value(context)),
|
|
||||||
2 => computed_value::T(self.0[0].to_computed_value(context),
|
|
||||||
self.0[1].to_computed_value(context),
|
|
||||||
self.0[0].to_computed_value(context),
|
|
||||||
self.0[1].to_computed_value(context)),
|
|
||||||
1 => computed_value::T(self.0[0].to_computed_value(context),
|
|
||||||
self.0[0].to_computed_value(context),
|
|
||||||
self.0[0].to_computed_value(context),
|
|
||||||
self.0[0].to_computed_value(context)),
|
|
||||||
_ => unreachable!(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
|
||||||
SpecifiedValue(vec![ToComputedValue::from_computed_value(&computed.0),
|
|
||||||
ToComputedValue::from_computed_value(&computed.1),
|
|
||||||
ToComputedValue::from_computed_value(&computed.2),
|
|
||||||
ToComputedValue::from_computed_value(&computed.3)])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
|
||||||
let mut values = vec![];
|
|
||||||
for _ in 0..4 {
|
|
||||||
let value = input.try(|input| LengthOrNumber::parse_non_negative(context, input));
|
|
||||||
match value {
|
|
||||||
Ok(val) => values.push(val),
|
|
||||||
Err(_) => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if values.len() > 0 {
|
|
||||||
Ok(SpecifiedValue(values))
|
|
||||||
} else {
|
|
||||||
Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
<%helpers:longhand name="border-image-repeat" animation_value_type="none"
|
<%helpers:longhand name="border-image-repeat" animation_value_type="none"
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#border-image-repeat">
|
spec="https://drafts.csswg.org/css-backgrounds/#border-image-repeat">
|
||||||
|
|
|
@ -603,6 +603,14 @@ pub type LengthOrAuto = Either<Length, Auto>;
|
||||||
/// Either a computed `<length>` or a `<number>` value.
|
/// Either a computed `<length>` or a `<number>` value.
|
||||||
pub type LengthOrNumber = Either<Length, Number>;
|
pub type LengthOrNumber = Either<Length, Number>;
|
||||||
|
|
||||||
|
impl LengthOrNumber {
|
||||||
|
/// Returns `0`.
|
||||||
|
#[inline]
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Either::Second(0.)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Either a computed `<length>` or the `normal` keyword.
|
/// Either a computed `<length>` or the `normal` keyword.
|
||||||
pub type LengthOrNormal = Either<Length, Normal>;
|
pub type LengthOrNormal = Either<Length, Normal>;
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ use super::specified;
|
||||||
pub use app_units::Au;
|
pub use app_units::Au;
|
||||||
pub use cssparser::Color as CSSColor;
|
pub use cssparser::Color as CSSColor;
|
||||||
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
|
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
|
||||||
|
pub use self::rect::LengthOrNumberRect;
|
||||||
pub use super::{Auto, Either, None_};
|
pub use super::{Auto, Either, None_};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||||
|
@ -40,6 +41,7 @@ pub mod basic_shape;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod length;
|
pub mod length;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
|
pub mod rect;
|
||||||
|
|
||||||
/// A `Context` is all the data a specified value could ever need to compute
|
/// A `Context` is all the data a specified value could ever need to compute
|
||||||
/// itself and be transformed to a computed value.
|
/// itself and be transformed to a computed value.
|
||||||
|
|
11
components/style/values/computed/rect.rs
Normal file
11
components/style/values/computed/rect.rs
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Computed types for CSS borders.
|
||||||
|
|
||||||
|
use values::computed::length::LengthOrNumber;
|
||||||
|
use values::generics::rect::Rect;
|
||||||
|
|
||||||
|
/// A specified rectangle made of four `<length-or-number>` values.
|
||||||
|
pub type LengthOrNumberRect = Rect<LengthOrNumber>;
|
|
@ -19,6 +19,7 @@ pub mod basic_shape;
|
||||||
pub mod grid;
|
pub mod grid;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
|
pub mod rect;
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
|
110
components/style/values/generics/rect.rs
Normal file
110
components/style/values/generics/rect.rs
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Generic types for CSS values that are composed of four sides.
|
||||||
|
|
||||||
|
use cssparser::Parser;
|
||||||
|
use parser::{Parse, ParserContext};
|
||||||
|
use std::fmt;
|
||||||
|
use style_traits::ToCss;
|
||||||
|
|
||||||
|
/// A CSS value made of four sides: top, right, bottom, and left.
|
||||||
|
#[derive(Clone, Copy, Debug, HasViewportPercentage, PartialEq, ToComputedValue)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct Rect<T> {
|
||||||
|
/// Top
|
||||||
|
pub top: T,
|
||||||
|
/// Right.
|
||||||
|
pub right: T,
|
||||||
|
/// Bottom.
|
||||||
|
pub bottom: T,
|
||||||
|
/// Left.
|
||||||
|
pub left: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Rect<T> {
|
||||||
|
/// Returns a new `Rect<T>` value.
|
||||||
|
pub fn new(top: T, right: T, bottom: T, left: T) -> Self {
|
||||||
|
Rect {
|
||||||
|
top: top,
|
||||||
|
right: right,
|
||||||
|
bottom: bottom,
|
||||||
|
left: left,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Rect<T>
|
||||||
|
where T: Clone
|
||||||
|
{
|
||||||
|
/// Parses a new `Rect<T>` value with the given parse function.
|
||||||
|
pub fn parse_with<Parse>(
|
||||||
|
context: &ParserContext,
|
||||||
|
input: &mut Parser,
|
||||||
|
parse: Parse)
|
||||||
|
-> Result<Self, ()>
|
||||||
|
where Parse: Fn(&ParserContext, &mut Parser) -> Result<T, ()>
|
||||||
|
{
|
||||||
|
let top = parse(context, input)?;
|
||||||
|
let right = if let Ok(right) = input.try(|i| parse(context, i)) { right } else {
|
||||||
|
// <top>
|
||||||
|
return Ok(Self::new(top.clone(), top.clone(), top.clone(), top));
|
||||||
|
};
|
||||||
|
let bottom = if let Ok(bottom) = input.try(|i| parse(context, i)) { bottom } else {
|
||||||
|
// <top> <right>
|
||||||
|
return Ok(Self::new(top.clone(), right.clone(), top, right));
|
||||||
|
};
|
||||||
|
let left = if let Ok(left) = input.try(|i| parse(context, i)) { left } else {
|
||||||
|
// <top> <right> <bottom>
|
||||||
|
return Ok(Self::new(top, right.clone(), bottom, right));
|
||||||
|
};
|
||||||
|
// <top> <right> <bottom> <left>
|
||||||
|
Ok(Self::new(top, right, bottom, left))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for Rect<T>
|
||||||
|
where T: Clone
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Self::new(value.clone(), value.clone(), value.clone(), value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Parse for Rect<T>
|
||||||
|
where T: Clone + Parse
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
Self::parse_with(context, input, T::parse)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> ToCss for Rect<T>
|
||||||
|
where T: PartialEq + ToCss
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result
|
||||||
|
where W: fmt::Write,
|
||||||
|
{
|
||||||
|
self.top.to_css(dest)?;
|
||||||
|
let same_vertical = self.top == self.bottom;
|
||||||
|
let same_horizontal = self.right == self.left;
|
||||||
|
if same_vertical && same_horizontal && self.top == self.right {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.right.to_css(dest)?;
|
||||||
|
if same_vertical && same_horizontal {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.bottom.to_css(dest)?;
|
||||||
|
if same_horizontal {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.left.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
|
@ -1180,6 +1180,12 @@ impl LengthOrNumber {
|
||||||
|
|
||||||
Length::parse_non_negative(context, input).map(Either::First)
|
Length::parse_non_negative(context, input).map(Either::First)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns `0`.
|
||||||
|
#[inline]
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Either::Second(Number::new(0.))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A value suitable for a `min-width` or `min-height` property.
|
/// A value suitable for a `min-width` or `min-height` property.
|
||||||
|
|
|
@ -30,6 +30,7 @@ use values::specified::calc::CalcNode;
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||||
|
pub use self::rect::LengthOrNumberRect;
|
||||||
pub use self::color::Color;
|
pub use self::color::Color;
|
||||||
pub use super::generics::grid::GridLine;
|
pub use super::generics::grid::GridLine;
|
||||||
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
|
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
|
||||||
|
@ -50,6 +51,7 @@ pub mod grid;
|
||||||
pub mod image;
|
pub mod image;
|
||||||
pub mod length;
|
pub mod length;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
|
pub mod rect;
|
||||||
|
|
||||||
/// Common handling for the specified value CSS url() values.
|
/// Common handling for the specified value CSS url() values.
|
||||||
pub mod url {
|
pub mod url {
|
||||||
|
|
21
components/style/values/specified/rect.rs
Normal file
21
components/style/values/specified/rect.rs
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
//! Computed types for CSS borders.
|
||||||
|
|
||||||
|
use cssparser::Parser;
|
||||||
|
use parser::ParserContext;
|
||||||
|
use values::generics::rect::Rect;
|
||||||
|
use values::specified::length::LengthOrNumber;
|
||||||
|
|
||||||
|
/// A specified rectangle made of four `<length-or-number>` values.
|
||||||
|
pub type LengthOrNumberRect = Rect<LengthOrNumber>;
|
||||||
|
|
||||||
|
impl LengthOrNumberRect {
|
||||||
|
/// Parses a `LengthOrNumberRect`, rejecting negative values.
|
||||||
|
#[inline]
|
||||||
|
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
Rect::parse_with(context, input, LengthOrNumber::parse_non_negative)
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue