aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbors-servo <lbergstrom+bors@mozilla.com>2017-05-10 09:56:17 -0500
committerGitHub <noreply@github.com>2017-05-10 09:56:17 -0500
commitd5efed6c6a3e05f09300a3ed36d0e1254fcb407c (patch)
tree0b36cbf101952b9b9f6b349f5d82c4aca01450b7
parent0040160b38bfef8f4a8c99bf3a0ad85f0b415d4d (diff)
parent70ec61cf01907c064c53563b46ea361b6a0348fe (diff)
downloadservo-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 -->
-rw-r--r--components/layout/display_list_builder.rs8
-rw-r--r--components/style/gecko/conversions.rs13
-rw-r--r--components/style/properties/gecko.mako.rs44
-rw-r--r--components/style/properties/helpers/animated_properties.mako.rs42
-rw-r--r--components/style/properties/longhand/background.mako.rs39
-rw-r--r--components/style/properties/longhand/box.mako.rs6
-rw-r--r--components/style/properties/longhand/svg.mako.rs51
-rw-r--r--components/style/properties/shorthand/background.mako.rs45
-rw-r--r--components/style/properties/shorthand/mask.mako.rs43
-rw-r--r--components/style/values/computed/position.rs61
-rw-r--r--components/style/values/generics/position.rs273
-rw-r--r--components/style/values/specified/basic_shape.rs110
-rw-r--r--components/style/values/specified/mod.rs2
-rw-r--r--components/style/values/specified/position.rs437
-rw-r--r--tests/unit/style/parsing/basic_shape.rs2
-rw-r--r--tests/unit/style/parsing/mod.rs4
-rw-r--r--tests/unit/style/parsing/position.rs82
-rw-r--r--tests/unit/style/parsing/value.rs1
-rw-r--r--tests/unit/style/properties/serialization.rs30
-rw-r--r--tests/unit/style/stylesheets.rs10
-rw-r--r--tests/wpt/mozilla/meta/MANIFEST.json2
-rw-r--r--tests/wpt/mozilla/tests/mozilla/calc.html2
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%)'],