mirror of
https://github.com/servo/servo.git
synced 2025-08-03 20:50:07 +01:00
Implement HorizontalPosition / VerticalPosition
This commit is contained in:
parent
872ec89a9c
commit
a409d41d1d
6 changed files with 513 additions and 181 deletions
|
@ -112,11 +112,16 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
pub fn get_initial_specified_value() -> SpecifiedValue {
|
||||||
use values::specified::Percentage;
|
use values::specified::Percentage;
|
||||||
|
use values::specified::position::{HorizontalPosition, VerticalPosition};
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: None,
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
|
keyword: None,
|
||||||
vert_keyword: None,
|
position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
|
||||||
vert_position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(specified::LengthOrPercentage::Percentage(Percentage(0.0))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,3 +26,19 @@ impl ToCss for Position {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct HorizontalPosition(pub LengthOrPercentage);
|
||||||
|
|
||||||
|
impl ToCss for HorizontalPosition {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
self.0.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct VerticalPosition(pub LengthOrPercentage);
|
||||||
|
|
||||||
|
impl ToCss for VerticalPosition {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
self.0.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ use style_traits::ToCss;
|
||||||
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
||||||
use values::computed::basic_shape as computed_basic_shape;
|
use values::computed::basic_shape as computed_basic_shape;
|
||||||
use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage};
|
use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage};
|
||||||
use values::specified::position::{Keyword, Position};
|
use values::specified::position::{Keyword, Position, HorizontalPosition, VerticalPosition};
|
||||||
use values::specified::url::SpecifiedUrl;
|
use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
/// A shape source, for some reference box
|
/// A shape source, for some reference box
|
||||||
|
@ -313,6 +313,7 @@ fn serialize_basicshape_position<W>(position: &Position, dest: &mut W)
|
||||||
},
|
},
|
||||||
Some(Keyword::Left) | Some(Keyword::Top) | None => pc,
|
Some(Keyword::Left) | Some(Keyword::Top) | None => pc,
|
||||||
Some(Keyword::Right) | Some(Keyword::Bottom) => Percentage(1.0 - pc.0),
|
Some(Keyword::Right) | Some(Keyword::Bottom) => Percentage(1.0 - pc.0),
|
||||||
|
_ => return None,
|
||||||
};
|
};
|
||||||
Some(LengthOrPercentage::Percentage(percent))
|
Some(LengthOrPercentage::Percentage(percent))
|
||||||
}
|
}
|
||||||
|
@ -336,8 +337,8 @@ fn serialize_basicshape_position<W>(position: &Position, dest: &mut W)
|
||||||
replace_with_percent(y).to_css(dest)
|
replace_with_percent(y).to_css(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
match (position.horiz_keyword, position.horiz_position,
|
match (position.horizontal.keyword, position.horizontal.position,
|
||||||
position.vert_keyword, position.vert_position) {
|
position.vertical.keyword, position.vertical.position) {
|
||||||
(Some(hk), None, Some(vk), None) => {
|
(Some(hk), None, Some(vk), None) => {
|
||||||
// two keywords: serialize as two lengths
|
// two keywords: serialize as two lengths
|
||||||
serialize_position_pair(hk.to_length_or_percentage(),
|
serialize_position_pair(hk.to_length_or_percentage(),
|
||||||
|
@ -385,10 +386,14 @@ impl Circle {
|
||||||
} else {
|
} else {
|
||||||
// Defaults to origin
|
// Defaults to origin
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: Some(Keyword::Center),
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: None,
|
keyword: Some(Keyword::Center),
|
||||||
vert_keyword: Some(Keyword::Center),
|
position: None,
|
||||||
vert_position: None,
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: Some(Keyword::Center),
|
||||||
|
position: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(Circle {
|
Ok(Circle {
|
||||||
|
@ -462,10 +467,14 @@ impl Ellipse {
|
||||||
} else {
|
} else {
|
||||||
// Defaults to origin
|
// Defaults to origin
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: Some(Keyword::Center),
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: None,
|
keyword: Some(Keyword::Center),
|
||||||
vert_keyword: Some(Keyword::Center),
|
position: None,
|
||||||
vert_position: None,
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: Some(Keyword::Center),
|
||||||
|
position: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(Ellipse {
|
Ok(Ellipse {
|
||||||
|
|
|
@ -21,31 +21,29 @@ use values::specified::{LengthOrPercentage, Percentage};
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
pub struct Position {
|
pub struct Position {
|
||||||
pub horiz_keyword: Option<Keyword>,
|
pub horizontal: HorizontalPosition,
|
||||||
pub horiz_position: Option<LengthOrPercentage>,
|
pub vertical: VerticalPosition,
|
||||||
pub vert_keyword: Option<Keyword>,
|
|
||||||
pub vert_position: Option<LengthOrPercentage>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Position {
|
impl ToCss for Position {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
let mut space_at_last = false;
|
let mut space_present = false;
|
||||||
if let Some(horiz_key) = self.horiz_keyword {
|
if let Some(horiz_key) = self.horizontal.keyword {
|
||||||
try!(horiz_key.to_css(dest));
|
try!(horiz_key.to_css(dest));
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
space_at_last = true;
|
space_present = true;
|
||||||
};
|
};
|
||||||
if let Some(horiz_pos) = self.horiz_position {
|
if let Some(horiz_pos) = self.horizontal.position {
|
||||||
try!(horiz_pos.to_css(dest));
|
try!(horiz_pos.to_css(dest));
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
space_at_last = true;
|
space_present = true;
|
||||||
};
|
};
|
||||||
if let Some(vert_key) = self.vert_keyword {
|
if let Some(vert_key) = self.vertical.keyword {
|
||||||
try!(vert_key.to_css(dest));
|
try!(vert_key.to_css(dest));
|
||||||
space_at_last = false;
|
space_present = false;
|
||||||
};
|
};
|
||||||
if let Some(vert_pos) = self.vert_position {
|
if let Some(vert_pos) = self.vertical.position {
|
||||||
if space_at_last == false {
|
if space_present == false {
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
}
|
}
|
||||||
try!(vert_pos.to_css(dest));
|
try!(vert_pos.to_css(dest));
|
||||||
|
@ -56,38 +54,10 @@ impl ToCss for Position {
|
||||||
|
|
||||||
impl HasViewportPercentage for Position {
|
impl HasViewportPercentage for Position {
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
let horiz_viewport = if let Some(horiz_pos) = self.horiz_position {
|
self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
|
||||||
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
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub enum Keyword {
|
|
||||||
Center,
|
|
||||||
Left,
|
|
||||||
Right,
|
|
||||||
Top,
|
|
||||||
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 {
|
impl Position {
|
||||||
pub fn new(mut first_position: Option<PositionComponent>, mut second_position: Option<PositionComponent>,
|
pub fn new(mut first_position: Option<PositionComponent>, mut second_position: Option<PositionComponent>,
|
||||||
first_keyword: Option<PositionComponent>, second_keyword: Option<PositionComponent>)
|
first_keyword: Option<PositionComponent>, second_keyword: Option<PositionComponent>)
|
||||||
|
@ -117,6 +87,12 @@ impl Position {
|
||||||
(PositionCategory::LengthOrPercentage, PositionCategory::HorizontalKeyword) |
|
(PositionCategory::LengthOrPercentage, PositionCategory::HorizontalKeyword) |
|
||||||
(PositionCategory::VerticalKeyword, PositionCategory::LengthOrPercentage) => return Err(()),
|
(PositionCategory::VerticalKeyword, PositionCategory::LengthOrPercentage) => return Err(()),
|
||||||
|
|
||||||
|
// FIXME(canaltinova): Allow logical keywords for Position. They are not in current spec yet.
|
||||||
|
(PositionCategory::HorizontalLogicalKeyword, _) |
|
||||||
|
(PositionCategory::VerticalLogicalKeyword, _) |
|
||||||
|
(_, PositionCategory::HorizontalLogicalKeyword) |
|
||||||
|
(_, PositionCategory::VerticalLogicalKeyword) => return Err(()),
|
||||||
|
|
||||||
// Swap if both are keywords and vertical precedes horizontal.
|
// Swap if both are keywords and vertical precedes horizontal.
|
||||||
(PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) |
|
(PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) |
|
||||||
(PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) |
|
(PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) |
|
||||||
|
@ -163,19 +139,27 @@ impl Position {
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(Position {
|
Ok(Position {
|
||||||
horiz_keyword: horizontal_keyword,
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: first_position,
|
keyword: horizontal_keyword,
|
||||||
vert_keyword: vertical_keyword,
|
position: first_position,
|
||||||
vert_position: second_position,
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: vertical_keyword,
|
||||||
|
position: second_position,
|
||||||
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn center() -> Position {
|
pub fn center() -> Position {
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: Some(Keyword::Center),
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: None,
|
keyword: Some(Keyword::Center),
|
||||||
vert_keyword: Some(Keyword::Center),
|
position: None,
|
||||||
vert_position: None,
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: Some(Keyword::Center),
|
||||||
|
position: None,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,46 +214,342 @@ impl Parse for Position {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for Position {
|
||||||
|
type ComputedValue = computed_position::Position;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> computed_position::Position {
|
||||||
|
computed_position::Position {
|
||||||
|
horizontal: self.horizontal.to_computed_value(context).0,
|
||||||
|
vertical: self.vertical.to_computed_value(context).0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &computed_position::Position) -> Position {
|
||||||
|
Position {
|
||||||
|
horizontal: HorizontalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(ToComputedValue::from_computed_value(&computed.horizontal)),
|
||||||
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(ToComputedValue::from_computed_value(&computed.vertical)),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct HorizontalPosition {
|
||||||
|
pub keyword: Option<Keyword>,
|
||||||
|
pub position: Option<LengthOrPercentage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasViewportPercentage for HorizontalPosition {
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
if let Some(pos) = self.position {
|
||||||
|
pos.has_viewport_percentage()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for HorizontalPosition {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
let mut keyword_present = false;
|
||||||
|
if let Some(keyword) = self.keyword {
|
||||||
|
try!(keyword.to_css(dest));
|
||||||
|
keyword_present = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(position) = self.position {
|
||||||
|
if keyword_present {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
}
|
||||||
|
try!(position.to_css(dest));
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for HorizontalPosition {
|
||||||
|
#[inline]
|
||||||
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
let first = try!(PositionComponent::parse(context, input));
|
||||||
|
let second = input.try(|i| PositionComponent::parse(context, i)).ok();
|
||||||
|
|
||||||
|
let (keyword, position) = if let PositionCategory::LengthOrPercentage = category(first) {
|
||||||
|
// "length keyword?"
|
||||||
|
(second, Some(first))
|
||||||
|
} else {
|
||||||
|
// "keyword length?"
|
||||||
|
(Some(first), second)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unwrapping and checking keyword.
|
||||||
|
let keyword = match keyword {
|
||||||
|
Some(PositionComponent::Keyword(key)) => {
|
||||||
|
match category(keyword.unwrap()) {
|
||||||
|
PositionCategory::VerticalKeyword |
|
||||||
|
PositionCategory::VerticalLogicalKeyword => return Err(()),
|
||||||
|
_ => Some(key),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(_) => return Err(()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unwrapping and checking position.
|
||||||
|
let position = match position {
|
||||||
|
Some(PositionComponent::Length(pos)) => {
|
||||||
|
// "center <length>" is not allowed
|
||||||
|
if let Some(Keyword::Center) = keyword {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
Some(pos)
|
||||||
|
},
|
||||||
|
Some(_) => return Err(()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(HorizontalPosition {
|
||||||
|
keyword: keyword,
|
||||||
|
position: position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for HorizontalPosition {
|
||||||
|
type ComputedValue = computed_position::HorizontalPosition;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> computed_position::HorizontalPosition {
|
||||||
|
let keyword = self.keyword.unwrap_or(Keyword::Left);
|
||||||
|
|
||||||
|
// Construct horizontal computed LengthOrPercentage
|
||||||
|
let horizontal = match keyword {
|
||||||
|
// FIXME(canaltinova): Support logical keywords.
|
||||||
|
Keyword::Right | Keyword::XEnd => {
|
||||||
|
if let Some(x) = self.position {
|
||||||
|
let (length, percentage) = match x {
|
||||||
|
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
||||||
|
LengthOrPercentage::Length(y) => (-y.to_computed_value(context), Some(1.0)),
|
||||||
|
_ => (Au(0), None),
|
||||||
|
};
|
||||||
|
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
||||||
|
length: length,
|
||||||
|
percentage: percentage
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ComputedLengthOrPercentage::Percentage(1.0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Keyword::Center => {
|
||||||
|
keyword.to_length_or_percentage().to_computed_value(context)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let horiz = self.position
|
||||||
|
.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.0)));
|
||||||
|
horiz.to_computed_value(context)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
computed_position::HorizontalPosition(horizontal)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &computed_position::HorizontalPosition) -> HorizontalPosition {
|
||||||
|
HorizontalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(ToComputedValue::from_computed_value(&computed.0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Copy)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct VerticalPosition {
|
||||||
|
pub keyword: Option<Keyword>,
|
||||||
|
pub position: Option<LengthOrPercentage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl HasViewportPercentage for VerticalPosition {
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
if let Some(pos) = self.position {
|
||||||
|
pos.has_viewport_percentage()
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToCss for VerticalPosition {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
let mut keyword_present = false;
|
||||||
|
if let Some(keyword) = self.keyword {
|
||||||
|
try!(keyword.to_css(dest));
|
||||||
|
keyword_present = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(position) = self.position {
|
||||||
|
if keyword_present {
|
||||||
|
try!(dest.write_str(" "));
|
||||||
|
}
|
||||||
|
try!(position.to_css(dest));
|
||||||
|
};
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for VerticalPosition {
|
||||||
|
#[inline]
|
||||||
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
let first = try!(PositionComponent::parse(context, input));
|
||||||
|
let second = input.try(|i| PositionComponent::parse(context, i)).ok();
|
||||||
|
|
||||||
|
let (keyword, position) = if let PositionCategory::LengthOrPercentage = category(first) {
|
||||||
|
// "length keyword?"
|
||||||
|
(second, Some(first))
|
||||||
|
} else {
|
||||||
|
// "keyword length?"
|
||||||
|
(Some(first), second)
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unwrapping and checking keyword.
|
||||||
|
let keyword = match keyword {
|
||||||
|
Some(PositionComponent::Keyword(key)) => {
|
||||||
|
match category(keyword.unwrap()) {
|
||||||
|
PositionCategory::HorizontalKeyword |
|
||||||
|
PositionCategory::HorizontalLogicalKeyword => return Err(()),
|
||||||
|
_ => Some(key),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Some(_) => return Err(()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Unwrapping and checking position.
|
||||||
|
let position = match position {
|
||||||
|
Some(PositionComponent::Length(pos)) => {
|
||||||
|
// "center <length>" is not allowed
|
||||||
|
if let Some(Keyword::Center) = keyword {
|
||||||
|
return Err(());
|
||||||
|
}
|
||||||
|
Some(pos)
|
||||||
|
},
|
||||||
|
Some(_) => return Err(()),
|
||||||
|
None => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(VerticalPosition {
|
||||||
|
keyword: keyword,
|
||||||
|
position: position,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for VerticalPosition {
|
||||||
|
type ComputedValue = computed_position::VerticalPosition;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> computed_position::VerticalPosition {
|
||||||
|
let keyword = self.keyword.unwrap_or(Keyword::Left);
|
||||||
|
|
||||||
|
// Construct vertical computed LengthOrPercentage
|
||||||
|
let vertical = match keyword {
|
||||||
|
// FIXME(canaltinova): Support logical keywords.
|
||||||
|
Keyword::Bottom | Keyword::YEnd => {
|
||||||
|
if let Some(x) = self.position {
|
||||||
|
let (length, percentage) = match x {
|
||||||
|
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
||||||
|
LengthOrPercentage::Length(y) => (-y.to_computed_value(context), Some(1.0)),
|
||||||
|
_ => (Au(0), None),
|
||||||
|
};
|
||||||
|
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
||||||
|
length: length,
|
||||||
|
percentage: percentage
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
ComputedLengthOrPercentage::Percentage(1.0)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Keyword::Center => {
|
||||||
|
keyword.to_length_or_percentage().to_computed_value(context)
|
||||||
|
},
|
||||||
|
_ => {
|
||||||
|
let vert = self.position
|
||||||
|
.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.0)));
|
||||||
|
vert.to_computed_value(context)
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
computed_position::VerticalPosition(vertical)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &computed_position::VerticalPosition) -> VerticalPosition {
|
||||||
|
VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(ToComputedValue::from_computed_value(&computed.0)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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 Keyword {
|
impl Keyword {
|
||||||
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
|
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
|
||||||
match self {
|
match self {
|
||||||
Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
|
Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
|
||||||
Keyword::Left | Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)),
|
Keyword::Left | Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)),
|
||||||
Keyword::Right | Keyword::Bottom => LengthOrPercentage::Percentage(Percentage(1.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)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Keyword {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
Keyword::Center => try!(dest.write_str("center")),
|
|
||||||
Keyword::Left => try!(dest.write_str("left")),
|
|
||||||
Keyword::Right => try!(dest.write_str("right")),
|
|
||||||
Keyword::Top => try!(dest.write_str("top")),
|
|
||||||
Keyword::Bottom => try!(dest.write_str("bottom")),
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collapse `Position` into a few categories to simplify the above `match` expression.
|
// Collapse `Position` into a few categories to simplify the above `match` expression.
|
||||||
enum PositionCategory {
|
enum PositionCategory {
|
||||||
HorizontalKeyword,
|
HorizontalKeyword,
|
||||||
VerticalKeyword,
|
VerticalKeyword,
|
||||||
|
HorizontalLogicalKeyword,
|
||||||
|
VerticalLogicalKeyword,
|
||||||
OtherKeyword,
|
OtherKeyword,
|
||||||
LengthOrPercentage,
|
LengthOrPercentage,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
|
||||||
|
#[derive(Clone, PartialEq, Copy)]
|
||||||
|
pub enum PositionComponent {
|
||||||
|
Length(LengthOrPercentage),
|
||||||
|
Keyword(Keyword),
|
||||||
|
}
|
||||||
|
|
||||||
fn category(p: PositionComponent) -> PositionCategory {
|
fn category(p: PositionComponent) -> PositionCategory {
|
||||||
if let PositionComponent::Keyword(keyword) = p {
|
if let PositionComponent::Keyword(keyword) = p {
|
||||||
match keyword {
|
match keyword {
|
||||||
Keyword::Left |
|
Keyword::Left | Keyword::Right =>
|
||||||
Keyword::Right =>
|
|
||||||
PositionCategory::HorizontalKeyword,
|
PositionCategory::HorizontalKeyword,
|
||||||
Keyword::Top |
|
Keyword::Top | Keyword::Bottom =>
|
||||||
Keyword::Bottom =>
|
|
||||||
PositionCategory::VerticalKeyword,
|
PositionCategory::VerticalKeyword,
|
||||||
|
Keyword::XStart | Keyword::XEnd =>
|
||||||
|
PositionCategory::HorizontalLogicalKeyword,
|
||||||
|
Keyword::YStart | Keyword::YEnd =>
|
||||||
|
PositionCategory::VerticalLogicalKeyword,
|
||||||
Keyword::Center =>
|
Keyword::Center =>
|
||||||
PositionCategory::OtherKeyword,
|
PositionCategory::OtherKeyword,
|
||||||
}
|
}
|
||||||
|
@ -278,83 +558,6 @@ fn category(p: PositionComponent) -> PositionCategory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToComputedValue for Position {
|
|
||||||
type ComputedValue = computed_position::Position;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_position::Position {
|
|
||||||
let horiz_keyword = self.horiz_keyword.unwrap_or(Keyword::Left);
|
|
||||||
let vert_keyword = self.vert_keyword.unwrap_or(Keyword::Top);
|
|
||||||
|
|
||||||
// Construct horizontal computed LengthOrPercentage
|
|
||||||
let horizontal = match horiz_keyword {
|
|
||||||
Keyword::Right => {
|
|
||||||
if let Some(x) = self.horiz_position {
|
|
||||||
let (length, percentage) = match x {
|
|
||||||
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
|
||||||
LengthOrPercentage::Length(y) => (-y.to_computed_value(context), Some(1.0)),
|
|
||||||
_ => (Au(0), None),
|
|
||||||
};
|
|
||||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
|
||||||
length: length,
|
|
||||||
percentage: percentage
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ComputedLengthOrPercentage::Percentage(1.0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Keyword::Center => {
|
|
||||||
horiz_keyword.to_length_or_percentage().to_computed_value(context)
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let horiz = self.horiz_position.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.0)));
|
|
||||||
horiz.to_computed_value(context)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Construct vertical computed LengthOrPercentage
|
|
||||||
let vertical = match vert_keyword {
|
|
||||||
Keyword::Bottom => {
|
|
||||||
if let Some(x) = self.vert_position {
|
|
||||||
let (length, percentage) = match x {
|
|
||||||
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
|
||||||
LengthOrPercentage::Length(y) => (-y.to_computed_value(context), Some(1.0)),
|
|
||||||
_ => (Au(0), None),
|
|
||||||
};
|
|
||||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
|
||||||
length: length,
|
|
||||||
percentage: percentage
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ComputedLengthOrPercentage::Percentage(1.0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Keyword::Center => {
|
|
||||||
vert_keyword.to_length_or_percentage().to_computed_value(context)
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let vert = self.vert_position.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.0)));
|
|
||||||
vert.to_computed_value(context)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
computed_position::Position {
|
|
||||||
horizontal: horizontal,
|
|
||||||
vertical: vertical,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &computed_position::Position) -> Position {
|
|
||||||
Position {
|
|
||||||
horiz_keyword: None,
|
|
||||||
horiz_position: Some(ToComputedValue::from_computed_value(&computed.horizontal)),
|
|
||||||
vert_keyword: None,
|
|
||||||
vert_position: Some(ToComputedValue::from_computed_value(&computed.vertical)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasViewportPercentage for PositionComponent {
|
impl HasViewportPercentage for PositionComponent {
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -387,6 +590,10 @@ impl Parse for PositionComponent {
|
||||||
"right" => Ok(PositionComponent::Keyword(Keyword::Right)),
|
"right" => Ok(PositionComponent::Keyword(Keyword::Right)),
|
||||||
"top" => Ok(PositionComponent::Keyword(Keyword::Top)),
|
"top" => Ok(PositionComponent::Keyword(Keyword::Top)),
|
||||||
"bottom" => Ok(PositionComponent::Keyword(Keyword::Bottom)),
|
"bottom" => Ok(PositionComponent::Keyword(Keyword::Bottom)),
|
||||||
|
"x-start" => Ok(PositionComponent::Keyword(Keyword::XStart)),
|
||||||
|
"x-end" => Ok(PositionComponent::Keyword(Keyword::XEnd)),
|
||||||
|
"y-start" => Ok(PositionComponent::Keyword(Keyword::YStart)),
|
||||||
|
"y-end" => Ok(PositionComponent::Keyword(Keyword::YEnd)),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -61,4 +61,79 @@ fn test_position() {
|
||||||
assert!(parse(Position::parse, "top 10px bottom").is_err());
|
assert!(parse(Position::parse, "top 10px bottom").is_err());
|
||||||
assert!(parse(Position::parse, "top 10px bottom 15%").is_err());
|
assert!(parse(Position::parse, "top 10px bottom 15%").is_err());
|
||||||
|
|
||||||
|
// Logical keywords are not supported in Position yet
|
||||||
|
assert!(parse(Position::parse, "x-start").is_err());
|
||||||
|
assert!(parse(Position::parse, "y-end").is_err());
|
||||||
|
assert!(parse(Position::parse, "x-start y-end").is_err());
|
||||||
|
assert!(parse(Position::parse, "x-end 10px").is_err());
|
||||||
|
assert!(parse(Position::parse, "y-start 20px").is_err());
|
||||||
|
assert!(parse(Position::parse, "x-start bottom 10%").is_err());
|
||||||
|
assert!(parse(Position::parse, "left y-start 10%").is_err());
|
||||||
|
assert!(parse(Position::parse, "x-start 20px y-end 10%").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_horizontal_position() {
|
||||||
|
// One value serializations.
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "20px", "20px");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "25%", "25%");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "center", "center");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "left", "left");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "right", "right");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "x-start", "x-start");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "x-end", "x-end");
|
||||||
|
|
||||||
|
// Two value serializations.
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "right 10px", "right 10px");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "10px left", "left 10px");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "x-end 20%", "x-end 20%");
|
||||||
|
assert_roundtrip_with_context!(HorizontalPosition::parse, "20px x-start", "x-start 20px");
|
||||||
|
|
||||||
|
// Invalid horizontal positions.
|
||||||
|
assert!(parse(HorizontalPosition::parse, "top").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "bottom").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "y-start").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "y-end").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "20px y-end").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "y-end 20px ").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "bottom 20px").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "20px top").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "left center").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "bottom top").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "left top").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "left right").is_err());
|
||||||
|
assert!(parse(HorizontalPosition::parse, "20px 30px").is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_vertical_position() {
|
||||||
|
// One value serializations.
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "20px", "20px");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "25%", "25%");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "center", "center");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "top", "top");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "bottom", "bottom");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "y-start", "y-start");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "y-end", "y-end");
|
||||||
|
|
||||||
|
// Two value serializations.
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "bottom 10px", "bottom 10px");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "10px top", "top 10px");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "y-end 20%", "y-end 20%");
|
||||||
|
assert_roundtrip_with_context!(VerticalPosition::parse, "20px y-start", "y-start 20px");
|
||||||
|
|
||||||
|
// Invalid vertical positions.
|
||||||
|
assert!(parse(VerticalPosition::parse, "left").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "right").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "x-start").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "x-end").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "20px x-end").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "x-end 20px ").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "left 20px").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "20px right").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "left center").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "bottom top").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "left top").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "left right").is_err());
|
||||||
|
assert!(parse(VerticalPosition::parse, "20px 30px").is_err());
|
||||||
}
|
}
|
||||||
|
|
|
@ -692,7 +692,7 @@ mod shorthand_serialization {
|
||||||
use style::properties::longhands::background_repeat as repeat;
|
use style::properties::longhands::background_repeat as repeat;
|
||||||
use style::properties::longhands::background_size as size;
|
use style::properties::longhands::background_size as size;
|
||||||
use style::values::specified::Image;
|
use style::values::specified::Image;
|
||||||
use style::values::specified::position::Position;
|
use style::values::specified::position::{HorizontalPosition, Position, VerticalPosition};
|
||||||
use super::*;
|
use super::*;
|
||||||
macro_rules! single_vec_value_typedef {
|
macro_rules! single_vec_value_typedef {
|
||||||
($name:ident, $path:expr) => {
|
($name:ident, $path:expr) => {
|
||||||
|
@ -733,10 +733,14 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
let position = single_vec_value_typedef!(position,
|
let position = single_vec_value_typedef!(position,
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: None,
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
keyword: None,
|
||||||
vert_keyword: None,
|
position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
||||||
vert_position: Some(LengthOrPercentage::Length(Length::from_px(4f32)))
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(LengthOrPercentage::Length(Length::from_px(4f32))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -787,10 +791,14 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
let position = single_vec_value_typedef!(position,
|
let position = single_vec_value_typedef!(position,
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: None,
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
keyword: None,
|
||||||
vert_keyword: None,
|
position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
||||||
vert_position: Some(LengthOrPercentage::Length(Length::from_px(4f32)))
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(LengthOrPercentage::Length(Length::from_px(4f32))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -840,10 +848,14 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
let position = single_vec_value_typedef!(position,
|
let position = single_vec_value_typedef!(position,
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: None,
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: Some(LengthOrPercentage::Length(Length::from_px(0f32))),
|
keyword: None,
|
||||||
vert_keyword: None,
|
position: Some(LengthOrPercentage::Length(Length::from_px(0f32))),
|
||||||
vert_position: Some(LengthOrPercentage::Length(Length::from_px(0f32)))
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(LengthOrPercentage::Length(Length::from_px(0f32))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -881,7 +893,7 @@ mod shorthand_serialization {
|
||||||
use style::properties::longhands::mask_repeat as repeat;
|
use style::properties::longhands::mask_repeat as repeat;
|
||||||
use style::properties::longhands::mask_size as size;
|
use style::properties::longhands::mask_size as size;
|
||||||
use style::values::specified::Image;
|
use style::values::specified::Image;
|
||||||
use style::values::specified::position::Position;
|
use style::values::specified::position::{HorizontalPosition, Position, VerticalPosition};
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
macro_rules! single_vec_value_typedef {
|
macro_rules! single_vec_value_typedef {
|
||||||
|
@ -918,10 +930,14 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
let position = single_vec_value_typedef!(position,
|
let position = single_vec_value_typedef!(position,
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: None,
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
keyword: None,
|
||||||
vert_keyword: None,
|
position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
||||||
vert_position: Some(LengthOrPercentage::Length(Length::from_px(4f32)))
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(LengthOrPercentage::Length(Length::from_px(4f32))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -968,10 +984,14 @@ mod shorthand_serialization {
|
||||||
|
|
||||||
let position = single_vec_value_typedef!(position,
|
let position = single_vec_value_typedef!(position,
|
||||||
Position {
|
Position {
|
||||||
horiz_keyword: None,
|
horizontal: HorizontalPosition {
|
||||||
horiz_position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
keyword: None,
|
||||||
vert_keyword: None,
|
position: Some(LengthOrPercentage::Length(Length::from_px(7f32))),
|
||||||
vert_position: Some(LengthOrPercentage::Length(Length::from_px(4f32)))
|
},
|
||||||
|
vertical: VerticalPosition {
|
||||||
|
keyword: None,
|
||||||
|
position: Some(LengthOrPercentage::Length(Length::from_px(4f32))),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue