From 3f53fb148db3d4891e30ea2de71388b1ef9f42d2 Mon Sep 17 00:00:00 2001 From: Ravi Shankar Date: Fri, 14 Apr 2017 19:22:50 +0530 Subject: [PATCH] Add generic versions of Position structs --- components/style/values/generics/position.rs | 142 +++++++++++++++++++ 1 file changed, 142 insertions(+) diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index 4cfbb860afd..7ecfafdf356 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -10,6 +10,7 @@ use parser::{Parse, ParserContext}; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; +use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; use values::specified::{LengthOrPercentage, Percentage}; define_css_keyword_enum!{ Keyword: @@ -112,3 +113,144 @@ impl ToCss for PositionValue { Ok(()) } } + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +/// A generic type for representing horizontal `` +pub struct HorizontalPosition(pub L); + +impl ToCss for HorizontalPosition { + #[inline] + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } +} + +impl HasViewportPercentage for HorizontalPosition { + #[inline] + fn has_viewport_percentage(&self) -> bool { + self.0.has_viewport_percentage() + } +} + +impl Parse for HorizontalPosition> { + #[inline] + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + PositionValue::parse_internal(context, input, |keyword| { + matches!{ keyword, + Keyword::Left | Keyword::Right | Keyword::Center | + Keyword::XStart | Keyword::XEnd + } + }).map(HorizontalPosition) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +/// A generic type for representing vertical `` +pub struct VerticalPosition(pub L); + +impl ToCss for VerticalPosition { + #[inline] + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.0.to_css(dest) + } +} + +impl HasViewportPercentage for VerticalPosition { + #[inline] + fn has_viewport_percentage(&self) -> bool { + self.0.has_viewport_percentage() + } +} + +impl Parse for VerticalPosition> { + #[inline] + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + PositionValue::parse_internal(context, input, |keyword| { + matches!{ keyword, + Keyword::Top | Keyword::Bottom | Keyword::Center | + Keyword::YStart | Keyword::YEnd + } + }).map(VerticalPosition) + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +/// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). +/// +/// Note that the horizontal and vertical positions aren't really different types. +/// They're just unit struct wrappers over `LengthOrPercentage`. They should be different +/// because they allow different keywords (for e.g., vertical position doesn't allow +/// `right` or `left` keywords and vice versa). +pub struct Position { + /// The horizontal component of position. + pub horizontal: H, + /// The vertical component of position. + pub vertical: V, +} + +/// A generic type for representing positions with keywords. +pub type PositionWithKeyword = Position, VerticalPosition>; + +impl HasViewportPercentage for Position { + #[inline] + fn has_viewport_percentage(&self) -> bool { + self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage() + } +} + +impl ToCss for Position { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + self.horizontal.to_css(dest)?; + dest.write_str(" ")?; + self.vertical.to_css(dest) + } +} + +impl ToCss for PositionWithKeyword> { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + macro_rules! to_css_with_keyword { + ($pos:expr, $default:expr) => { + $pos.keyword.unwrap_or($default).to_css(dest)?; + if let Some(ref position) = $pos.position { + dest.write_str(" ")?; + position.to_css(dest)?; + } + } + } + + if (self.horizontal.0.keyword.is_some() && self.horizontal.0.position.is_some()) || + (self.vertical.0.keyword.is_some() && self.vertical.0.position.is_some()) { + to_css_with_keyword!(self.horizontal.0, Keyword::Left); + dest.write_str(" ")?; + to_css_with_keyword!(self.vertical.0, Keyword::Top); + return Ok(()) + } + + self.horizontal.to_css(dest)?; + dest.write_str(" ")?; + self.vertical.to_css(dest) + } +} + +impl ToComputedValue for Position { + type ComputedValue = Position; + + #[inline] + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + Position { + horizontal: self.horizontal.to_computed_value(context), + vertical: self.vertical.to_computed_value(context), + } + } + + #[inline] + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + Position { + horizontal: ToComputedValue::from_computed_value(&computed.horizontal), + vertical: ToComputedValue::from_computed_value(&computed.vertical), + } + } +}