Cleanup position and make use of generic Position for its users

This commit is contained in:
Ravi Shankar 2017-04-15 22:04:13 +05:30
parent 3f53fb148d
commit 61a17993eb
10 changed files with 277 additions and 677 deletions

View file

@ -273,8 +273,8 @@ impl nsStyleImage {
}, },
} }
unsafe { unsafe {
(*gecko_gradient).mBgPosX.set(position.horizontal); (*gecko_gradient).mBgPosX.set(position.horizontal.0);
(*gecko_gradient).mBgPosY.set(position.vertical); (*gecko_gradient).mBgPosY.set(position.vertical.0);
} }
gecko_gradient gecko_gradient
@ -330,6 +330,7 @@ pub mod basic_shape {
use values::computed::position; use values::computed::position;
use values::generics::BorderRadiusSize as GenericBorderRadiusSize; use values::generics::BorderRadiusSize as GenericBorderRadiusSize;
use values::generics::basic_shape::FillRule; use values::generics::basic_shape::FillRule;
use values::generics::position::{HorizontalPosition, VerticalPosition};
// using Borrow so that we can have a non-moving .into() // using Borrow so that we can have a non-moving .into()
impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape { impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape {
@ -440,8 +441,8 @@ pub mod basic_shape {
impl From<position::Position> for structs::Position { impl From<position::Position> for structs::Position {
fn from(other: position::Position) -> Self { fn from(other: position::Position) -> Self {
structs::Position { structs::Position {
mXPosition: other.horizontal.into(), mXPosition: other.horizontal.0.into(),
mYPosition: other.vertical.into() mYPosition: other.vertical.0.into()
} }
} }
} }
@ -458,8 +459,8 @@ pub mod basic_shape {
fn from(other: T) -> Self { fn from(other: T) -> Self {
let other = other.borrow(); let other = other.borrow();
position::Position { position::Position {
horizontal: other.mXPosition.into(), horizontal: HorizontalPosition(other.mXPosition.into()),
vertical: other.mYPosition.into(), vertical: VerticalPosition(other.mYPosition.into()),
} }
} }
} }

View file

@ -376,17 +376,17 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
<%def name="impl_position(ident, gecko_ffi_name, need_clone=False)"> <%def name="impl_position(ident, gecko_ffi_name, need_clone=False)">
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.into()")} ${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.0.into()")}
${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.into()")} ${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.0.into()")}
} }
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call> <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
% if need_clone: % if need_clone:
#[allow(non_snake_case)] #[allow(non_snake_case)]
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
use values::computed::Position; use values::generics::position::{HorizontalPosition, Position, VerticalPosition};
Position { Position {
horizontal: self.gecko.${gecko_ffi_name}.mXPosition.into(), horizontal: HorizontalPosition(self.gecko.${gecko_ffi_name}.mXPosition.into()),
vertical: self.gecko.${gecko_ffi_name}.mYPosition.into(), vertical: VerticalPosition(self.gecko.${gecko_ffi_name}.mYPosition.into()),
} }
} }
% endif % endif
@ -1947,8 +1947,8 @@ fn static_assert() {
for (gecko, servo) in self.gecko.mScrollSnapCoordinate for (gecko, servo) in self.gecko.mScrollSnapCoordinate
.iter_mut() .iter_mut()
.zip(v.0.iter()) { .zip(v.0.iter()) {
gecko.mXPosition = servo.horizontal.into(); gecko.mXPosition = servo.horizontal.0.into();
gecko.mYPosition = servo.vertical.into(); gecko.mYPosition = servo.vertical.0.into();
} }
} }
@ -2600,7 +2600,7 @@ fn static_assert() {
pub fn clone_${shorthand}_position_${orientation[0]}(&self) pub fn clone_${shorthand}_position_${orientation[0]}(&self)
-> longhands::${shorthand}_position_${orientation[0]}::computed_value::T { -> longhands::${shorthand}_position_${orientation[0]}::computed_value::T {
use values::computed::position::${orientation[1]}Position; use values::generics::position::${orientation[1]}Position;
longhands::${shorthand}_position_${orientation[0]}::computed_value::T( longhands::${shorthand}_position_${orientation[0]}::computed_value::T(
self.gecko.${image_layers_field}.mLayers.iter() self.gecko.${image_layers_field}.mLayers.iter()
.take(self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count as usize) .take(self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count as usize)

View file

@ -36,9 +36,9 @@ use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone
use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone}; use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone};
use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage}; use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
use values::computed::{MaxLength, MinLength}; use values::computed::{MaxLength, MinLength};
use values::computed::position::{HorizontalPosition, Position, VerticalPosition}; use values::computed::position::{HorizontalPosition, VerticalPosition};
use values::computed::ToComputedValue; use values::computed::ToComputedValue;
use values::generics::position as generic_position;
/// A given transition property, that is either `All`, or an animatable /// A given transition property, that is either `All`, or an animatable
@ -957,23 +957,24 @@ impl Interpolate for FontWeight {
} }
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list /// https://drafts.csswg.org/css-transitions/#animtype-simple-list
impl Interpolate for Position { impl<H: Interpolate, V: Interpolate> Interpolate for generic_position::Position<H, V> {
#[inline] #[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
Ok(Position { Ok(generic_position::Position {
horizontal: try!(self.horizontal.interpolate(&other.horizontal, progress)), horizontal: try!(self.horizontal.interpolate(&other.horizontal, progress)),
vertical: try!(self.vertical.interpolate(&other.vertical, progress)), vertical: try!(self.vertical.interpolate(&other.vertical, progress)),
}) })
} }
} }
impl RepeatableListInterpolate for Position {} impl<H, V> RepeatableListInterpolate for generic_position::Position<H, V>
where H: RepeatableListInterpolate, V: RepeatableListInterpolate {}
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list /// https://drafts.csswg.org/css-transitions/#animtype-simple-list
impl Interpolate for HorizontalPosition { impl Interpolate for HorizontalPosition {
#[inline] #[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
Ok(HorizontalPosition(try!(self.0.interpolate(&other.0, progress)))) self.0.interpolate(&other.0, progress).map(generic_position::HorizontalPosition)
} }
} }
@ -983,7 +984,7 @@ impl RepeatableListInterpolate for HorizontalPosition {}
impl Interpolate for VerticalPosition { impl Interpolate for VerticalPosition {
#[inline] #[inline]
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
Ok(VerticalPosition(try!(self.0.interpolate(&other.0, progress)))) self.0.interpolate(&other.0, progress).map(generic_position::VerticalPosition)
} }
} }
@ -2607,7 +2608,9 @@ impl ComputeDistance for FontWeight {
} }
} }
impl ComputeDistance for Position { impl<H, V> ComputeDistance for generic_position::Position<H, V>
where H: ComputeDistance, V: ComputeDistance
{
#[inline] #[inline]
fn compute_distance(&self, other: &Self) -> Result<f64, ()> { fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
self.compute_squared_distance(other).map(|sd| sd.sqrt()) self.compute_squared_distance(other).map(|sd| sd.sqrt())

View file

@ -111,26 +111,27 @@ ${helpers.predefined_type("background-color", "CSSColor",
#[inline] #[inline]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
use values::computed::position::HorizontalPosition; use values::generics::position::HorizontalPosition;
HorizontalPosition(computed::LengthOrPercentage::Percentage(0.0)) HorizontalPosition(computed::LengthOrPercentage::Percentage(0.0))
} }
#[inline] #[inline]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn get_initial_specified_value() -> SpecifiedValue { pub fn get_initial_specified_value() -> SpecifiedValue {
use values::specified::position::Keyword; use values::generics::position::{HorizontalPosition, Keyword, PositionValue};
HorizontalPosition { HorizontalPosition(PositionValue {
keyword: Some(Keyword::Left), keyword: Some(Keyword::Left),
position: None, position: None,
} })
} }
#[inline] #[inline]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn get_initial_position_value() -> SpecifiedValue { pub fn get_initial_position_value() -> SpecifiedValue {
use values::generics::position::{HorizontalPosition, PositionValue};
use values::specified::{LengthOrPercentage, Percentage}; use values::specified::{LengthOrPercentage, Percentage};
HorizontalPosition { HorizontalPosition(PositionValue {
keyword: None, keyword: None,
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))), position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
} })
} }
#[allow(missing_docs)] #[allow(missing_docs)]
@ -162,26 +163,27 @@ ${helpers.predefined_type("background-color", "CSSColor",
#[inline] #[inline]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn get_initial_value() -> computed_value::T { pub fn get_initial_value() -> computed_value::T {
use values::computed::position::VerticalPosition; use values::generics::position::VerticalPosition;
VerticalPosition(computed::LengthOrPercentage::Percentage(0.0)) VerticalPosition(computed::LengthOrPercentage::Percentage(0.0))
} }
#[inline] #[inline]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn get_initial_specified_value() -> SpecifiedValue { pub fn get_initial_specified_value() -> SpecifiedValue {
use values::specified::position::Keyword; use values::generics::position::{Keyword, PositionValue, VerticalPosition};
VerticalPosition { VerticalPosition(PositionValue {
keyword: Some(Keyword::Top), keyword: Some(Keyword::Top),
position: None, position: None,
} })
} }
#[inline] #[inline]
#[allow(missing_docs)] #[allow(missing_docs)]
pub fn get_initial_position_value() -> SpecifiedValue { pub fn get_initial_position_value() -> SpecifiedValue {
use values::generics::position::{PositionValue, VerticalPosition};
use values::specified::{LengthOrPercentage, Percentage}; use values::specified::{LengthOrPercentage, Percentage};
VerticalPosition { VerticalPosition(PositionValue {
keyword: None, keyword: None,
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))), position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
} })
} }
#[inline] #[inline]

