diff options
author | bors-servo <lbergstrom+bors@mozilla.com> | 2017-05-10 09:56:17 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-05-10 09:56:17 -0500 |
commit | d5efed6c6a3e05f09300a3ed36d0e1254fcb407c (patch) | |
tree | 0b36cbf101952b9b9f6b349f5d82c4aca01450b7 | |
parent | 0040160b38bfef8f4a8c99bf3a0ad85f0b415d4d (diff) | |
parent | 70ec61cf01907c064c53563b46ea361b6a0348fe (diff) | |
download | servo-d5efed6c6a3e05f09300a3ed36d0e1254fcb407c.tar.gz servo-d5efed6c6a3e05f09300a3ed36d0e1254fcb407c.zip |
Auto merge of #16770 - nox:POSITION-DO-YOU-EVEN, r=Wafflespeanut,nox
Refactor Position
<!-- Reviewable:start -->
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16770)
<!-- Reviewable:end -->
22 files changed, 452 insertions, 855 deletions
diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index b48bb607ac7..472a34529ca 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -1008,9 +1008,9 @@ impl FragmentDisplayListBuilding for Fragment { let horiz_position = *get_cyclic(&background.background_position_x.0, index); let vert_position = *get_cyclic(&background.background_position_y.0, index); // Use `background-position` to get the offset. - let horizontal_position = model::specified(horiz_position.0, + let horizontal_position = model::specified(horiz_position, bounds.size.width - image_size.width); - let vertical_position = model::specified(vert_position.0, + let vertical_position = model::specified(vert_position, bounds.size.height - image_size.height); // The anchor position for this background, based on both the background-attachment @@ -1167,8 +1167,8 @@ impl FragmentDisplayListBuilding for Fragment { repeating: bool, style: &ServoComputedValues) -> display_list::RadialGradient { - let center = Point2D::new(specified(center.horizontal.0, bounds.size.width), - specified(center.vertical.0, bounds.size.height)); + let center = Point2D::new(specified(center.horizontal, bounds.size.width), + specified(center.vertical, bounds.size.height)); let radius = match *shape { EndingShape::Circle(LengthOrKeyword::Length(length)) => Size2D::new(length, length), diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 5b2e726583e..bb299a74db1 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -307,8 +307,8 @@ impl nsStyleImage { }, } unsafe { - (*gecko_gradient).mBgPosX.set(position.horizontal.0); - (*gecko_gradient).mBgPosY.set(position.vertical.0); + (*gecko_gradient).mBgPosX.set(position.horizontal); + (*gecko_gradient).mBgPosY.set(position.vertical); } gecko_gradient @@ -372,7 +372,6 @@ pub mod basic_shape { use values::computed::position; use values::generics::BorderRadiusSize as GenericBorderRadiusSize; use values::generics::basic_shape::FillRule; - use values::generics::position::{HorizontalPosition, VerticalPosition}; // using Borrow so that we can have a non-moving .into() impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape { @@ -483,8 +482,8 @@ pub mod basic_shape { impl From<position::Position> for structs::Position { fn from(other: position::Position) -> Self { structs::Position { - mXPosition: other.horizontal.0.into(), - mYPosition: other.vertical.0.into() + mXPosition: other.horizontal.into(), + mYPosition: other.vertical.into() } } } @@ -501,8 +500,8 @@ pub mod basic_shape { fn from(other: T) -> Self { let other = other.borrow(); position::Position { - horizontal: HorizontalPosition(other.mXPosition.into()), - vertical: VerticalPosition(other.mYPosition.into()), + horizontal: other.mXPosition.into(), + vertical: other.mYPosition.into(), } } } diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 4995e9abfce..0df847cfd95 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -367,17 +367,16 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor { <%def name="impl_position(ident, gecko_ffi_name, need_clone=False)"> #[allow(non_snake_case)] pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { - ${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.0.into()")} - ${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.0.into()")} + ${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.into()")} + ${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.into()")} } <%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call> % if need_clone: #[allow(non_snake_case)] pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T { - use values::generics::position::{HorizontalPosition, Position, VerticalPosition}; - Position { - horizontal: HorizontalPosition(self.gecko.${gecko_ffi_name}.mXPosition.into()), - vertical: VerticalPosition(self.gecko.${gecko_ffi_name}.mYPosition.into()), + longhands::${ident}::computed_value::T { + horizontal: self.gecko.${gecko_ffi_name}.mXPosition.into(), + vertical: self.gecko.${gecko_ffi_name}.mYPosition.into(), } } % endif @@ -2040,8 +2039,8 @@ fn static_assert() { for (gecko, servo) in self.gecko.mScrollSnapCoordinate .iter_mut() .zip(v) { - gecko.mXPosition = servo.horizontal.0.into(); - gecko.mYPosition = servo.vertical.0.into(); + gecko.mXPosition = servo.horizontal.into(); + gecko.mYPosition = servo.vertical.into(); } } @@ -2726,12 +2725,12 @@ fn static_assert() { } </%self:simple_image_array_property> - % for orientation in [("x", "Horizontal"), ("y", "Vertical")]: - pub fn copy_${shorthand}_position_${orientation[0]}_from(&mut self, other: &Self) { + % for orientation in ["x", "y"]: + pub fn copy_${shorthand}_position_${orientation}_from(&mut self, other: &Self) { use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; - self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count - = cmp::min(1, other.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count); + self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count + = cmp::min(1, other.gecko.${image_layers_field}.mPosition${orientation.upper()}Count); self.gecko.${image_layers_field}.mLayers.mFirstElement.mPosition = other.gecko.${image_layers_field}.mLayers.mFirstElement.mPosition; unsafe { @@ -2742,20 +2741,19 @@ fn static_assert() { for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() .zip(other.gecko.${image_layers_field}.mLayers.iter()) { - layer.mPosition.m${orientation[0].upper()}Position - = other.mPosition.m${orientation[0].upper()}Position; + layer.mPosition.m${orientation.upper()}Position + = other.mPosition.m${orientation.upper()}Position; } - self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count - = other.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count; + self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count + = other.gecko.${image_layers_field}.mPosition${orientation.upper()}Count; } - pub fn clone_${shorthand}_position_${orientation[0]}(&self) - -> longhands::${shorthand}_position_${orientation[0]}::computed_value::T { - use values::generics::position::${orientation[1]}Position; - longhands::${shorthand}_position_${orientation[0]}::computed_value::T( + pub fn clone_${shorthand}_position_${orientation}(&self) + -> longhands::${shorthand}_position_${orientation}::computed_value::T { + longhands::${shorthand}_position_${orientation}::computed_value::T( self.gecko.${image_layers_field}.mLayers.iter() - .take(self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count as usize) - .map(|position| ${orientation[1]}Position(position.mPosition.m${orientation[0].upper()}Position.into())) + .take(self.gecko.${image_layers_field}.mPosition${orientation.upper()}Count as usize) + .map(|position| position.mPosition.m${orientation.upper()}Position.into()) .collect() ) } @@ -2778,7 +2776,7 @@ fn static_assert() { self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count = v.len() as u32; for (servo, geckolayer) in v.zip(self.gecko.${image_layers_field} .mLayers.iter_mut()) { - geckolayer.mPosition.m${orientation[0].upper()}Position = servo.0.into(); + geckolayer.mPosition.m${orientation[0].upper()}Position = servo.into(); } } % endfor diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index fcc963d2d2a..9d75c63d7eb 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -41,7 +41,6 @@ use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone use values::computed::{BorderRadiusSize, ClipRect}; use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage}; use values::computed::{MaxLength, MinLength}; -use values::computed::position::{HorizontalPosition, VerticalPosition}; use values::computed::ToComputedValue; use values::generics::position as generic_position; @@ -655,6 +654,7 @@ pub trait Animatable: Sized { /// https://drafts.csswg.org/css-transitions/#animtype-repeatable-list pub trait RepeatableListAnimatable: Animatable {} +impl RepeatableListAnimatable for LengthOrPercentage {} impl RepeatableListAnimatable for Either<f32, LengthOrPercentage> {} impl<T: RepeatableListAnimatable> Animatable for SmallVec<[T; 1]> { @@ -1336,46 +1336,6 @@ impl<H: Animatable, V: Animatable> Animatable for generic_position::Position<H, impl<H, V> RepeatableListAnimatable for generic_position::Position<H, V> where H: RepeatableListAnimatable, V: RepeatableListAnimatable {} -/// https://drafts.csswg.org/css-transitions/#animtype-simple-list -impl Animatable for HorizontalPosition { - #[inline] - fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - self.0.interpolate(&other.0, progress).map(generic_position::HorizontalPosition) - } - - #[inline] - fn compute_distance(&self, other: &Self) -> Result<f64, ()> { - self.0.compute_distance(&other.0) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { - self.0.compute_squared_distance(&other.0) - } -} - -impl RepeatableListAnimatable for HorizontalPosition {} - -/// https://drafts.csswg.org/css-transitions/#animtype-simple-list -impl Animatable for VerticalPosition { - #[inline] - fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - self.0.interpolate(&other.0, progress).map(generic_position::VerticalPosition) - } - - #[inline] - fn compute_distance(&self, other: &Self) -> Result<f64, ()> { - self.0.compute_distance(&other.0) - } - - #[inline] - fn compute_squared_distance(&self, other: &Self) -> Result<f64, ()> { - self.0.compute_squared_distance(&other.0) - } -} - -impl RepeatableListAnimatable for VerticalPosition {} - /// https://drafts.csswg.org/css-transitions/#animtype-rect impl Animatable for ClipRect { #[inline] diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index 50e2ce4e9bd..b0c998d59fd 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -20,38 +20,13 @@ ${helpers.predefined_type("background-image", "LayerImage", animation_value_type="none", has_uncacheable_values="True" if product == "gecko" else "False")} -<%helpers:predefined_type name="background-position-x" type="position::HorizontalPosition" - initial_value="computed::position::HorizontalPosition::zero()" - initial_specified_value="specified::position::HorizontalPosition::left()" - spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x" - animation_value_type="ComputedValue" vector="True" delegate_animate="True"> - #[inline] - /// Get the initial value for horizontal position. - pub fn get_initial_position_value() -> SpecifiedValue { - use values::generics::position::{HorizontalPosition, PositionValue}; - use values::specified::{LengthOrPercentage, Percentage}; - HorizontalPosition(PositionValue { - keyword: None, - position: Some(LengthOrPercentage::Percentage(Percentage(0.0))), - }) - } -</%helpers:predefined_type> - -<%helpers:predefined_type name="background-position-y" type="position::VerticalPosition" - initial_value="computed::position::VerticalPosition::zero()" - initial_specified_value="specified::position::VerticalPosition::top()" - spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y" - animation_value_type="ComputedValue" vector="True" delegate_animate="True"> - /// Get the initial value for vertical position. - pub fn get_initial_position_value() -> SpecifiedValue { - use values::generics::position::{VerticalPosition, PositionValue}; - use values::specified::{LengthOrPercentage, Percentage}; - VerticalPosition(PositionValue { - keyword: None, - position: Some(LengthOrPercentage::Percentage(Percentage(0.0))), - }) - } -</%helpers:predefined_type> +% for (axis, direction, initial) in [("x", "Horizontal", "left"), ("y", "Vertical", "top")]: + ${helpers.predefined_type("background-position-" + axis, "position::" + direction + "Position", + initial_value="computed::LengthOrPercentage::zero()", + initial_specified_value="SpecifiedValue::initial_specified_value()", + spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-" + axis, + animation_value_type="ComputedValue", vector=True, delegate_animate=True)} +% endfor <%helpers:vector_longhand name="background-repeat" animation_value_type="none" spec="https://drafts.csswg.org/css-backgrounds/#the-background-repeat"> diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index b9a451b1571..4927c807d2f 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -2143,11 +2143,11 @@ ${helpers.predefined_type("perspective", animation_value_type="ComputedValue")} ${helpers.predefined_type("perspective-origin", - "position::OriginPosition", - "computed::position::OriginPosition::center()", + "position::Position", + "computed::position::Position::center()", boxed="True", extra_prefixes="moz webkit", - spec="https://drafts.csswg.org/css-transforms/#perspective-origin-property", + spec="https://drafts.csswg.org/css-transforms-2/#perspective-origin-property", animation_value_type="ComputedValue")} ${helpers.single_keyword("backface-visibility", diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index 104929fff77..c1327a6ca2e 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -90,49 +90,14 @@ ${helpers.single_keyword("mask-mode", } </%helpers:vector_longhand> -<%helpers:vector_longhand name="mask-position-x" products="gecko" - animation_value_type="ComputedValue" extra_prefixes="webkit" - spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position"> - pub use properties::longhands::background_position_x::single_value::get_initial_value; - pub use properties::longhands::background_position_x::single_value::get_initial_position_value; - pub use properties::longhands::background_position_x::single_value::get_initial_specified_value; - pub use properties::longhands::background_position_x::single_value::parse; - pub use properties::longhands::background_position_x::single_value::SpecifiedValue; - pub use properties::longhands::background_position_x::single_value::computed_value; - use properties::animated_properties::{Animatable, RepeatableListAnimatable}; - use properties::longhands::mask_position_x::computed_value::T as MaskPositionX; - - impl Animatable for MaskPositionX { - #[inline] - fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - Ok(MaskPositionX(try!(self.0.interpolate(&other.0, progress)))) - } - } - - impl RepeatableListAnimatable for MaskPositionX {} -</%helpers:vector_longhand> - -<%helpers:vector_longhand name="mask-position-y" products="gecko" - animation_value_type="ComputedValue" extra_prefixes="webkit" - spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position"> - pub use properties::longhands::background_position_y::single_value::get_initial_value; - pub use properties::longhands::background_position_y::single_value::get_initial_position_value; - pub use properties::longhands::background_position_y::single_value::get_initial_specified_value; - pub use properties::longhands::background_position_y::single_value::parse; - pub use properties::longhands::background_position_y::single_value::SpecifiedValue; - pub use properties::longhands::background_position_y::single_value::computed_value; - use properties::animated_properties::{Animatable, RepeatableListAnimatable}; - use properties::longhands::mask_position_y::computed_value::T as MaskPositionY; - - impl Animatable for MaskPositionY { - #[inline] - fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> { - Ok(MaskPositionY(try!(self.0.interpolate(&other.0, progress)))) - } - } - - impl RepeatableListAnimatable for MaskPositionY {} -</%helpers:vector_longhand> +% for (axis, direction) in [("x", "Horizontal"), ("y", "Vertical")]: + ${helpers.predefined_type("mask-position-" + axis, "position::" + direction + "Position", + products="gecko", extra_prefixes="webkit", + initial_value="computed::LengthOrPercentage::zero()", + initial_specified_value="specified::PositionComponent::Center", + spec="https://drafts.fxtf.org/css-masking/#propdef-mask-position", + animation_value_type="ComputedValue", vector=True, delegate_animate=True)} +% endfor ${helpers.single_keyword("mask-clip", "border-box content-box padding-box", diff --git a/components/style/properties/shorthand/background.mako.rs b/components/style/properties/shorthand/background.mako.rs index 21a75db2693..7732a84ff73 100644 --- a/components/style/properties/shorthand/background.mako.rs +++ b/components/style/properties/shorthand/background.mako.rs @@ -15,7 +15,7 @@ use properties::longhands::background_clip; use properties::longhands::background_clip::single_value::computed_value::T as Clip; use properties::longhands::background_origin::single_value::computed_value::T as Origin; - use values::specified::position::Position; + use values::specified::{Position, PositionComponent}; use parser::Parse; impl From<background_origin::single_value::SpecifiedValue> for background_clip::single_value::SpecifiedValue { @@ -39,7 +39,7 @@ let mut background_${name} = background_${name}::SpecifiedValue(Vec::new()); % endfor try!(input.parse_comma_separated(|input| { - % for name in "image position_x position_y repeat size attachment origin clip".split(): + % for name in "image position repeat size attachment origin clip".split(): let mut ${name} = None; % endfor loop { @@ -52,10 +52,9 @@ return Err(()) } } - if position_x.is_none() && position_y.is_none() { + if position.is_none() { if let Ok(value) = input.try(|input| Position::parse(context, input)) { - position_x = Some(value.horizontal); - position_y = Some(value.vertical); + position = Some(value); // Parse background size, if applicable. size = input.try(|input| { @@ -83,22 +82,17 @@ } } let mut any = false; - % for name in "image position_x position_y repeat size attachment origin clip".split(): + % for name in "image position repeat size attachment origin clip".split(): any = any || ${name}.is_some(); % endfor any = any || background_color.is_some(); if any { - if position_x.is_some() || position_y.is_some() { - % for name in "position_x position_y".split(): - if let Some(bg_${name}) = ${name} { - background_${name}.0.push(bg_${name}); - } - % endfor + if let Some(position) = position { + background_position_x.0.push(position.horizontal); + background_position_y.0.push(position.vertical); } else { - % for name in "position_x position_y".split(): - background_${name}.0.push(background_${name}::single_value - ::get_initial_position_value()); - % endfor + background_position_x.0.push(PositionComponent::zero()); + background_position_y.0.push(PositionComponent::zero()); } % for name in "image repeat size attachment origin clip".split(): if let Some(bg_${name}) = ${name} { @@ -193,7 +187,7 @@ <%helpers:shorthand name="background-position" sub_properties="background-position-x background-position-y" spec="https://drafts.csswg.org/css-backgrounds-4/#the-background-position"> - use properties::longhands::{background_position_x,background_position_y}; + use properties::longhands::{background_position_x, background_position_y}; use values::specified::AllowQuirks; use values::specified::position::Position; @@ -202,18 +196,13 @@ let mut position_y = background_position_y::SpecifiedValue(Vec::new()); let mut any = false; - try!(input.parse_comma_separated(|input| { - loop { - if let Ok(value) = input.try(|input| Position::parse_quirky(context, input, AllowQuirks::Yes)) { - position_x.0.push(value.horizontal); - position_y.0.push(value.vertical); - any = true; - continue - } - break - } + input.parse_comma_separated(|input| { + let value = Position::parse_quirky(context, input, AllowQuirks::Yes)?; + position_x.0.push(value.horizontal); + position_y.0.push(value.vertical); + any = true; Ok(()) - })); + })?; if !any { return Err(()); } diff --git a/components/style/properties/shorthand/mask.mako.rs b/components/style/properties/shorthand/mask.mako.rs index 8096f223757..e9d03035964 100644 --- a/components/style/properties/shorthand/mask.mako.rs +++ b/components/style/properties/shorthand/mask.mako.rs @@ -11,7 +11,7 @@ use properties::longhands::{mask_mode, mask_repeat, mask_clip, mask_origin, mask_composite, mask_position_x, mask_position_y}; use properties::longhands::{mask_size, mask_image}; - use values::specified::position::Position; + use values::specified::{Position, PositionComponent}; use parser::Parse; impl From<mask_origin::single_value::SpecifiedValue> for mask_clip::single_value::SpecifiedValue { @@ -41,7 +41,7 @@ % endfor try!(input.parse_comma_separated(|input| { - % for name in "image mode position_x position_y size repeat origin clip composite".split(): + % for name in "image mode position size repeat origin clip composite".split(): let mut ${name} = None; % endfor loop { @@ -52,10 +52,9 @@ continue } } - if position_x.is_none() && position_y.is_none() { + if position.is_none() { if let Ok(value) = input.try(|input| Position::parse(context, input)) { - position_x = Some(value.horizontal); - position_y = Some(value.vertical); + position = Some(value); // Parse mask size, if applicable. size = input.try(|input| { @@ -83,21 +82,16 @@ } } let mut any = false; - % for name in "image mode position_x position_y size repeat origin clip composite".split(): + % for name in "image mode position size repeat origin clip composite".split(): any = any || ${name}.is_some(); % endfor if any { - if position_x.is_some() || position_y.is_some() { - % for name in "position_x position_y".split(): - if let Some(bg_${name}) = ${name} { - mask_${name}.0.push(bg_${name}); - } - % endfor + if let Some(position) = position { + mask_position_x.0.push(position.horizontal); + mask_position_y.0.push(position.vertical); } else { - % for name in "position_x position_y".split(): - mask_${name}.0.push(mask_${name}::single_value - ::get_initial_position_value()); - % endfor + mask_position_x.0.push(PositionComponent::zero()); + mask_position_y.0.push(PositionComponent::zero()); } % for name in "image mode size repeat origin clip composite".split(): if let Some(m_${name}) = ${name} { @@ -191,18 +185,13 @@ let mut position_y = mask_position_y::SpecifiedValue(Vec::new()); let mut any = false; - try!(input.parse_comma_separated(|input| { - loop { - if let Ok(value) = input.try(|input| Position::parse(context, input)) { - position_x.0.push(value.horizontal); - position_y.0.push(value.vertical); - any = true; - continue - } - break - } + input.parse_comma_separated(|input| { + let value = Position::parse(context, input)?; + position_x.0.push(value.horizontal); + position_y.0.push(value.vertical); + any = true; Ok(()) - })); + })?; if any == false { return Err(()); } diff --git a/components/style/values/computed/position.rs b/components/style/values/computed/position.rs index d30e911f9fa..97f14b73f04 100644 --- a/components/style/values/computed/position.rs +++ b/components/style/values/computed/position.rs @@ -10,39 +10,28 @@ use std::fmt; use style_traits::ToCss; 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; +use values::generics::position::Position as GenericPosition; /// The computed value of a CSS `<position>` -pub type Position = PositionWithKeyword<LengthOrPercentage>; +pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>; -impl Copy for Position {} +/// The computed value of a CSS horizontal position. +pub type HorizontalPosition = LengthOrPercentage; -/// The computed value for `<position>` values without a keyword. -pub type OriginPosition = GenericPosition<LengthOrPercentage, LengthOrPercentage>; +/// The computed value of a CSS vertical position. +pub type VerticalPosition = LengthOrPercentage; -impl Copy for OriginPosition {} - -impl OriginPosition { +impl Position { + /// `50% 50%` #[inline] - /// The initial value for `perspective-origin` - pub fn center() -> OriginPosition { - GenericPosition { - horizontal: LengthOrPercentage::Percentage(0.5), - vertical: LengthOrPercentage::Percentage(0.5), - } + pub fn center() -> Self { + Self::new(LengthOrPercentage::Percentage(0.5), LengthOrPercentage::Percentage(0.5)) } -} -impl Position { + /// `0% 0%` #[inline] - /// Construct a position at (0, 0) pub fn zero() -> Self { - Position { - horizontal: GenericHorizontalPosition(LengthOrPercentage::zero()), - vertical: GenericVerticalPosition(LengthOrPercentage::zero()), - } + Self::new(LengthOrPercentage::zero(), LengthOrPercentage::zero()) } } @@ -53,29 +42,3 @@ impl ToCss for Position { self.vertical.to_css(dest) } } - -/// The computed value of a horizontal `<position>` -pub type HorizontalPosition = GenericHorizontalPosition<LengthOrPercentage>; - -impl Copy for HorizontalPosition {} - -impl HorizontalPosition { - #[inline] - /// Create a zero position value. - pub fn zero() -> HorizontalPosition { - GenericHorizontalPosition(LengthOrPercentage::Percentage(0.0)) - } -} - -/// The computed value of a vertical `<position>` -pub type VerticalPosition = GenericVerticalPosition<LengthOrPercentage>; - -impl Copy for VerticalPosition {} - -impl VerticalPosition { - #[inline] - /// Create a zero position value. - pub fn zero() -> VerticalPosition { - GenericVerticalPosition(LengthOrPercentage::Percentage(0.0)) - } -} diff --git a/components/style/values/generics/position.rs b/components/style/values/generics/position.rs index d15198b638e..1b805b8ff08 100644 --- a/components/style/values/generics/position.rs +++ b/components/style/values/generics/position.rs @@ -5,231 +5,12 @@ //! Generic types for CSS handling of specified and computed values of //! [`position`](https://drafts.csswg.org/css-backgrounds-3/#position) -use cssparser::Parser; -use parser::{Parse, ParserContext}; -use std::fmt; -use style_traits::ToCss; use values::HasViewportPercentage; -use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue}; -use values::specified::{LengthOrPercentage, Percentage}; +use values::computed::{Context, ToComputedValue}; -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 -} - -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 { - fn from(val: Keyword) -> LengthOrPercentage { - match val { - Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)), - Keyword::Left | Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)), - Keyword::Right | Keyword::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)), - // FIXME(canaltinova): Support logical keywords - Keyword::XStart | Keyword::YStart => LengthOrPercentage::Percentage(Percentage(0.0)), - Keyword::XEnd | Keyword::YEnd => LengthOrPercentage::Percentage(Percentage(1.0)), - } - } -} - -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -/// A generic type for representing horizontal or vertical `<position>` value. -pub struct PositionValue<L> { - /// Even though this is generic, it's always a `<length-percentage>` value. - pub position: Option<L>, - /// A position keyword. - pub keyword: Option<Keyword>, -} - -impl<L: HasViewportPercentage> HasViewportPercentage for PositionValue<L> { - #[inline] - fn has_viewport_percentage(&self) -> bool { - self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage()) - } -} - -impl<L: Parse> PositionValue<L> { - /// Internal parsing function which (after parsing) checks the keyword with the - /// given function. - pub fn parse_internal<F>(context: &ParserContext, input: &mut Parser, - mut is_allowed_keyword: F) -> Result<PositionValue<L>, ()> - where F: FnMut(Keyword) -> bool - { - let (mut pos, mut keyword) = (None, None); - for _ in 0..2 { - if let Ok(l) = input.try(|i| L::parse(context, i)) { - if pos.is_some() { - return Err(()) - } - - pos = Some(l); - } - - if let Ok(k) = input.try(Keyword::parse) { - if keyword.is_some() || !is_allowed_keyword(k) { - return Err(()) - } - - keyword = Some(k); - } - } - - if pos.is_some() { - if let Some(Keyword::Center) = keyword { - return Err(()) // "center" and <length> is not allowed - } - } else if keyword.is_none() { - return Err(()) // at least one value is necessary - } - - Ok(PositionValue { - position: pos, - keyword: keyword, - }) - } -} - -impl<L: ToCss> ToCss for PositionValue<L> { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - if let Some(keyword) = self.keyword { - keyword.to_css(dest)?; - } - - if let Some(ref position) = self.position { - if self.keyword.is_some() { - dest.write_str(" ")?; - } - - position.to_css(dest)?; - } - - Ok(()) - } -} - -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -/// A generic type for representing horizontal `<position>` -pub struct HorizontalPosition<L>(pub L); - -impl<L: ToCss> ToCss for HorizontalPosition<L> { - #[inline] - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } -} - -impl<L: HasViewportPercentage> HasViewportPercentage for HorizontalPosition<L> { - #[inline] - fn has_viewport_percentage(&self) -> bool { - self.0.has_viewport_percentage() - } -} - -impl<L: Parse> Parse for HorizontalPosition<PositionValue<L>> { - #[inline] - fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - PositionValue::parse_internal(context, input, |keyword| { - matches!{ keyword, - Keyword::Left | Keyword::Right | Keyword::Center | - Keyword::XStart | Keyword::XEnd - } - }).map(HorizontalPosition) - } -} - -#[derive(Debug, Clone, PartialEq)] -#[cfg_attr(feature = "servo", derive(HeapSizeOf))] -/// A generic type for representing vertical `<position>` -pub struct VerticalPosition<L>(pub L); - -impl<L: ToCss> ToCss for VerticalPosition<L> { - #[inline] - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.0.to_css(dest) - } -} - -impl<L: HasViewportPercentage> HasViewportPercentage for VerticalPosition<L> { - #[inline] - fn has_viewport_percentage(&self) -> bool { - self.0.has_viewport_percentage() - } -} - -impl<L: Parse> Parse for VerticalPosition<PositionValue<L>> { - #[inline] - fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - PositionValue::parse_internal(context, input, |keyword| { - matches!{ keyword, - Keyword::Top | Keyword::Bottom | Keyword::Center | - Keyword::YStart | Keyword::YEnd - } - }).map(VerticalPosition) - } -} - -#[derive(Debug, Clone, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] /// A generic type for representing a CSS [position](https://drafts.csswg.org/css-values/#position). -/// -/// Note that the horizontal and vertical positions aren't really different types. -/// They're just unit struct wrappers over `LengthOrPercentage`. They should be different -/// because they allow different keywords (for e.g., vertical position doesn't allow -/// `right` or `left` keywords and vice versa). pub struct Position<H, V> { /// The horizontal component of position. pub horizontal: H, @@ -237,8 +18,15 @@ pub struct Position<H, V> { pub vertical: V, } -/// A generic type for representing positions with keywords. -pub type PositionWithKeyword<L> = Position<HorizontalPosition<L>, VerticalPosition<L>>; +impl<H, V> Position<H, V> { + /// Returns a new position. + pub fn new(horizontal: H, vertical: V) -> Self { + Self { + horizontal: horizontal, + vertical: vertical, + } + } +} impl<H: HasViewportPercentage, V: HasViewportPercentage> HasViewportPercentage for Position<H, V> { #[inline] @@ -247,42 +35,9 @@ impl<H: HasViewportPercentage, V: HasViewportPercentage> HasViewportPercentage f } } -impl<L: ToCss> ToCss for Position<L, L> { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - self.horizontal.to_css(dest)?; - dest.write_str(" ")?; - self.vertical.to_css(dest) - } -} - -impl<L: ToCss> ToCss for PositionWithKeyword<PositionValue<L>> { - fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { - macro_rules! to_css_with_keyword { - ($pos:expr, $default:expr) => { - $pos.keyword.unwrap_or($default).to_css(dest)?; - if let Some(ref position) = $pos.position { - dest.write_str(" ")?; - position.to_css(dest)?; - } - } - } - - if (self.horizontal.0.keyword.is_some() && self.horizontal.0.position.is_some()) || - (self.vertical.0.keyword.is_some() && self.vertical.0.position.is_some()) { - to_css_with_keyword!(self.horizontal.0, Keyword::Left); - dest.write_str(" ")?; - to_css_with_keyword!(self.vertical.0, Keyword::Top); - return Ok(()) - } - - self.horizontal.to_css(dest)?; - dest.write_str(" ")?; - self.vertical.to_css(dest) - } -} - impl<H: ToComputedValue, V: ToComputedValue> ToComputedValue for Position<H, V> { - type ComputedValue = Position<H::ComputedValue, V::ComputedValue>; + type ComputedValue = Position<<H as ToComputedValue>::ComputedValue, + <V as ToComputedValue>::ComputedValue>; #[inline] fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { @@ -294,7 +49,7 @@ impl<H: ToComputedValue, V: ToComputedValue> ToComputedValue for Position<H, V> #[inline] fn from_computed_value(computed: &Self::ComputedValue) -> Self { - Position { + Self { horizontal: ToComputedValue::from_computed_value(&computed.horizontal), vertical: ToComputedValue::from_computed_value(&computed.vertical), } diff --git a/components/style/values/specified/basic_shape.rs b/components/style/values/specified/basic_shape.rs index 9d1176dad70..94d006f6033 100644 --- a/components/style/values/specified/basic_shape.rs +++ b/components/style/values/specified/basic_shape.rs @@ -11,6 +11,7 @@ use cssparser::Parser; use parser::{Parse, ParserContext}; use properties::shorthands::parse_four_sides; use std::ascii::AsciiExt; +use std::borrow::Cow; use std::fmt; use style_traits::ToCss; use values::HasViewportPercentage; @@ -19,8 +20,8 @@ use values::computed::basic_shape as computed_basic_shape; use values::generics::BorderRadiusSize; use values::generics::basic_shape::{BorderRadius as GenericBorderRadius, ShapeRadius as GenericShapeRadius}; use values::generics::basic_shape::{InsetRect as GenericInsetRect, Polygon as GenericPolygon, ShapeSource}; -use values::specified::{LengthOrPercentage, Percentage}; -use values::specified::position::{Keyword, Position}; +use values::specified::{LengthOrPercentage, Percentage, Position, PositionComponent}; +use values::specified::position::Side; /// The specified value used by `clip-path` pub type ShapeWithGeometryBox = ShapeSource<BasicShape, GeometryBox>; @@ -138,75 +139,62 @@ impl Parse for InsetRect { fn serialize_basicshape_position<W>(position: &Position, dest: &mut W) -> fmt::Result where W: fmt::Write { - // 0 length should be replaced with 0% - fn replace_with_percent(input: LengthOrPercentage) -> LengthOrPercentage { - match input { - LengthOrPercentage::Length(ref l) if l.is_zero() => - LengthOrPercentage::Percentage(Percentage(0.0)), - _ => input + fn to_keyword_and_lop<S>(component: &PositionComponent<S>) -> (S, Cow<LengthOrPercentage>) + where S: Copy + Side + { + match *component { + PositionComponent::Center => { + (S::start(), Cow::Owned(LengthOrPercentage::Percentage(Percentage(0.5)))) + }, + PositionComponent::Side(keyword, None) => { + // left | top => 0% + // right | bottom => 100% + let p = if keyword.is_start() { 0. } else { 1. }; + (S::start(), Cow::Owned(LengthOrPercentage::Percentage(Percentage(p)))) + }, + PositionComponent::Side(keyword, Some(ref lop)) if !keyword.is_start() => { + if let LengthOrPercentage::Percentage(p) = *to_non_zero_length(lop) { + (S::start(), Cow::Owned(LengthOrPercentage::Percentage(Percentage(1. - p.0)))) + } else { + (keyword, Cow::Borrowed(lop)) + } + }, + PositionComponent::Length(ref lop) | + PositionComponent::Side(_, Some(ref lop)) => { + (S::start(), to_non_zero_length(lop)) + }, } } - // keyword-percentage pairs can be folded into a single percentage - fn fold_keyword(keyword: Option<Keyword>, - length: Option<LengthOrPercentage>) -> Option<LengthOrPercentage> { - let is_length_none = length.is_none(); - let pc = match length.map(replace_with_percent) { - Some(LengthOrPercentage::Percentage(pc)) => pc, - None => Percentage(0.0), // unspecified length = 0% - _ => return None - }; - - let percent = match keyword { - Some(Keyword::Center) => { - assert!(is_length_none); // center cannot pair with lengths - Percentage(0.5) + fn to_non_zero_length(lop: &LengthOrPercentage) -> Cow<LengthOrPercentage> { + match *lop { + LengthOrPercentage::Length(ref l) if l.is_zero() => { + Cow::Owned(LengthOrPercentage::Percentage(Percentage(0.))) }, - Some(Keyword::Left) | Some(Keyword::Top) | None => pc, - Some(Keyword::Right) | Some(Keyword::Bottom) => Percentage(1.0 - pc.0), - _ => return None, - }; - - Some(LengthOrPercentage::Percentage(percent)) + _ => { + Cow::Borrowed(lop) + } + } } - fn serialize_position_pair<W>(x: LengthOrPercentage, y: LengthOrPercentage, - dest: &mut W) -> fmt::Result where W: fmt::Write { - replace_with_percent(x).to_css(dest)?; + fn write_pair<A, B, W>(a: &A, b: &B, dest: &mut W) -> fmt::Result + where A: ToCss, B: ToCss, W: fmt::Write + { + a.to_css(dest)?; dest.write_str(" ")?; - replace_with_percent(y).to_css(dest) + b.to_css(dest) } - match (position.horizontal.0.keyword, position.horizontal.0.position.clone(), - position.vertical.0.keyword, position.vertical.0.position.clone()) { - (Some(hk), None, Some(vk), None) => { - // two keywords: serialize as two lengths - serialize_position_pair(hk.into(), vk.into(), dest) - } - (None, Some(hp), None, Some(vp)) => { - // two lengths: just serialize regularly - serialize_position_pair(hp, vp, dest) - } - (hk, hp, vk, vp) => { - // only fold if both fold; the three-value form isn't - // allowed here. - if let (Some(x), Some(y)) = (fold_keyword(hk, hp.clone()), - fold_keyword(vk, vp.clone())) { - serialize_position_pair(x, y, dest) - } else { - // We failed to reduce it to a two-value form, - // so we expand it to 4-value - let zero = LengthOrPercentage::Percentage(Percentage(0.0)); - hk.unwrap_or(Keyword::Left).to_css(dest)?; - dest.write_str(" ")?; - replace_with_percent(hp.unwrap_or(zero.clone())).to_css(dest)?; - dest.write_str(" ")?; - vk.unwrap_or(Keyword::Top).to_css(dest)?; - dest.write_str(" ")?; - replace_with_percent(vp.unwrap_or(zero)).to_css(dest) - } - } + let (x_pos, x_lop) = to_keyword_and_lop(&position.horizontal); + let (y_pos, y_lop) = to_keyword_and_lop(&position.vertical); + + if x_pos.is_start() && y_pos.is_start() { + return write_pair(&*x_lop, &*y_lop, dest); } + + write_pair(&x_pos, &*x_lop, dest)?; + dest.write_str(" ")?; + write_pair(&y_pos, &*y_lop, dest) } #[derive(Clone, PartialEq, Debug)] diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index 3062e3bfff0..a14b6ca2e62 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -36,7 +36,7 @@ pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWi pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto}; pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength}; pub use self::length::{MaxLength, MinLength}; -pub use self::position::{HorizontalPosition, Position, VerticalPosition}; +pub use self::position::{Position, PositionComponent}; #[cfg(feature = "gecko")] pub mod align; diff --git a/components/style/values/specified/position.rs b/components/style/values/specified/position.rs index dfa05b36609..678d2a8777d 100644 --- a/components/style/values/specified/position.rs +++ b/components/style/values/specified/position.rs @@ -7,278 +7,297 @@ //! //! [position]: https://drafts.csswg.org/css-backgrounds-3/#position -use app_units::Au; use cssparser::Parser; use parser::{Parse, ParserContext}; -use properties::longhands::parse_origin; -use std::mem; -use values::Either; -use values::computed::{CalcLengthOrPercentage, Context}; +use std::fmt; +use style_traits::ToCss; +use values::HasViewportPercentage; +use values::computed::{CalcLengthOrPercentage, ComputedValueAsSpecified, Context}; use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, ToComputedValue}; -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::generics::position::Position as GenericPosition; use values::specified::{AllowQuirks, LengthOrPercentage, Percentage}; -pub use values::generics::position::Keyword; - /// The specified value of a CSS `<position>` -pub type Position = PositionWithKeyword<PositionValue<LengthOrPercentage>>; +pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>; + +/// The specified value of a horizontal position. +pub type HorizontalPosition = PositionComponent<X>; + +/// The specified value of a vertical position. +pub type VerticalPosition = PositionComponent<Y>; + +/// The specified value of a component of a CSS `<position>`. +#[cfg_attr(feature = "servo", derive(HeapSizeOf))] +#[derive(Clone, Debug, PartialEq)] +pub enum PositionComponent<S> { + /// `center` + Center, + /// `<lop>` + Length(LengthOrPercentage), + /// `<side> <lop>?` + Side(S, Option<LengthOrPercentage>), +} -/// The specified value for `<position>` values without a keyword. -pub type OriginPosition = GenericPosition<LengthOrPercentage, LengthOrPercentage>; +define_css_keyword_enum! { X: + "left" => Left, + "right" => Right, +} +add_impls_for_keyword_enum!(X); + +define_css_keyword_enum! { Y: + "top" => Top, + "bottom" => Bottom, +} +add_impls_for_keyword_enum!(Y); -impl Parse for OriginPosition { +impl Parse for Position { 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))), - }) - } + Self::parse_quirky(context, input, AllowQuirks::No) } } -type PositionComponent = Either<LengthOrPercentage, Keyword>; - impl Position { - /// Create a new position value from either a length or a keyword. - pub fn from_components(mut first_position: Option<PositionComponent>, - mut second_position: Option<PositionComponent>, - first_keyword: Option<PositionComponent>, - second_keyword: Option<PositionComponent>) -> Result<Position, ()> { - // Unwrap for checking if values are at right place. - let first_key = first_keyword.clone().unwrap_or(Either::Second(Keyword::Left)); - let second_key = second_keyword.clone().unwrap_or(Either::Second(Keyword::Top)); - - let (horiz_keyword, vert_keyword) = match (&first_key, &second_key) { - // Check if a position is specified after center keyword. - (&Either::Second(Keyword::Center), _) if first_position.is_some() => return Err(()), - (_, &Either::Second(Keyword::Center)) if second_position.is_some() => return Err(()), - - // Check first and second keywords for both 2 and 4 value positions. - - // FIXME(canaltinova): Allow logical keywords for Position. They are not in current spec yet. - (&Either::Second(k), _) if k.is_logical() => return Err(()), - (_, &Either::Second(k)) if k.is_logical() => 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. - (&Either::Second(k1), &Either::Second(k2)) - if (k1.is_vertical() && k2.is_horizontal()) || (k1.is_vertical() && k2 == Keyword::Center) || - (k1 == Keyword::Center && k2.is_horizontal()) => { - mem::swap(&mut first_position, &mut second_position); - (second_keyword, first_keyword) + /// Parses a `<position>`, with quirks. + pub fn parse_quirky(context: &ParserContext, + input: &mut Parser, + allow_quirks: AllowQuirks) + -> Result<Self, ()> { + match input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { + Ok(x_pos @ PositionComponent::Center) => { + if let Ok(y_pos) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { + return Ok(Self::new(x_pos, y_pos)); + } + let x_pos = input + .try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) + .unwrap_or(x_pos); + let y_pos = PositionComponent::Center; + return Ok(Self::new(x_pos, y_pos)); }, - - // By default, horizontal is first. - _ => (first_keyword, second_keyword), - }; - - let (mut h_pos, mut h_key, mut v_pos, mut v_key) = (None, None, None, None); - if let Some(Either::First(l)) = first_position { - h_pos = Some(l); + Ok(PositionComponent::Side(x_keyword, lop)) => { + if input.try(|i| i.expect_ident_matching("center")).is_ok() { + let x_pos = PositionComponent::Side(x_keyword, lop); + let y_pos = PositionComponent::Center; + return Ok(Self::new(x_pos, y_pos)); + } + if let Ok(y_keyword) = input.try(Y::parse) { + let y_lop = input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok(); + let x_pos = PositionComponent::Side(x_keyword, lop); + let y_pos = PositionComponent::Side(y_keyword, y_lop); + return Ok(Self::new(x_pos, y_pos)); + } + let x_pos = PositionComponent::Side(x_keyword, None); + let y_pos = lop.map_or(PositionComponent::Center, PositionComponent::Length); + return Ok(Self::new(x_pos, y_pos)); + }, + Ok(x_pos @ PositionComponent::Length(_)) => { + if let Ok(y_keyword) = input.try(Y::parse) { + let y_pos = PositionComponent::Side(y_keyword, None); + return Ok(Self::new(x_pos, y_pos)); + } + if let Ok(y_lop) = input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) { + let y_pos = PositionComponent::Length(y_lop); + return Ok(Self::new(x_pos, y_pos)); + } + let y_pos = PositionComponent::Center; + let _ = input.try(|i| i.expect_ident_matching("center")); + return Ok(Self::new(x_pos, y_pos)); + }, + Err(_) => {}, } - - if let Some(Either::First(l)) = second_position { - v_pos = Some(l); + let y_keyword = Y::parse(input)?; + let lop_and_x_pos: Result<_, ()> = input.try(|i| { + let y_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok(); + if let Ok(x_keyword) = i.try(X::parse) { + let x_lop = i.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok(); + let x_pos = PositionComponent::Side(x_keyword, x_lop); + return Ok((y_lop, x_pos)); + } + i.expect_ident_matching("center")?; + let x_pos = PositionComponent::Center; + Ok((y_lop, x_pos)) + }); + if let Ok((y_lop, x_pos)) = lop_and_x_pos { + let y_pos = PositionComponent::Side(y_keyword, y_lop); + return Ok(Self::new(x_pos, y_pos)); } + let x_pos = PositionComponent::Center; + let y_pos = PositionComponent::Side(y_keyword, None); + Ok(Self::new(x_pos, y_pos)) + } - if let Some(Either::Second(k)) = horiz_keyword { - h_key = Some(k); - } + /// `center center` + #[inline] + pub fn center() -> Self { + Self::new(PositionComponent::Center, PositionComponent::Center) + } +} - if let Some(Either::Second(k)) = vert_keyword { - v_key = Some(k); +impl ToCss for Position { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match (&self.horizontal, &self.vertical) { + (x_pos @ &PositionComponent::Side(_, Some(_)), &PositionComponent::Length(ref y_lop)) => { + x_pos.to_css(dest)?; + dest.write_str(" top ")?; + y_lop.to_css(dest) + }, + (&PositionComponent::Length(ref x_lop), y_pos @ &PositionComponent::Side(_, Some(_))) => { + dest.write_str("left ")?; + x_lop.to_css(dest)?; + dest.write_str(" ")?; + y_pos.to_css(dest) + }, + (x_pos, y_pos) => { + x_pos.to_css(dest)?; + dest.write_str(" ")?; + y_pos.to_css(dest) + }, } - - Ok(Position { - horizontal: GenericHorizontalPosition(PositionValue { - keyword: h_key, - position: h_pos, - }), - vertical: GenericVerticalPosition(PositionValue { - keyword: v_key, - position: v_pos, - }), - }) } +} - /// Returns a "centered" position, as in "center center". - pub fn center() -> Position { - Position { - horizontal: GenericHorizontalPosition(PositionValue { - keyword: Some(Keyword::Center), - position: None, - }), - vertical: GenericVerticalPosition(PositionValue { - keyword: Some(Keyword::Center), - position: None, - }), +impl<S> HasViewportPercentage for PositionComponent<S> { + fn has_viewport_percentage(&self) -> bool { + match *self { + PositionComponent::Length(ref lop) | + PositionComponent::Side(_, Some(ref lop)) => { + lop.has_viewport_percentage() + }, + _ => false, } } } -impl Parse for Position { +impl<S: Parse> Parse for PositionComponent<S> { fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> { - Position::parse_quirky(context, input, AllowQuirks::No) + Self::parse_quirky(context, input, AllowQuirks::No) } } -impl Position { - /// Parses, with quirks. +impl<S: Parse> PositionComponent<S> { + /// Parses a component of a CSS position, with quirks. pub fn parse_quirky(context: &ParserContext, input: &mut Parser, allow_quirks: AllowQuirks) -> Result<Self, ()> { - let first = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks))?; - let second = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) - .unwrap_or(Either::Second(Keyword::Center)); - - if let Ok(third) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { - // There's a 3rd value. - if let Ok(fourth) = input.try(|i| PositionComponent::parse_quirky(context, i, allow_quirks)) { - // There's a 4th value. - Position::from_components(Some(second), Some(fourth), Some(first), Some(third)) - } 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" - (&Either::First(_), _) => Position::from_components(Some(second), None, - Some(first), Some(third)), - // "keyword keyword length" - _ => Position::from_components(None, Some(third), Some(first), Some(second)), - } - } - } else { - // only 2 values. - match (&first, &second) { - (&Either::First(_), &Either::First(_)) => - Position::from_components(Some(first), Some(second), None, None), - (&Either::First(_), &Either::Second(_)) => - Position::from_components(Some(first), None, None, Some(second)), - (&Either::Second(_), &Either::First(_)) => - Position::from_components(None, Some(second), Some(first), None), - (&Either::Second(_), &Either::Second(_)) => - Position::from_components(None, None, Some(first), Some(second)), - } + if input.try(|i| i.expect_ident_matching("center")).is_ok() { + return Ok(PositionComponent::Center); + } + if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) { + return Ok(PositionComponent::Length(lop)); } + let keyword = S::parse(context, input)?; + let lop = input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)).ok(); + Ok(PositionComponent::Side(keyword, lop)) } } -impl PositionComponent { - /// Parses, with quirks. - fn parse_quirky(context: &ParserContext, - input: &mut Parser, - allow_quirks: AllowQuirks) -> Result<Self, ()> { - input.try(|i| LengthOrPercentage::parse_quirky(context, i, allow_quirks)) - .map(Either::First) - .or_else(|()| input.try(Keyword::parse).map(Either::Second)) +impl<S> PositionComponent<S> { + /// `0%` + pub fn zero() -> Self { + PositionComponent::Length(LengthOrPercentage::Percentage(Percentage(0.))) } } -impl PositionValue<LengthOrPercentage> { - /// Generic function for the computed value of a position. - fn computed_value(&self, context: &Context) -> ComputedLengthOrPercentage { - match self.keyword { - Some(Keyword::Center) => ComputedLengthOrPercentage::Percentage(0.5), - Some(k) if k.is_other_side() => match self.position { - Some(ref x) => { - 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 - }) - }, - None => ComputedLengthOrPercentage::Percentage(1.0), +impl<S: ToCss> ToCss for PositionComponent<S> { + fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + PositionComponent::Center => { + dest.write_str("center") + }, + PositionComponent::Length(ref lop) => { + lop.to_css(dest) + }, + PositionComponent::Side(ref keyword, ref lop) => { + keyword.to_css(dest)?; + if let Some(ref lop) = *lop { + dest.write_str(" ")?; + lop.to_css(dest)?; + } + Ok(()) }, - _ => 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 { - type ComputedValue = computed_position::HorizontalPosition; +impl<S: Side> ToComputedValue for PositionComponent<S> { + type ComputedValue = ComputedLengthOrPercentage; - #[inline] - fn to_computed_value(&self, context: &Context) -> computed_position::HorizontalPosition { - GenericHorizontalPosition(self.0.computed_value(context)) + fn to_computed_value(&self, context: &Context) -> Self::ComputedValue { + match *self { + PositionComponent::Center => { + ComputedLengthOrPercentage::Percentage(0.5) + }, + PositionComponent::Side(ref keyword, None) => { + let p = if keyword.is_start() { 0. } else { 1. }; + ComputedLengthOrPercentage::Percentage(p) + }, + PositionComponent::Side(ref keyword, Some(ref length)) if !keyword.is_start() => { + match length.to_computed_value(context) { + ComputedLengthOrPercentage::Length(length) => { + ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage { + length: -length, + percentage: Some(1.0), + }) + }, + ComputedLengthOrPercentage::Percentage(p) => { + ComputedLengthOrPercentage::Percentage(1.0 - p) + }, + ComputedLengthOrPercentage::Calc(calc) => { + ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage { + length: -calc.length, + percentage: Some(1.0 - calc.percentage.unwrap_or(0.)), + }) + }, + } + }, + PositionComponent::Side(_, Some(ref length)) | + PositionComponent::Length(ref length) => { + length.to_computed_value(context) + }, + } } - #[inline] - fn from_computed_value(computed: &computed_position::HorizontalPosition) -> HorizontalPosition { - GenericHorizontalPosition(PositionValue { - keyword: None, - position: Some(ToComputedValue::from_computed_value(&computed.0)), - }) + fn from_computed_value(computed: &Self::ComputedValue) -> Self { + PositionComponent::Length(ToComputedValue::from_computed_value(computed)) } } -impl HorizontalPosition { - #[inline] - /// Initial specified value for vertical position (`top` keyword). - pub fn left() -> HorizontalPosition { - GenericHorizontalPosition(PositionValue { - keyword: Some(Keyword::Left), - position: None, - }) +impl<S: Side> PositionComponent<S> { + /// The initial specified value of a position component, i.e. the start side. + pub fn initial_specified_value() -> Self { + PositionComponent::Side(S::start(), None) } } +/// Represents a side, either horizontal or vertical, of a CSS position. +pub trait Side { + /// Returns the start side. + fn start() -> Self; -/// The specified value of vertical `<position>` -pub type VerticalPosition = GenericVerticalPosition<PositionValue<LengthOrPercentage>>; - -impl ToComputedValue for VerticalPosition { - type ComputedValue = computed_position::VerticalPosition; + /// Returns whether this side is the start side. + fn is_start(&self) -> bool; +} +impl Side for X { #[inline] - fn to_computed_value(&self, context: &Context) -> computed_position::VerticalPosition { - GenericVerticalPosition(self.0.computed_value(context)) + fn start() -> Self { + X::Left } #[inline] - fn from_computed_value(computed: &computed_position::VerticalPosition) -> VerticalPosition { - GenericVerticalPosition(PositionValue { - keyword: None, - position: Some(ToComputedValue::from_computed_value(&computed.0)), - }) + fn is_start(&self) -> bool { + *self == X::Left } } -impl VerticalPosition { +impl Side for Y { + #[inline] + fn start() -> Self { + Y::Top + } + #[inline] - /// Initial specified value for vertical position (`top` keyword). - pub fn top() -> VerticalPosition { - GenericVerticalPosition(PositionValue { - keyword: Some(Keyword::Top), - position: None, - }) + fn is_start(&self) -> bool { + *self == Y::Top } } diff --git a/tests/unit/style/parsing/basic_shape.rs b/tests/unit/style/parsing/basic_shape.rs index ead6b4bb7b0..3cef9ca1803 100644 --- a/tests/unit/style/parsing/basic_shape.rs +++ b/tests/unit/style/parsing/basic_shape.rs @@ -124,7 +124,7 @@ fn test_circle() { assert_roundtrip_basicshape!(Circle::parse, "circle(at right 5% bottom 0px)", "circle(at 95% 100%)"); assert_roundtrip_basicshape!(Circle::parse, "circle(at right 5% bottom 1px)", - "circle(at right 5% bottom 1px)"); + "circle(at left 95% bottom 1px)"); assert!(parse(Circle::parse, "circle(at 5% bottom 1px)").is_err()); assert!(parse(Circle::parse, "circle(at top 40%)").is_err()); diff --git a/tests/unit/style/parsing/mod.rs b/tests/unit/style/parsing/mod.rs index 6ba2043bd95..18d85953a58 100644 --- a/tests/unit/style/parsing/mod.rs +++ b/tests/unit/style/parsing/mod.rs @@ -20,6 +20,10 @@ fn parse<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F, s: &str) f(&context, &mut parser) } +fn parse_entirely<T, F: Fn(&ParserContext, &mut Parser) -> Result<T, ()>>(f: F, s: &str) -> Result<T, ()> { + parse(|context, parser| parser.parse_entirely(|p| f(context, p)), s) +} + // This is a macro so that the file/line information // is preserved in the panic macro_rules! assert_roundtrip_with_context { diff --git a/tests/unit/style/parsing/position.rs b/tests/unit/style/parsing/position.rs index e5e8aa6379d..7a3bfe1bae3 100644 --- a/tests/unit/style/parsing/position.rs +++ b/tests/unit/style/parsing/position.rs @@ -2,7 +2,7 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ -use parsing::parse; +use parsing::{parse, parse_entirely}; use style::parser::Parse; use style::values::specified::position::*; use style_traits::ToCss; @@ -28,8 +28,8 @@ fn test_position() { assert_roundtrip_with_context!(Position::parse, "right 10%", "right 10%"); // Only keywords can be reordered - assert!(parse(Position::parse, "top 40%").is_err()); - assert!(parse(Position::parse, "40% left").is_err()); + assert!(parse_entirely(Position::parse, "top 40%").is_err()); + assert!(parse_entirely(Position::parse, "40% left").is_err()); // 3 and 4 value serialization assert_roundtrip_with_context!(Position::parse, "left 10px top 15px", "left 10px top 15px"); @@ -46,31 +46,31 @@ fn test_position() { assert_roundtrip_with_context!(Position::parse, "center bottom 10px", "center bottom 10px"); // Invalid 3 value positions - assert!(parse(Position::parse, "20px 30px 20px").is_err()); - assert!(parse(Position::parse, "top 30px 20px").is_err()); - assert!(parse(Position::parse, "50% bottom 20%").is_err()); + assert!(parse_entirely(Position::parse, "20px 30px 20px").is_err()); + assert!(parse_entirely(Position::parse, "top 30px 20px").is_err()); + assert!(parse_entirely(Position::parse, "50% bottom 20%").is_err()); // Only horizontal and vertical keywords can have positions - assert!(parse(Position::parse, "center 10px left 15px").is_err()); - assert!(parse(Position::parse, "center 10px 15px").is_err()); - assert!(parse(Position::parse, "center 10px bottom").is_err()); + assert!(parse_entirely(Position::parse, "center 10px left 15px").is_err()); + assert!(parse_entirely(Position::parse, "center 10px 15px").is_err()); + assert!(parse_entirely(Position::parse, "center 10px bottom").is_err()); // "Horizontal Horizontal" or "Vertical Vertical" positions cause error - assert!(parse(Position::parse, "left right").is_err()); - assert!(parse(Position::parse, "left 10px right").is_err()); - assert!(parse(Position::parse, "left 10px right 15%").is_err()); - assert!(parse(Position::parse, "top bottom").is_err()); - assert!(parse(Position::parse, "top 10px bottom").is_err()); - assert!(parse(Position::parse, "top 10px bottom 15%").is_err()); - - // Logical keywords are not supported in Position yet + assert!(parse_entirely(Position::parse, "left right").is_err()); + assert!(parse_entirely(Position::parse, "left 10px right").is_err()); + assert!(parse_entirely(Position::parse, "left 10px right 15%").is_err()); + assert!(parse_entirely(Position::parse, "top bottom").is_err()); + assert!(parse_entirely(Position::parse, "top 10px bottom").is_err()); + assert!(parse_entirely(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_entirely(Position::parse, "left y-start 10%").is_err()); assert!(parse(Position::parse, "x-start 20px y-end 10%").is_err()); } @@ -82,29 +82,31 @@ fn test_horizontal_position() { 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()); + assert!(parse_entirely(HorizontalPosition::parse, "20px y-end").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "20px top").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "left center").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "left top").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "left right").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "20px 30px").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "10px left").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "x-end 20%").is_err()); + assert!(parse_entirely(HorizontalPosition::parse, "20px x-start").is_err()); + + // Logical keywords are not supported in Position yet. + assert!(parse(HorizontalPosition::parse, "x-start").is_err()); + assert!(parse(HorizontalPosition::parse, "x-end").is_err()); } #[test] @@ -115,29 +117,31 @@ fn test_vertical_position() { 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, "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()); + assert!(parse_entirely(VerticalPosition::parse, "20px x-end").is_err()); + assert!(parse_entirely(VerticalPosition::parse, "20px right").is_err()); + assert!(parse_entirely(VerticalPosition::parse, "bottom top").is_err()); + assert!(parse_entirely(VerticalPosition::parse, "20px 30px").is_err()); + assert!(parse_entirely(VerticalPosition::parse, "10px top").is_err()); + assert!(parse_entirely(VerticalPosition::parse, "y-end 20%").is_err()); + assert!(parse_entirely(VerticalPosition::parse, "20px y-start").is_err()); + + // Logical keywords are not supported in Position yet. + assert!(parse(VerticalPosition::parse, "y-start").is_err()); + assert!(parse(VerticalPosition::parse, "y-end").is_err()); } #[test] diff --git a/tests/unit/style/parsing/value.rs b/tests/unit/style/parsing/value.rs index 637a6131912..2151529a293 100644 --- a/tests/unit/style/parsing/value.rs +++ b/tests/unit/style/parsing/value.rs @@ -3,7 +3,6 @@ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ use app_units::Au; -use parsing::parse; use style::values::HasViewportPercentage; use style::values::specified::{AbsoluteLength, NoCalcLength, ViewportPercentageLength}; diff --git a/tests/unit/style/properties/serialization.rs b/tests/unit/style/properties/serialization.rs index 0e89e22cde4..f164b656ce1 100644 --- a/tests/unit/style/properties/serialization.rs +++ b/tests/unit/style/properties/serialization.rs @@ -9,8 +9,10 @@ use style::properties::longhands::outline_color::computed_value::T as ComputedCo use style::properties::parse_property_declaration_list; use style::values::{RGBA, Auto}; use style::values::CustomIdent; -use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length, NoCalcLength}; -use style::values::specified::{LengthOrPercentage, LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent}; +use style::values::specified::{BorderStyle, BorderWidth, CSSColor, Length, LengthOrPercentage}; +use style::values::specified::{LengthOrPercentageOrAuto, LengthOrPercentageOrAutoOrContent}; +use style::values::specified::{NoCalcLength, PositionComponent}; +use style::values::specified::position::Y; use style::values::specified::url::SpecifiedUrl; use style_traits::ToCss; use stylesheets::block_from; @@ -796,7 +798,6 @@ mod shorthand_serialization { use style::properties::longhands::mask_position_y as position_y; use style::properties::longhands::mask_repeat as repeat; use style::properties::longhands::mask_size as size; - use style::values::generics::position::{HorizontalPosition, Keyword, PositionValue, VerticalPosition}; use style::values::specified::Image; use super::*; @@ -833,16 +834,13 @@ mod shorthand_serialization { let mode = single_vec_keyword_value!(mode, luminance); let position_x = single_vec_value_typedef!(position_x, - HorizontalPosition(PositionValue { - keyword: None, - position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))), - }) + PositionComponent::Length(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))) ); let position_y = single_vec_value_typedef!(position_y, - VerticalPosition(PositionValue { - keyword: Some(Keyword::Bottom), - position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))), - }) + PositionComponent::Side( + Y::Bottom, + Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))), + ) ); let size = single_vec_variant_value!(size, @@ -888,17 +886,11 @@ mod shorthand_serialization { let mode = single_vec_keyword_value!(mode, luminance); let position_x = single_vec_value_typedef!(position_x, - HorizontalPosition(PositionValue { - keyword: None, - position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))), - }) + PositionComponent::Length(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))) ); let position_y = single_vec_value_typedef!(position_y, - VerticalPosition(PositionValue { - keyword: None, - position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))), - }) + PositionComponent::Length(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))) ); let size = single_vec_variant_value!(size, diff --git a/tests/unit/style/stylesheets.rs b/tests/unit/style/stylesheets.rs index e87bfeb95b8..64bbcf1874f 100644 --- a/tests/unit/style/stylesheets.rs +++ b/tests/unit/style/stylesheets.rs @@ -25,7 +25,7 @@ use style::stylearc::Arc; use style::stylesheets::{Origin, Namespaces}; use style::stylesheets::{Stylesheet, NamespaceRule, CssRule, CssRules, StyleRule, KeyframesRule}; use style::values::{KeyframesName, CustomIdent}; -use style::values::specified::{LengthOrPercentageOrAuto, Percentage}; +use style::values::specified::{LengthOrPercentageOrAuto, Percentage, PositionComponent}; pub fn block_from<I>(iterable: I) -> PropertyDeclarationBlock where I: IntoIterator<Item=(PropertyDeclaration, Importance)> { @@ -183,13 +183,11 @@ fn test_parse_stylesheet() { Importance::Normal), (PropertyDeclaration::BackgroundPositionX( longhands::background_position_x::SpecifiedValue( - vec![longhands::background_position_x::single_value - ::get_initial_position_value()])), - Importance::Normal), + vec![PositionComponent::zero()])), + Importance::Normal), (PropertyDeclaration::BackgroundPositionY( longhands::background_position_y::SpecifiedValue( - vec![longhands::background_position_y::single_value - ::get_initial_position_value()])), + vec![PositionComponent::zero()])), Importance::Normal), (PropertyDeclaration::BackgroundRepeat( longhands::background_repeat::SpecifiedValue( diff --git a/tests/wpt/mozilla/meta/MANIFEST.json b/tests/wpt/mozilla/meta/MANIFEST.json index 1b33db843e9..154c948b894 100644 --- a/tests/wpt/mozilla/meta/MANIFEST.json +++ b/tests/wpt/mozilla/meta/MANIFEST.json @@ -25371,7 +25371,7 @@ "testharness" ], "mozilla/calc.html": [ - "028fc71bdc9a99d552ba552036d38fb4eef11bc1", + "47507adabc0d3642154b3ed4b1ab64d726fa682d", "testharness" ], "mozilla/canvas.initial.reset.2dstate.html": [ diff --git a/tests/wpt/mozilla/tests/mozilla/calc.html b/tests/wpt/mozilla/tests/mozilla/calc.html index 2f35b363422..d6a1a1a53cf 100644 --- a/tests/wpt/mozilla/tests/mozilla/calc.html +++ b/tests/wpt/mozilla/tests/mozilla/calc.html @@ -142,7 +142,7 @@ var otherProperties = [ ['border-width', 'calc(1px)', 'calc(1px)'], ['border-spacing', 'calc(1px)', 'calc(1px)'], ['transform-origin', 'calc(1px + 0%)', 'calc(1px + 0%) 50% 0px'], - ['perspective-origin', 'calc(1px + 0%)', 'calc(1px + 0%) 50%'], + ['perspective-origin', 'calc(1px + 0%)', 'calc(1px + 0%) center'], ['background-size', 'calc(1px + 0%)', 'calc(1px + 0%) auto'], ['background-position', 'calc(1px + 0%) calc(2px + 0%)', 'calc(1px + 0%) calc(2px + 0%)'], ['border-top-left-radius', 'calc(1px + 0%)', 'calc(1px + 0%) calc(1px + 0%)'], |