mirror of
https://github.com/servo/servo.git
synced 2025-08-06 14:10:11 +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) {
|
||||
% for side in SIDES:
|
||||
v.${side.index}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset
|
||||
.data_at_mut(${side.index}));
|
||||
v.${side.ident}.to_gecko_style_coord(&mut self.gecko.mBorderImageOutset.data_at_mut(${side.index}));
|
||||
% endfor
|
||||
}
|
||||
|
||||
|
|
|
@ -200,109 +200,13 @@ ${helpers.predefined_type("border-image-source", "ImageLayer",
|
|||
has_uncacheable_values=False,
|
||||
boxed="True")}
|
||||
|
||||
<%helpers:longhand name="border-image-outset" animation_value_type="none"
|
||||
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset">
|
||||
use std::fmt;
|
||||
use style_traits::ToCss;
|
||||
use values::specified::{LengthOrNumber, Number};
|
||||
|
||||
pub mod computed_value {
|
||||
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.predefined_type("border-image-outset", "LengthOrNumberRect",
|
||||
parse_method="parse_non_negative",
|
||||
initial_value="computed::LengthOrNumber::zero().into()",
|
||||
initial_specified_value="specified::LengthOrNumber::zero().into()",
|
||||
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset",
|
||||
animation_value_type="none",
|
||||
boxed=True)}
|
||||
|
||||
<%helpers:longhand name="border-image-repeat" animation_value_type="none"
|
||||
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.
|
||||
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.
|
||||
pub type LengthOrNormal = Either<Length, Normal>;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ use super::specified;
|
|||
pub use app_units::Au;
|
||||
pub use cssparser::Color as CSSColor;
|
||||
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
|
||||
pub use self::rect::LengthOrNumberRect;
|
||||
pub use super::{Auto, Either, None_};
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||
|
@ -40,6 +41,7 @@ pub mod basic_shape;
|
|||
pub mod image;
|
||||
pub mod length;
|
||||
pub mod position;
|
||||
pub mod rect;
|
||||
|
||||
/// A `Context` is all the data a specified value could ever need to compute
|
||||
/// 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 image;
|
||||
pub mod position;
|
||||
pub mod rect;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, ToComputedValue)]
|
||||
#[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)
|
||||
}
|
||||
|
||||
/// Returns `0`.
|
||||
#[inline]
|
||||
pub fn zero() -> Self {
|
||||
Either::Second(Number::new(0.))
|
||||
}
|
||||
}
|
||||
|
||||
/// A value suitable for a `min-width` or `min-height` property.
|
||||
|
|
|
@ -30,6 +30,7 @@ use values::specified::calc::CalcNode;
|
|||
|
||||
#[cfg(feature = "gecko")]
|
||||
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||
pub use self::rect::LengthOrNumberRect;
|
||||
pub use self::color::Color;
|
||||
pub use super::generics::grid::GridLine;
|
||||
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
|
||||
|
@ -50,6 +51,7 @@ pub mod grid;
|
|||
pub mod image;
|
||||
pub mod length;
|
||||
pub mod position;
|
||||
pub mod rect;
|
||||
|
||||
/// Common handling for the specified value CSS url() values.
|
||||
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