View file

@ -1113,7 +1113,6 @@ ${helpers.predefined_type("scroll-snap-coordinate",
delegate_animate=True)} delegate_animate=True)}
<%helpers:longhand name="transform" extra_prefixes="webkit" <%helpers:longhand name="transform" extra_prefixes="webkit"
animation_value_type="ComputedValue" animation_value_type="ComputedValue"
flags="CREATES_STACKING_CONTEXT FIXPOS_CB" flags="CREATES_STACKING_CONTEXT FIXPOS_CB"
@ -2096,83 +2095,13 @@ ${helpers.predefined_type("perspective",
flags="CREATES_STACKING_CONTEXT FIXPOS_CB", flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
animation_value_type="ComputedValue")} animation_value_type="ComputedValue")}
<%helpers:longhand name="perspective-origin" boxed="True" ${helpers.predefined_type("perspective-origin",
animation_value_type="ComputedValue" "position::OriginPosition",
extra_prefixes="moz webkit" "computed::position::OriginPosition::center()",
spec="https://drafts.csswg.org/css-transforms/#perspective-origin-property"> boxed="True",
use std::fmt; extra_prefixes="moz webkit",
use style_traits::ToCss; spec="https://drafts.csswg.org/css-transforms/#perspective-origin-property",
use values::HasViewportPercentage; animation_value_type="ComputedValue")}
use values::specified::{LengthOrPercentage, Percentage};
pub mod computed_value {
use properties::animated_properties::Interpolate;
use values::computed::LengthOrPercentage;
use values::computed::Position;
pub type T = Position;
}
impl HasViewportPercentage for SpecifiedValue {
fn has_viewport_percentage(&self) -> bool {
self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
}
}
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
pub struct SpecifiedValue {
horizontal: LengthOrPercentage,
vertical: LengthOrPercentage,
}
impl ToCss for SpecifiedValue {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
try!(self.horizontal.to_css(dest));
try!(dest.write_str(" "));
self.vertical.to_css(dest)
}
}
#[inline]
pub fn get_initial_value() -> computed_value::T {
computed_value::T {
horizontal: computed::LengthOrPercentage::Percentage(0.5),
vertical: computed::LengthOrPercentage::Percentage(0.5),
}
}
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
let result = try!(super::parse_origin(context, input));
match result.depth {
Some(_) => Err(()),
None => Ok(SpecifiedValue {
horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))),
vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))),
})
}
}
impl ToComputedValue for SpecifiedValue {
type ComputedValue = computed_value::T;
#[inline]
fn to_computed_value(&self, context: &Context) -> computed_value::T {
computed_value::T {
horizontal: self.horizontal.to_computed_value(context),
vertical: self.vertical.to_computed_value(context),
}
}
#[inline]
fn from_computed_value(computed: &computed_value::T) -> Self {
SpecifiedValue {
horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
vertical: ToComputedValue::from_computed_value(&computed.vertical),
}
}
}
</%helpers:longhand>
${helpers.single_keyword("backface-visibility", ${helpers.single_keyword("backface-visibility",
"visible hidden", "visible hidden",

View file

@ -3,59 +3,63 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
//! CSS handling for the computed value of //! CSS handling for the computed value of
//! [`position`][position]s //! [`position`][position] values.
//! //!
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
use std::fmt; use std::fmt;
use style_traits::ToCss; use style_traits::ToCss;
use values::computed::LengthOrPercentage; use values::computed::LengthOrPercentage;
use values::generics::position::{Position as GenericPosition, PositionWithKeyword};
use values::generics::position::HorizontalPosition as GenericHorizontalPosition;
use values::generics::position::VerticalPosition as GenericVerticalPosition;
#[derive(Debug, Clone, PartialEq, Copy)] /// The computed value of a CSS `<position>`
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub type Position = PositionWithKeyword<LengthOrPercentage>;
#[allow(missing_docs)]
pub struct Position { impl Copy for Position {}
pub horizontal: LengthOrPercentage,
pub vertical: LengthOrPercentage, /// The computed value for `<position>` values without a keyword.
pub type OriginPosition = GenericPosition<LengthOrPercentage, LengthOrPercentage>;
impl Copy for OriginPosition {}
impl OriginPosition {
#[inline]
/// The initial value for `perspective-origin`
pub fn center() -> OriginPosition {
GenericPosition {
horizontal: LengthOrPercentage::Percentage(0.5),
vertical: LengthOrPercentage::Percentage(0.5),
}
}
} }
impl Position { impl Position {
#[inline]
/// Construct a position at (0, 0) /// Construct a position at (0, 0)
pub fn zero() -> Self { pub fn zero() -> Self {
Position { Position {
horizontal: LengthOrPercentage::zero(), horizontal: GenericHorizontalPosition(LengthOrPercentage::zero()),
vertical: LengthOrPercentage::zero(), vertical: GenericVerticalPosition(LengthOrPercentage::zero()),
} }
} }
} }
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 {
try!(self.horizontal.to_css(dest)); self.horizontal.to_css(dest)?;
try!(dest.write_str(" ")); dest.write_str(" ")?;
try!(self.vertical.to_css(dest)); self.vertical.to_css(dest)
Ok(())
} }
} }
#[derive(Debug, Clone, PartialEq, Copy)] /// The computed value of a horizontal `<position>`
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub type HorizontalPosition = GenericHorizontalPosition<LengthOrPercentage>;
#[allow(missing_docs)]
pub struct HorizontalPosition(pub LengthOrPercentage);
impl ToCss for HorizontalPosition { impl Copy for HorizontalPosition {}
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.0.to_css(dest)
}
}
#[derive(Debug, Clone, PartialEq, Copy)] /// The computed value of a vertical `<position>`
#[cfg_attr(feature = "servo", derive(HeapSizeOf))] pub type VerticalPosition = GenericVerticalPosition<LengthOrPercentage>;
#[allow(missing_docs)]
pub struct VerticalPosition(pub LengthOrPercentage);
impl ToCss for VerticalPosition { impl Copy for VerticalPosition {}
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
self.0.to_css(dest)
}
}

