From 6f062e585794d077bc391ccbcaad0d86a95879b6 Mon Sep 17 00:00:00 2001 From: Ravi Shankar Date: Fri, 14 Apr 2017 15:39:13 +0530 Subject: [PATCH] Add a generic PositionValue struct --- components/style/values/generics/mod.rs | 1 + components/style/values/generics/position.rs | 114 +++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100644 components/style/values/generics/position.rs diff --git a/components/style/values/generics/mod.rs b/components/style/values/generics/mod.rs index 75ca9ccf8ab..c0a3823f3b0 100644 --- a/components/style/values/generics/mod.rs +++ b/components/style/values/generics/mod.rs @@ -14,6 +14,7 @@ use super::computed::{Context, ToComputedValue}; pub use self::basic_shape::serialize_radius_values; pub mod basic_shape; +pub mod position; #[derive(Clone, PartialEq, Debug)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs new file mode 100644 index 00000000000..4cfbb860afd --- /dev/null +++ b/components/style/values/generics/position.rs @@ -0,0 +1,114 @@ +/* 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 handling of specified and computed values of +//! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) + +use cssparser::Parser; +use parser::{Parse, ParserContext}; +use std::fmt; +use style_traits::ToCss; +use values::HasViewportPercentage; +use values::specified::{LengthOrPercentage, Percentage}; + +define_css_keyword_enum!{ Keyword: + "center" => Center, + "left" => Left, + "right" => Right, + "top" => Top, + "bottom" => Bottom, + "x-start" => XStart, + "x-end" => XEnd, + "y-start" => YStart, + "y-end" => YEnd +} + +impl From for LengthOrPercentage { + fn from(val: Keyword) -> LengthOrPercentage { + match val { + Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)), + Keyword::Left | Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)), + Keyword::Right | Keyword::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)), + // FIXME(canaltinova): Support logical keywords + Keyword::XStart | Keyword::YStart => LengthOrPercentage::Percentage(Percentage(0.0)), + Keyword::XEnd | Keyword::YEnd => LengthOrPercentage::Percentage(Percentage(1.0)), + } + } +} + +#[derive(Debug, Clone, PartialEq)] +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +/// A generic type for representing horizontal or vertical `` value. +pub struct PositionValue { + /// Even though this is generic, it's always a `` value. + pub position: Option, + /// A position keyword. + pub keyword: Option, +} + +impl HasViewportPercentage for PositionValue { + #[inline] + fn has_viewport_percentage(&self) -> bool { + self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage()) + } +} + +impl PositionValue { + /// Internal parsing function which (after parsing) checks the keyword with the + /// given function. + pub fn parse_internal(context: &ParserContext, input: &mut Parser, + mut is_allowed_keyword: F) -> Result, ()> + where F: FnMut(Keyword) -> bool + { + let (mut pos, mut keyword) = (None, None); + for _ in 0..2 { + if let Ok(l) = input.try(|i| L::parse(context, i)) { + if pos.is_some() { + return Err(()) + } + + pos = Some(l); + } + + if let Ok(k) = input.try(Keyword::parse) { + if keyword.is_some() || !is_allowed_keyword(k) { + return Err(()) + } + + keyword = Some(k); + } + } + + if pos.is_some() { + if let Some(Keyword::Center) = keyword { + return Err(()) // "center" and is not allowed + } + } else if keyword.is_none() { + return Err(()) // at least one value is necessary + } + + Ok(PositionValue { + position: pos, + keyword: keyword, + }) + } +} + +impl ToCss for PositionValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + if let Some(keyword) = self.keyword { + keyword.to_css(dest)?; + } + + if let Some(ref position) = self.position { + if self.keyword.is_some() { + dest.write_str(" ")?; + } + + position.to_css(dest)?; + } + + Ok(()) + } +}