diff options
Diffstat (limited to 'components')
-rw-r--r-- | components/style/properties/longhand/background.mako.rs | 6 | ||||
-rw-r--r-- | components/style/values/specified/basic_shape.rs | 12 | ||||
-rw-r--r-- | components/style/values/specified/position.rs | 212 |
3 files changed, 182 insertions, 48 deletions
diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index 9ad9daf4262..893a0985d4b 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -107,8 +107,10 @@ ${helpers.predefined_type("background-color", "CSSColor", pub fn get_initial_specified_value() -> SpecifiedValue { use values::specified::Percentage; Position { - horizontal: specified::LengthOrPercentage::Percentage(Percentage(0.0)), - vertical: specified::LengthOrPercentage::Percentage(Percentage(0.0)), + horiz_keyword: None, + horiz_position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))), + vert_keyword: None, + vert_position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))), } } diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index ff9b88559a6..f5813a35b05 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -265,8 +265,10 @@ impl Circle { } else { // Defaults to origin Position { - horizontal: LengthOrPercentage::Percentage(Percentage(0.5)), - vertical: LengthOrPercentage::Percentage(Percentage(0.5)), + horiz_keyword: None, + horiz_position: Some(LengthOrPercentage::Percentage(Percentage(0.5))), + vert_keyword: None, + vert_position: Some(LengthOrPercentage::Percentage(Percentage(0.5))), } }; Ok(Circle { @@ -329,8 +331,10 @@ impl Ellipse { } else { // Defaults to origin Position { - horizontal: LengthOrPercentage::Percentage(Percentage(0.5)), - vertical: LengthOrPercentage::Percentage(Percentage(0.5)), + horiz_keyword: None, + horiz_position: Some(LengthOrPercentage::Percentage(Percentage(0.5))), + vert_keyword: None, + vert_position: Some(LengthOrPercentage::Percentage(Percentage(0.5))), } }; Ok(Ellipse { diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index 071df767f38..3ce32adf22f 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -17,28 +17,54 @@ use values::specified::{LengthOrPercentage, Percentage}; #[derive(Debug, Clone, PartialEq, Copy)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub struct Position { - pub horizontal: LengthOrPercentage, - pub vertical: LengthOrPercentage, + pub horiz_keyword: Option<Keyword>, + pub horiz_position: Option<LengthOrPercentage>, + pub vert_keyword: Option<Keyword>, + pub vert_position: Option<LengthOrPercentage>, } impl ToCss for Position { fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - try!(self.horizontal.to_css(dest)); + // TODO: canaltinova: We should add keywords, probably? + if let Some(horiz_pos) = self.horiz_position { + if let Some(horiz_key) = self.horiz_keyword { + try!(horiz_key.to_css(dest)); + }; + try!(horiz_pos.to_css(dest)); + }; + try!(dest.write_str(" ")); - try!(self.vertical.to_css(dest)); + + if let Some(vert_pos) = self.vert_position { + if let Some(vert_key) = self.vert_keyword { + try!(vert_key.to_css(dest)); + }; + try!(vert_pos.to_css(dest)); + }; Ok(()) } } impl HasViewportPercentage for Position { fn has_viewport_percentage(&self) -> bool { - self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage() + let horiz_viewport = if let Some(horiz_pos) = self.horiz_position { + horiz_pos.has_viewport_percentage() + } else { + false + }; + + let vert_viewport = if let Some(vert_pos) = self.vert_position { + vert_pos.has_viewport_percentage() + } else { + false + }; + horiz_viewport || vert_viewport } } -// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position + #[derive(Clone, PartialEq, Copy)] -pub enum PositionComponent { - LengthOrPercentage(LengthOrPercentage), +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +pub enum Keyword { Center, Left, Right, @@ -46,10 +72,49 @@ pub enum PositionComponent { Bottom, } +// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position +#[derive(Clone, PartialEq, Copy)] +pub enum PositionComponent { + Length(LengthOrPercentage), + Keyword(Keyword), +} + impl Position { - pub fn new(first: PositionComponent, second: PositionComponent) + pub fn new(first_position: Option<PositionComponent>, second_position: Option<PositionComponent>, + first_keyword: Option<PositionComponent>, second_keyword: Option<PositionComponent>) -> Result<Position, ()> { - let (horiz, vert) = match (category(first), category(second)) { + // Check firts and second positions, this is more like for 2 value backgrounds. + let (mut horiz, mut vert) = if let Some(first_pos) = first_position { + if let Some(second_pos) = second_position { + match (category(first_pos), category(second_pos)) { + // Don't allow two vertical keywords or two horizontal keywords. + // also don't allow length/percentage values in the wrong position + (PositionCategory::HorizontalKeyword, PositionCategory::HorizontalKeyword) | + (PositionCategory::VerticalKeyword, PositionCategory::VerticalKeyword) | + (PositionCategory::LengthOrPercentage, PositionCategory::HorizontalKeyword) | + (PositionCategory::VerticalKeyword, PositionCategory::LengthOrPercentage) => return Err(()), + + // Swap if both are keywords and vertical precedes horizontal. + (PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) | + (PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) | + (PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => + (second_position, first_position), + // By default, horizontal is first. + _ => (first_position, second_position), + } + } else { + (first_position, second_position) + } + } else { + (first_position, second_position) + }; + + // Unwrap for checking if values are at right place. + let first_key = first_keyword.unwrap_or(PositionComponent::Keyword(Keyword::Left)); + let second_key = second_keyword.unwrap_or(PositionComponent::Keyword(Keyword::Top)); + + // Check first and second keywords. This is for 4 value swapping. + let (horiz_keyword, vert_keyword) = match (category(first_key), category(second_key)) { // Don't allow two vertical keywords or two horizontal keywords. // also don't allow length/percentage values in the wrong position (PositionCategory::HorizontalKeyword, PositionCategory::HorizontalKeyword) | @@ -60,21 +125,80 @@ impl Position { // Swap if both are keywords and vertical precedes horizontal. (PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) | (PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) | - (PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => (second, first), + (PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => { + let tmp = horiz; + horiz = vert; + vert = tmp; + + (second_keyword, first_keyword) + }, // By default, horizontal is first. - _ => (first, second), + _ => (first_keyword, second_keyword), }; + + // Unwrap keywords from PositionComponent and wrap with Option. + let (wrapped_horiz_key, wrapped_vert_key) = if let Some(PositionComponent::Keyword(horiz_key)) = horiz_keyword { + if let Some(PositionComponent::Keyword(vert_key)) = vert_keyword { + (Some(horiz_key), Some(vert_key)) + } else { + (Some(horiz_key), None) + } + } else { + (None, None) + }; + Ok(Position { - horizontal: horiz.to_length_or_percentage(), - vertical: vert.to_length_or_percentage(), + horiz_keyword: wrapped_horiz_key, + horiz_position: Some(horiz.unwrap().to_length_or_percentage()), + vert_keyword: wrapped_vert_key, + vert_position: Some(vert.unwrap().to_length_or_percentage()), }) } pub fn parse(input: &mut Parser) -> Result<Position, ()> { let first = try!(PositionComponent::parse(input)); let second = input.try(PositionComponent::parse) - .unwrap_or(PositionComponent::Center); - Position::new(first, second) + .unwrap_or(PositionComponent::Keyword(Keyword::Center)); + + // Try to parse third and fourth values + if let Ok(third) = input.try(PositionComponent::parse) { + if let Ok(fourth) = input.try(PositionComponent::parse) { + // Handle 4 value background position + Position::new(Some(second), Some(fourth), Some(first), Some(third)) + } else { + // Handle 3 value background position + if let PositionCategory::LengthOrPercentage = category(first) { + // "20px bottom 20%" + Position::new(Some(first), Some(third), None, Some(second)) + } else { + if let PositionCategory::LengthOrPercentage = category(second) { + if let PositionCategory::HorizontalKeyword = category(third) { + // "bottom 10% right" + Position::new(Some(second), None, Some(first), Some(third)) + } else { + // "right 10px 50%" + Position::new(Some(second), Some(third), Some(first), None) + } + } else { + // "right bottom 10px" + Position::new(None, Some(third), Some(first), Some(second)) + } + } + } + } else { + // Handle 2 value background position + Position::new(Some(first), Some(second), None, None) + } + } +} + +impl ToCss for Keyword { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + Keyword::Right => try!(dest.write_str("right ")), + Keyword::Bottom => try!(dest.write_str("bottom ")), + _ => (), + }; } } @@ -87,17 +211,19 @@ enum PositionCategory { } fn category(p: PositionComponent) -> PositionCategory { - match p { - PositionComponent::Left | - PositionComponent::Right => - PositionCategory::HorizontalKeyword, - PositionComponent::Top | - PositionComponent::Bottom => - PositionCategory::VerticalKeyword, - PositionComponent::Center => - PositionCategory::OtherKeyword, - PositionComponent::LengthOrPercentage(_) => - PositionCategory::LengthOrPercentage, + if let PositionComponent::Keyword(keyword) = p { + match keyword { + Keyword::Left | + Keyword::Right => + PositionCategory::HorizontalKeyword, + Keyword::Top | + Keyword::Bottom => + PositionCategory::VerticalKeyword, + Keyword::Center => + PositionCategory::OtherKeyword, + } + } else { + PositionCategory::LengthOrPercentage } } @@ -107,8 +233,8 @@ impl ToComputedValue for Position { #[inline] fn to_computed_value(&self, context: &Context) -> computed_position::Position { computed_position::Position { - horizontal: self.horizontal.to_computed_value(context), - vertical: self.vertical.to_computed_value(context), + horizontal: self.horiz_position.to_computed_value(context), + vertical: self.vert_position.to_computed_value(context), } } } @@ -116,7 +242,7 @@ impl ToComputedValue for Position { impl HasViewportPercentage for PositionComponent { fn has_viewport_percentage(&self) -> bool { match *self { - PositionComponent::LengthOrPercentage(length) => length.has_viewport_percentage(), + PositionComponent::Length(length) => length.has_viewport_percentage(), _ => false } } @@ -125,16 +251,16 @@ impl HasViewportPercentage for PositionComponent { impl PositionComponent { pub fn parse(input: &mut Parser) -> Result<PositionComponent, ()> { input.try(LengthOrPercentage::parse) - .map(PositionComponent::LengthOrPercentage) + .map(PositionComponent::Length) .or_else(|()| { match try!(input.next()) { Token::Ident(value) => { match_ignore_ascii_case! { value, - "center" => Ok(PositionComponent::Center), - "left" => Ok(PositionComponent::Left), - "right" => Ok(PositionComponent::Right), - "top" => Ok(PositionComponent::Top), - "bottom" => Ok(PositionComponent::Bottom), + "center" => Ok(PositionComponent::Keyword(Keyword::Center)), + "left" => Ok(PositionComponent::Keyword(Keyword::Left)), + "right" => Ok(PositionComponent::Keyword(Keyword::Right)), + "top" => Ok(PositionComponent::Keyword(Keyword::Top)), + "bottom" => Ok(PositionComponent::Keyword(Keyword::Bottom)), _ => Err(()) } }, @@ -145,12 +271,14 @@ impl PositionComponent { #[inline] pub fn to_length_or_percentage(self) -> LengthOrPercentage { match self { - PositionComponent::LengthOrPercentage(value) => value, - PositionComponent::Center => LengthOrPercentage::Percentage(Percentage(0.5)), - PositionComponent::Left | - PositionComponent::Top => LengthOrPercentage::Percentage(Percentage(0.0)), - PositionComponent::Right | - PositionComponent::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)), + PositionComponent::Length(value) => value, + PositionComponent::Keyword(keyword) if keyword == Keyword::Center => + LengthOrPercentage::Percentage(Percentage(0.5)), + PositionComponent::Keyword(keyword) if keyword == Keyword::Left || + keyword == Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)), + PositionComponent::Keyword(keyword) if keyword == Keyword::Right || + keyword == Keyword::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)), + PositionComponent::Keyword(_) => unimplemented!(), // TODO: All keywords are covered but rust forcing me to add this too? } } } |