View file

@ -25,6 +25,52 @@ define_css_keyword_enum!{ Keyword:
"y-end" => YEnd "y-end" => YEnd
} }
add_impls_for_keyword_enum!(Keyword);
impl Keyword {
#[inline]
/// The defaults for position keywords are `left` and `top` (`x-start` and `y-start` for logical).
/// This method checks whether this keyword indicates their opposite sides. See the
/// `ToComputedValue` impl on `HorizontalPosition` and `VerticalPosition` for its use case.
pub fn is_other_side(&self) -> bool {
if self.is_horizontal() || self.is_logical_x() {
matches!(*self, Keyword::Right | Keyword::XEnd)
} else {
matches!(*self, Keyword::Bottom | Keyword::YEnd)
}
}
#[inline]
/// Check whether this is a keyword for horizontal position.
pub fn is_horizontal(&self) -> bool {
matches!(*self, Keyword::Left | Keyword::Right)
}
#[inline]
/// Check whether this is a keyword for vertical position.
pub fn is_vertical(&self) -> bool {
matches!(*self, Keyword::Top | Keyword::Bottom)
}
#[inline]
/// Check whether this is a horizontal logical keyword.
pub fn is_logical_x(&self) -> bool {
matches!(*self, Keyword::XStart | Keyword::XEnd)
}
#[inline]
/// Check whether this is a vertical logical keyword.
pub fn is_logical_y(&self) -> bool {
matches!(*self, Keyword::YStart | Keyword::YEnd)
}
#[inline]
/// Check whether this is a logical keyword.
pub fn is_logical(&self) -> bool {
self.is_logical_x() || self.is_logical_y()
}
}
impl From<Keyword> for LengthOrPercentage { impl From<Keyword> for LengthOrPercentage {
fn from(val: Keyword) -> LengthOrPercentage { fn from(val: Keyword) -> LengthOrPercentage {
match val { match val {

View file

@ -338,13 +338,11 @@ fn serialize_basicshape_position<W>(position: &Position, dest: &mut W) -> fmt::R
replace_with_percent(y).to_css(dest) replace_with_percent(y).to_css(dest)
} }
match (position.horizontal.keyword, position.horizontal.position.clone(), match (position.horizontal.0.keyword, position.horizontal.0.position.clone(),
position.vertical.keyword, position.vertical.position.clone()) { position.vertical.0.keyword, position.vertical.0.position.clone()) {
(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.into(), vk.into(), dest)
vk.to_length_or_percentage(),
dest)
} }
(None, Some(hp), None, Some(vp)) => { (None, Some(hp), None, Some(vp)) => {
// two lengths: just serialize regularly // two lengths: just serialize regularly

View file

@ -8,616 +8,233 @@
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
use app_units::Au; use app_units::Au;
use cssparser::{Parser, Token}; use cssparser::Parser;
use parser::{Parse, ParserContext}; use parser::{Parse, ParserContext};
use std::fmt; use properties::longhands::parse_origin;
use style_traits::ToCss; use std::mem;
use values::HasViewportPercentage; use values::Either;
use values::computed::{self, CalcLengthOrPercentage, Context}; use values::computed::{CalcLengthOrPercentage, Context};
use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, ToComputedValue}; use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, ToComputedValue};
use values::computed::position as computed_position; use values::computed::position as computed_position;
use values::generics::position::{Position as GenericPosition, PositionValue, PositionWithKeyword};
use values::generics::position::HorizontalPosition as GenericHorizontalPosition;
use values::generics::position::VerticalPosition as GenericVerticalPosition;
use values::specified::{LengthOrPercentage, Percentage}; use values::specified::{LengthOrPercentage, Percentage};
#[derive(Debug, Clone, PartialEq)] pub use values::generics::position::Keyword;
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
/// A [position][pos]. /// The specified value of a CSS `<position>`
/// pub type Position = PositionWithKeyword<PositionValue<LengthOrPercentage>>;
/// [pos]: https://drafts.csswg.org/css-values/#position
pub struct Position { /// The specified value for `<position>` values without a keyword.
/// The horizontal component. pub type OriginPosition = GenericPosition<LengthOrPercentage, LengthOrPercentage>;
pub horizontal: HorizontalPosition,
/// The vertical component. impl Parse for OriginPosition {
pub vertical: VerticalPosition, fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
let result = parse_origin(context, input)?;
match result.depth {
Some(_) => Err(()),
None => Ok(GenericPosition {
horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))),
vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))),
})
} }
impl ToCss for Position {
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
macro_rules! to_css_with_keyword {
($pos:expr, $default_keyword:expr) => {
$pos.keyword.unwrap_or($default_keyword).to_css(dest)?;
if let Some(ref position) = $pos.position {
dest.write_str(" ")?;
position.to_css(dest)?;
};
};
}
let mut is_keyword_needed = false;
let position_x = &self.horizontal;
let position_y = &self.vertical;
if (position_x.keyword.is_some() && position_x.position.is_some()) ||
(position_y.keyword.is_some() && position_y.position.is_some()) {
is_keyword_needed = true;
}
if is_keyword_needed {
to_css_with_keyword!(position_x, Keyword::Left);
dest.write_str(" ")?;
to_css_with_keyword!(position_y, Keyword::Top);
} else {
position_x.to_css(dest)?;
dest.write_str(" ")?;
position_y.to_css(dest)?;
}
Ok(())
} }
} }
impl HasViewportPercentage for Position { type PositionComponent = Either<LengthOrPercentage, Keyword>;
fn has_viewport_percentage(&self) -> bool {
self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
}
}
impl Position { impl Position {
/// Create a new position value. /// Create a new position value from either a length or a keyword.
pub fn new(mut first_position: Option<PositionComponent>, pub fn from_components(mut first_position: Option<PositionComponent>,
mut second_position: Option<PositionComponent>, mut second_position: Option<PositionComponent>,
first_keyword: Option<PositionComponent>, first_keyword: Option<PositionComponent>,
second_keyword: Option<PositionComponent>) second_keyword: Option<PositionComponent>) -> Result<Position, ()> {
-> Result<Position, ()> {
// Unwrap for checking if values are at right place. // Unwrap for checking if values are at right place.
let first_key = first_keyword.clone().unwrap_or(PositionComponent::Keyword(Keyword::Left)); let first_key = first_keyword.clone().unwrap_or(Either::Second(Keyword::Left));
let second_key = second_keyword.clone().unwrap_or(PositionComponent::Keyword(Keyword::Top)); let second_key = second_keyword.clone().unwrap_or(Either::Second(Keyword::Top));
// Check if position specified after center keyword. let (horiz_keyword, vert_keyword) = match (&first_key, &second_key) {
if let PositionCategory::OtherKeyword = category(&first_key) { // Check if a position is specified after center keyword.
if let Some(_) = first_position { (&Either::Second(Keyword::Center), _) if first_position.is_some() => return Err(()),
return Err(()); (_, &Either::Second(Keyword::Center)) if second_position.is_some() => return Err(()),
};
};
if let PositionCategory::OtherKeyword = category(&second_key) {
if let Some(_) = second_position {
return Err(());
};
};
// Check first and second keywords for both 2 and 4 value positions. // Check first and second keywords for both 2 and 4 value positions.
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) |
(PositionCategory::VerticalKeyword, PositionCategory::VerticalKeyword) |
(PositionCategory::LengthOrPercentage, PositionCategory::HorizontalKeyword) |
(PositionCategory::VerticalKeyword, PositionCategory::LengthOrPercentage) => return Err(()),
// FIXME(canaltinova): Allow logical keywords for Position. They are not in current spec yet. // FIXME(canaltinova): Allow logical keywords for Position. They are not in current spec yet.
(PositionCategory::HorizontalLogicalKeyword, _) | (&Either::Second(k), _) if k.is_logical() => return Err(()),
(PositionCategory::VerticalLogicalKeyword, _) | (_, &Either::Second(k)) if k.is_logical() => return Err(()),
(_, PositionCategory::HorizontalLogicalKeyword) |
(_, PositionCategory::VerticalLogicalKeyword) => return Err(()), // Don't allow two vertical keywords or two horizontal keywords.
(&Either::Second(k1), &Either::Second(k2))
if (k1.is_horizontal() && k2.is_horizontal()) || (k1.is_vertical() && k2.is_vertical()) =>
return Err(()),
// Also don't allow <length-percentage> values in the wrong position
(&Either::First(_), &Either::Second(k)) if k.is_horizontal() => return Err(()),
(&Either::Second(k), &Either::First(_)) if k.is_vertical() => return Err(()),
// Swap if both are keywords and vertical precedes horizontal. // Swap if both are keywords and vertical precedes horizontal.
(PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) | (&Either::Second(k1), &Either::Second(k2))
(PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) | if (k1.is_vertical() && k2.is_horizontal()) || (k1.is_vertical() && k2 == Keyword::Center) ||
(PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => { (k1 == Keyword::Center && k2.is_horizontal()) => {
let tmp = first_position; mem::swap(&mut first_position, &mut second_position);
first_position = second_position;
second_position = tmp;
(second_keyword, first_keyword) (second_keyword, first_keyword)
}, },
// By default, horizontal is first. // By default, horizontal is first.
_ => (first_keyword, second_keyword), _ => (first_keyword, second_keyword),
}; };
// Unwrap positions from PositionComponent and wrap with Option let (mut h_pos, mut h_key, mut v_pos, mut v_key) = (None, None, None, None);
let (first_position, second_position) = if let Some(PositionComponent::Length(horiz_pos)) = first_position { if let Some(Either::First(l)) = first_position {
if let Some(PositionComponent::Length(vert_pos)) = second_position { h_pos = Some(l);
(Some(horiz_pos), Some(vert_pos))
} else {
(Some(horiz_pos), None)
} }
} else {
if let Some(PositionComponent::Length(vert_pos)) = second_position {
(None, Some(vert_pos))
} else {
(None, None)
}
};
// Unwrap keywords from PositionComponent and wrap with Option. if let Some(Either::First(l)) = second_position {
let (horizontal_keyword, vertical_keyword) = if let Some(PositionComponent::Keyword(horiz_key)) = v_pos = Some(l);
horiz_keyword {
if let Some(PositionComponent::Keyword(vert_key)) = vert_keyword {
(Some(horiz_key), Some(vert_key))
} else {
(Some(horiz_key), None)
} }
} else {
if let Some(PositionComponent::Keyword(vert_key)) = vert_keyword { if let Some(Either::Second(k)) = horiz_keyword {
(None, Some(vert_key)) h_key = Some(k);
} else { }
(None, None)
if let Some(Either::Second(k)) = vert_keyword {
v_key = Some(k);
} }
};
Ok(Position { Ok(Position {
horizontal: HorizontalPosition { horizontal: GenericHorizontalPosition(PositionValue {
keyword: horizontal_keyword, keyword: h_key,
position: first_position, position: h_pos,
}, }),
vertical: VerticalPosition { vertical: GenericVerticalPosition(PositionValue {
keyword: vertical_keyword, keyword: v_key,
position: second_position, position: v_pos,
}, }),
}) })
} }
/// Returns a "centered" position, as in "center center". /// Returns a "centered" position, as in "center center".
pub fn center() -> Position { pub fn center() -> Position {
Position { Position {
horizontal: HorizontalPosition { horizontal: GenericHorizontalPosition(PositionValue {
keyword: Some(Keyword::Center), keyword: Some(Keyword::Center),
position: None, position: None,
}, }),
vertical: VerticalPosition { vertical: GenericVerticalPosition(PositionValue {
keyword: Some(Keyword::Center), keyword: Some(Keyword::Center),
position: None, position: None,
}, }),
} }
} }
} }
impl Parse for Position { impl Parse for Position {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
let first = try!(PositionComponent::parse(context, input)); let first = input.try(|i| PositionComponent::parse(context, i))?;
let second = input.try(|i| PositionComponent::parse(context, i)) let second = input.try(|i| PositionComponent::parse(context, i))
.unwrap_or(PositionComponent::Keyword(Keyword::Center)); .unwrap_or(Either::Second(Keyword::Center));
// Try to parse third and fourth values
if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) { if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) {
// There's a 3rd value.
if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) { if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) {
// Handle 4 value background position // There's a 4th value.
Position::new(Some(second), Some(fourth), Some(first), Some(third)) Position::from_components(Some(second), Some(fourth), Some(first), Some(third))
} else {
// Handle 3 value background position there are several options:
if let PositionCategory::LengthOrPercentage = category(&first) {
Err(())
} else {
if let PositionCategory::LengthOrPercentage = category(&second) {
if let PositionCategory::LengthOrPercentage = category(&third) {
Err(())
} else { } else {
// For 3 value background position, there are several options.
if let Either::First(_) = first {
return Err(()) // <length-percentage> must be preceded by <keyword>
}
// only 3 values.
match (&second, &third) {
(&Either::First(_), &Either::First(_)) => Err(()),
// "keyword length keyword" // "keyword length keyword"
Position::new(Some(second), None, Some(first), Some(third)) (&Either::First(_), _) => Position::from_components(Some(second), None,
} Some(first), Some(third)),
} else {
// "keyword keyword length" // "keyword keyword length"
Position::new(None, Some(third), Some(first), Some(second)) _ => Position::from_components(None, Some(third), Some(first), Some(second)),
}
} }
} }
} else { } else {
// Handle 2 value background position. // only 2 values.
if let PositionCategory::LengthOrPercentage = category(&first) { match (&first, &second) {
if let PositionCategory::LengthOrPercentage = category(&second) { (&Either::First(_), &Either::First(_)) =>
Position::new(Some(first), Some(second), None, None) Position::from_components(Some(first), Some(second), None, None),
} else { (&Either::First(_), &Either::Second(_)) =>
Position::new(Some(first), None, None, Some(second)) Position::from_components(Some(first), None, None, Some(second)),
} (&Either::Second(_), &Either::First(_)) =>
} else { Position::from_components(None, Some(second), Some(first), None),
if let PositionCategory::LengthOrPercentage = category(&second) { (&Either::Second(_), &Either::Second(_)) =>
Position::new(None, Some(second), Some(first), None) Position::from_components(None, None, Some(first), Some(second)),
} else {
Position::new(None, None, Some(first), Some(second))
}
} }
} }
} }
} }
impl ToComputedValue for Position { impl PositionValue<LengthOrPercentage> {
type ComputedValue = computed_position::Position; /// Generic function for the computed value of a position.
fn computed_value(&self, context: &Context) -> ComputedLengthOrPercentage {
#[inline] match self.keyword {
fn to_computed_value(&self, context: &Context) -> computed_position::Position { Some(Keyword::Center) => ComputedLengthOrPercentage::Percentage(0.5),
computed_position::Position { Some(k) if k.is_other_side() => match self.position {
horizontal: self.horizontal.to_computed_value(context).0, Some(ref x) => {
vertical: self.vertical.to_computed_value(context).0, let (length, percentage) = match *x {
} LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
} LengthOrPercentage::Length(ref y) => (-y.to_computed_value(context), Some(1.0)),
_ => (Au(0), None),
#[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)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct HorizontalPosition {
pub keyword: Option<Keyword>,
pub position: Option<LengthOrPercentage>,
}
impl HasViewportPercentage for HorizontalPosition {
fn has_viewport_percentage(&self) -> bool {
self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage())
}
}
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(ref position) = self.position { ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
if keyword_present { length: length,
try!(dest.write_str(" ")); percentage: percentage
}
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.as_ref().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,
}) })
},
None => ComputedLengthOrPercentage::Percentage(1.0),
},
_ => self.position.as_ref().map(|l| l.to_computed_value(context))
.unwrap_or(ComputedLengthOrPercentage::Percentage(0.0)),
} }
} }
}
/// The specified value of horizontal `<position>`
pub type HorizontalPosition = GenericHorizontalPosition<PositionValue<LengthOrPercentage>>;
impl ToComputedValue for HorizontalPosition { impl ToComputedValue for HorizontalPosition {
type ComputedValue = computed_position::HorizontalPosition; type ComputedValue = computed_position::HorizontalPosition;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> computed_position::HorizontalPosition { fn to_computed_value(&self, context: &Context) -> computed_position::HorizontalPosition {
let keyword = self.keyword.unwrap_or(Keyword::Left); GenericHorizontalPosition(self.0.computed_value(context))
// Construct horizontal computed LengthOrPercentage
let horizontal = match keyword {
// FIXME(canaltinova): Support logical keywords.
Keyword::Right | Keyword::XEnd => {
if let Some(ref x) = self.position {
let (length, percentage) = match *x {
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
LengthOrPercentage::Length(ref 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 zero = LengthOrPercentage::Percentage(Percentage(0.0));
let horiz = self.position.as_ref().unwrap_or(&zero);
horiz.to_computed_value(context)
},
};
computed_position::HorizontalPosition(horizontal)
} }
#[inline] #[inline]
fn from_computed_value(computed: &computed_position::HorizontalPosition) -> HorizontalPosition { fn from_computed_value(computed: &computed_position::HorizontalPosition) -> HorizontalPosition {
HorizontalPosition { GenericHorizontalPosition(PositionValue {
keyword: None, keyword: None,
position: Some(ToComputedValue::from_computed_value(&computed.0)), position: Some(ToComputedValue::from_computed_value(&computed.0)),
}
}
}
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
#[allow(missing_docs)]
pub struct VerticalPosition {
pub keyword: Option<Keyword>,
pub position: Option<LengthOrPercentage>,
}
impl HasViewportPercentage for VerticalPosition {
fn has_viewport_percentage(&self) -> bool {
self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage())
}
}
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(ref 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.as_ref().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,
}) })
} }
} }
/// The specified value of vertical `<position>`
pub type VerticalPosition = GenericVerticalPosition<PositionValue<LengthOrPercentage>>;
impl ToComputedValue for VerticalPosition { impl ToComputedValue for VerticalPosition {
type ComputedValue = computed_position::VerticalPosition; type ComputedValue = computed_position::VerticalPosition;
#[inline] #[inline]
fn to_computed_value(&self, context: &Context) -> computed_position::VerticalPosition { fn to_computed_value(&self, context: &Context) -> computed_position::VerticalPosition {
let keyword = self.keyword.unwrap_or(Keyword::Left); GenericVerticalPosition(self.0.computed_value(context))
// Construct vertical computed LengthOrPercentage
let vertical = match keyword {
// FIXME(canaltinova): Support logical keywords.
Keyword::Bottom | Keyword::YEnd => {
if let Some(ref x) = self.position {
let (length, percentage) = match *x {
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
LengthOrPercentage::Length(ref 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 zero = LengthOrPercentage::Percentage(Percentage(0.0));
let vert = self.position.as_ref().unwrap_or(&zero);
vert.to_computed_value(context)
},
};
computed_position::VerticalPosition(vertical)
} }
#[inline] #[inline]
fn from_computed_value(computed: &computed_position::VerticalPosition) -> VerticalPosition { fn from_computed_value(computed: &computed_position::VerticalPosition) -> VerticalPosition {
VerticalPosition { GenericVerticalPosition(PositionValue {
keyword: None, keyword: None,
position: Some(ToComputedValue::from_computed_value(&computed.0)), 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 {
/// Convert the given keyword to a length or a percentage.
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
match self {
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)),
}
}
}
// Collapse `Position` into a few categories to simplify the above `match` expression.
enum PositionCategory {
HorizontalKeyword,
VerticalKeyword,
HorizontalLogicalKeyword,
VerticalLogicalKeyword,
OtherKeyword,
LengthOrPercentage,
}
/// A position component.
///
/// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
#[derive(Clone, PartialEq)]
pub enum PositionComponent {
/// A `<length>`
Length(LengthOrPercentage),
/// A position keyword.
Keyword(Keyword),
}
fn category(p: &PositionComponent) -> PositionCategory {
if let PositionComponent::Keyword(keyword) = *p {
match keyword {
Keyword::Left | Keyword::Right =>
PositionCategory::HorizontalKeyword,
Keyword::Top | Keyword::Bottom =>
PositionCategory::VerticalKeyword,
Keyword::XStart | Keyword::XEnd =>
PositionCategory::HorizontalLogicalKeyword,
Keyword::YStart | Keyword::YEnd =>
PositionCategory::VerticalLogicalKeyword,
Keyword::Center =>
PositionCategory::OtherKeyword,
}
} else {
PositionCategory::LengthOrPercentage
}
}
impl HasViewportPercentage for PositionComponent {
fn has_viewport_percentage(&self) -> bool {
match *self {
PositionComponent::Length(ref length) => length.has_viewport_percentage(),
_ => false
}
}
}
impl PositionComponent {
/// Convert the given position component to a length or a percentage.
#[inline]
pub fn to_length_or_percentage_computed(&self, cx: &Context) -> computed::LengthOrPercentage {
match *self {
PositionComponent::Length(ref value) => value.to_computed_value(cx),
PositionComponent::Keyword(keyword) => {
keyword.to_length_or_percentage().to_computed_value(cx)
}
}
}
}
impl Parse for PositionComponent {
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
input.try(|i| LengthOrPercentage::parse(context, i))
.map(PositionComponent::Length)
.or_else(|()| {
match try!(input.next()) {
Token::Ident(value) => {
match_ignore_ascii_case! { &value,
"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)),
"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(())
}
}) })
} }
} }

View file

@ -799,8 +799,8 @@ mod shorthand_serialization {
use style::properties::longhands::mask_position_y as position_y; use style::properties::longhands::mask_position_y as position_y;
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::generics::position::{HorizontalPosition, Keyword, PositionValue, VerticalPosition};
use style::values::specified::Image; use style::values::specified::Image;
use style::values::specified::position::{HorizontalPosition, VerticalPosition, Keyword};
use super::*; use super::*;
macro_rules! single_vec_value_typedef { macro_rules! single_vec_value_typedef {
@ -836,16 +836,16 @@ mod shorthand_serialization {
let mode = single_vec_keyword_value!(mode, luminance); let mode = single_vec_keyword_value!(mode, luminance);
let position_x = single_vec_value_typedef!(position_x, let position_x = single_vec_value_typedef!(position_x,
HorizontalPosition { HorizontalPosition(PositionValue {
keyword: None, keyword: None,
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))), position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))),
} })
); );
let position_y = single_vec_value_typedef!(position_y, let position_y = single_vec_value_typedef!(position_y,
VerticalPosition { VerticalPosition(PositionValue {
keyword: Some(Keyword::Bottom), keyword: Some(Keyword::Bottom),
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))), position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))),
} })
); );
let size = single_vec_variant_value!(size, let size = single_vec_variant_value!(size,
@ -891,17 +891,17 @@ mod shorthand_serialization {
let mode = single_vec_keyword_value!(mode, luminance); let mode = single_vec_keyword_value!(mode, luminance);
let position_x = single_vec_value_typedef!(position_x, let position_x = single_vec_value_typedef!(position_x,
HorizontalPosition { HorizontalPosition(PositionValue {
keyword: None, keyword: None,
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))), position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))),
} })
); );
let position_y = single_vec_value_typedef!(position_y, let position_y = single_vec_value_typedef!(position_y,
VerticalPosition { VerticalPosition(PositionValue {
keyword: None, keyword: None,
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))), position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))),
} })
); );
let size = single_vec_variant_value!(size, let size = single_vec_variant_value!(size,