aboutsummaryrefslogtreecommitdiffstats
path: root/components
diff options
context:
space:
mode:
Diffstat (limited to 'components')
-rw-r--r--components/style/properties/longhand/background.mako.rs6
-rw-r--r--components/style/values/specified/basic_shape.rs12
-rw-r--r--components/style/values/specified/position.rs212
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?
}
}
}