mirror of
https://github.com/servo/servo.git
synced 2025-08-06 06:00:15 +01:00
Auto merge of #16444 - Wafflespeanut:generics, r=emilio
Cleanup various modules and introduce generic types Almost all the types in `values/specified` and `values/computed` share their `ToCss` implementations. The only reason they have duplicated code hanging around is a result of different specified and computed forms for types like `LengthOrPercentage`. This PR makes some of these types *generic* so that we could have a common definition and `ToCss` impl (`Parse` and `ToComputedValue` impls too, if possible). <!-- 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/16444) <!-- Reviewable:end -->
This commit is contained in:
commit
3c7c960e11
26 changed files with 1168 additions and 1535 deletions
|
@ -16,6 +16,7 @@ use style::logical_geometry::{LogicalMargin, WritingMode};
|
||||||
use style::properties::ServoComputedValues;
|
use style::properties::ServoComputedValues;
|
||||||
use style::values::computed::{BorderRadiusSize, LengthOrPercentageOrAuto};
|
use style::values::computed::{BorderRadiusSize, LengthOrPercentageOrAuto};
|
||||||
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrNone};
|
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrNone};
|
||||||
|
use style::values::generics;
|
||||||
|
|
||||||
/// A collapsible margin. See CSS 2.1 § 8.3.1.
|
/// A collapsible margin. See CSS 2.1 § 8.3.1.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -478,7 +479,7 @@ pub fn specified(length: LengthOrPercentage, containing_length: Au) -> Au {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn specified_border_radius(radius: BorderRadiusSize, containing_length: Au) -> Size2D<Au> {
|
pub fn specified_border_radius(radius: BorderRadiusSize, containing_length: Au) -> Size2D<Au> {
|
||||||
let BorderRadiusSize(size) = radius;
|
let generics::BorderRadiusSize(size) = radius;
|
||||||
let w = specified(size.width, containing_length);
|
let w = specified(size.width, containing_length);
|
||||||
let h = specified(size.height, containing_length);
|
let h = specified(size.height, containing_length);
|
||||||
Size2D::new(w, h)
|
Size2D::new(w, h)
|
||||||
|
|
|
@ -273,8 +273,8 @@ impl nsStyleImage {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
(*gecko_gradient).mBgPosX.set(position.horizontal);
|
(*gecko_gradient).mBgPosX.set(position.horizontal.0);
|
||||||
(*gecko_gradient).mBgPosY.set(position.vertical);
|
(*gecko_gradient).mBgPosY.set(position.vertical.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
gecko_gradient
|
gecko_gradient
|
||||||
|
@ -318,7 +318,6 @@ impl nsStyleImage {
|
||||||
pub mod basic_shape {
|
pub mod basic_shape {
|
||||||
//! Conversions from and to CSS shape representations.
|
//! Conversions from and to CSS shape representations.
|
||||||
|
|
||||||
use euclid::size::Size2D;
|
|
||||||
use gecko::values::GeckoStyleCoordConvertible;
|
use gecko::values::GeckoStyleCoordConvertible;
|
||||||
use gecko_bindings::structs;
|
use gecko_bindings::structs;
|
||||||
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleFillRule};
|
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleFillRule};
|
||||||
|
@ -329,6 +328,9 @@ pub mod basic_shape {
|
||||||
use values::computed::{BorderRadiusSize, LengthOrPercentage};
|
use values::computed::{BorderRadiusSize, LengthOrPercentage};
|
||||||
use values::computed::basic_shape::*;
|
use values::computed::basic_shape::*;
|
||||||
use values::computed::position;
|
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()
|
// using Borrow so that we can have a non-moving .into()
|
||||||
impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape {
|
impl<T: Borrow<StyleBasicShape>> From<T> for BasicShape {
|
||||||
|
@ -391,11 +393,11 @@ pub mod basic_shape {
|
||||||
fn from(other: T) -> Self {
|
fn from(other: T) -> Self {
|
||||||
let other = other.borrow();
|
let other = other.borrow();
|
||||||
let get_corner = |index| {
|
let get_corner = |index| {
|
||||||
BorderRadiusSize(Size2D::new(
|
GenericBorderRadiusSize::new(
|
||||||
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
|
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index))
|
||||||
.expect("<border-radius> should be a length, percentage, or calc value"),
|
.expect("<border-radius> should be a length, percentage, or calc value"),
|
||||||
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
|
LengthOrPercentage::from_gecko_style_coord(&other.data_at(index + 1))
|
||||||
.expect("<border-radius> should be a length, percentage, or calc value")))
|
.expect("<border-radius> should be a length, percentage, or calc value"))
|
||||||
};
|
};
|
||||||
|
|
||||||
BorderRadius {
|
BorderRadius {
|
||||||
|
@ -439,8 +441,8 @@ pub mod basic_shape {
|
||||||
impl From<position::Position> for structs::Position {
|
impl From<position::Position> for structs::Position {
|
||||||
fn from(other: position::Position) -> Self {
|
fn from(other: position::Position) -> Self {
|
||||||
structs::Position {
|
structs::Position {
|
||||||
mXPosition: other.horizontal.into(),
|
mXPosition: other.horizontal.0.into(),
|
||||||
mYPosition: other.vertical.into()
|
mYPosition: other.vertical.0.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,8 +459,8 @@ pub mod basic_shape {
|
||||||
fn from(other: T) -> Self {
|
fn from(other: T) -> Self {
|
||||||
let other = other.borrow();
|
let other = other.borrow();
|
||||||
position::Position {
|
position::Position {
|
||||||
horizontal: other.mXPosition.into(),
|
horizontal: HorizontalPosition(other.mXPosition.into()),
|
||||||
vertical: other.mYPosition.into(),
|
vertical: VerticalPosition(other.mYPosition.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,8 @@ use values::{Auto, Either, ExtremumLength, None_, Normal};
|
||||||
use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto};
|
use values::computed::{Angle, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
|
use values::computed::{LengthOrPercentageOrNone, Number, NumberOrPercentage};
|
||||||
use values::computed::{MaxLength, MinLength};
|
use values::computed::{MaxLength, MinLength};
|
||||||
use values::computed::basic_shape::ShapeRadius;
|
use values::computed::basic_shape::ShapeRadius as ComputedShapeRadius;
|
||||||
|
use values::generics::basic_shape::ShapeRadius;
|
||||||
use values::specified::Percentage;
|
use values::specified::Percentage;
|
||||||
use values::specified::grid::{TrackBreadth, TrackKeyword};
|
use values::specified::grid::{TrackBreadth, TrackKeyword};
|
||||||
|
|
||||||
|
@ -205,15 +206,13 @@ impl<L: GeckoStyleCoordConvertible> GeckoStyleCoordConvertible for TrackBreadth<
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GeckoStyleCoordConvertible for ShapeRadius {
|
impl GeckoStyleCoordConvertible for ComputedShapeRadius {
|
||||||
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
fn to_gecko_style_coord<T: CoordDataMut>(&self, coord: &mut T) {
|
||||||
match *self {
|
match *self {
|
||||||
ShapeRadius::ClosestSide => {
|
ShapeRadius::ClosestSide =>
|
||||||
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::ClosestSide as u32))
|
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::ClosestSide as u32)),
|
||||||
}
|
ShapeRadius::FarthestSide =>
|
||||||
ShapeRadius::FarthestSide => {
|
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::FarthestSide as u32)),
|
||||||
coord.set_value(CoordDataValue::Enumerated(StyleShapeRadius::FarthestSide as u32))
|
|
||||||
}
|
|
||||||
ShapeRadius::Length(lop) => lop.to_gecko_style_coord(coord),
|
ShapeRadius::Length(lop) => lop.to_gecko_style_coord(coord),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -376,17 +376,17 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
|
||||||
<%def name="impl_position(ident, gecko_ffi_name, need_clone=False)">
|
<%def name="impl_position(ident, gecko_ffi_name, need_clone=False)">
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
||||||
${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.into()")}
|
${set_gecko_property("%s.mXPosition" % gecko_ffi_name, "v.horizontal.0.into()")}
|
||||||
${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.into()")}
|
${set_gecko_property("%s.mYPosition" % gecko_ffi_name, "v.vertical.0.into()")}
|
||||||
}
|
}
|
||||||
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
|
<%call expr="impl_simple_copy(ident, gecko_ffi_name)"></%call>
|
||||||
% if need_clone:
|
% if need_clone:
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
||||||
use values::computed::Position;
|
use values::generics::position::{HorizontalPosition, Position, VerticalPosition};
|
||||||
Position {
|
Position {
|
||||||
horizontal: self.gecko.${gecko_ffi_name}.mXPosition.into(),
|
horizontal: HorizontalPosition(self.gecko.${gecko_ffi_name}.mXPosition.into()),
|
||||||
vertical: self.gecko.${gecko_ffi_name}.mYPosition.into(),
|
vertical: VerticalPosition(self.gecko.${gecko_ffi_name}.mYPosition.into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
% endif
|
% endif
|
||||||
|
@ -543,15 +543,14 @@ fn color_to_nscolor_zero_currentcolor(color: Color) -> structs::nscolor {
|
||||||
% if need_clone:
|
% if need_clone:
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
pub fn clone_${ident}(&self) -> longhands::${ident}::computed_value::T {
|
||||||
use properties::longhands::${ident}::computed_value::T;
|
use values::generics::BorderRadiusSize;
|
||||||
use euclid::Size2D;
|
|
||||||
let width = GeckoStyleCoordConvertible::from_gecko_style_coord(
|
let width = GeckoStyleCoordConvertible::from_gecko_style_coord(
|
||||||
&self.gecko.${gecko_ffi_name}.data_at(${x_index}))
|
&self.gecko.${gecko_ffi_name}.data_at(${x_index}))
|
||||||
.expect("Failed to clone ${ident}");
|
.expect("Failed to clone ${ident}");
|
||||||
let height = GeckoStyleCoordConvertible::from_gecko_style_coord(
|
let height = GeckoStyleCoordConvertible::from_gecko_style_coord(
|
||||||
&self.gecko.${gecko_ffi_name}.data_at(${y_index}))
|
&self.gecko.${gecko_ffi_name}.data_at(${y_index}))
|
||||||
.expect("Failed to clone ${ident}");
|
.expect("Failed to clone ${ident}");
|
||||||
T(Size2D::new(width, height))
|
BorderRadiusSize::new(width, height)
|
||||||
}
|
}
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
@ -1948,8 +1947,8 @@ fn static_assert() {
|
||||||
for (gecko, servo) in self.gecko.mScrollSnapCoordinate
|
for (gecko, servo) in self.gecko.mScrollSnapCoordinate
|
||||||
.iter_mut()
|
.iter_mut()
|
||||||
.zip(v.0.iter()) {
|
.zip(v.0.iter()) {
|
||||||
gecko.mXPosition = servo.horizontal.into();
|
gecko.mXPosition = servo.horizontal.0.into();
|
||||||
gecko.mYPosition = servo.vertical.into();
|
gecko.mYPosition = servo.vertical.0.into();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2601,7 +2600,7 @@ fn static_assert() {
|
||||||
|
|
||||||
pub fn clone_${shorthand}_position_${orientation[0]}(&self)
|
pub fn clone_${shorthand}_position_${orientation[0]}(&self)
|
||||||
-> longhands::${shorthand}_position_${orientation[0]}::computed_value::T {
|
-> longhands::${shorthand}_position_${orientation[0]}::computed_value::T {
|
||||||
use values::computed::position::${orientation[1]}Position;
|
use values::generics::position::${orientation[1]}Position;
|
||||||
longhands::${shorthand}_position_${orientation[0]}::computed_value::T(
|
longhands::${shorthand}_position_${orientation[0]}::computed_value::T(
|
||||||
self.gecko.${image_layers_field}.mLayers.iter()
|
self.gecko.${image_layers_field}.mLayers.iter()
|
||||||
.take(self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count as usize)
|
.take(self.gecko.${image_layers_field}.mPosition${orientation[0].upper()}Count as usize)
|
||||||
|
@ -3565,12 +3564,12 @@ fn static_assert() {
|
||||||
<%def name="impl_shape_source(ident, gecko_ffi_name)">
|
<%def name="impl_shape_source(ident, gecko_ffi_name)">
|
||||||
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) {
|
||||||
use gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyShapeSource};
|
use gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyShapeSource};
|
||||||
use gecko_bindings::structs::StyleGeometryBox;
|
|
||||||
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType};
|
use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType};
|
||||||
use gecko_bindings::structs::{StyleFillRule, StyleShapeSource};
|
use gecko_bindings::structs::{StyleFillRule, StyleGeometryBox, StyleShapeSource};
|
||||||
use gecko::conversions::basic_shape::set_corners_from_radius;
|
use gecko::conversions::basic_shape::set_corners_from_radius;
|
||||||
use gecko::values::GeckoStyleCoordConvertible;
|
use gecko::values::GeckoStyleCoordConvertible;
|
||||||
use values::computed::basic_shape::*;
|
use values::computed::basic_shape::BasicShape;
|
||||||
|
use values::generics::basic_shape::{ShapeSource, FillRule};
|
||||||
let ref mut ${ident} = self.gecko.${gecko_ffi_name};
|
let ref mut ${ident} = self.gecko.${gecko_ffi_name};
|
||||||
// clean up existing struct
|
// clean up existing struct
|
||||||
unsafe { Gecko_DestroyShapeSource(${ident}) };
|
unsafe { Gecko_DestroyShapeSource(${ident}) };
|
||||||
|
@ -3580,7 +3579,7 @@ fn static_assert() {
|
||||||
match v {
|
match v {
|
||||||
ShapeSource::Url(ref url) => {
|
ShapeSource::Url(ref url) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.for_ffi());
|
bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.for_ffi())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ShapeSource::None => {} // don't change the type
|
ShapeSource::None => {} // don't change the type
|
||||||
|
|
|
@ -8,14 +8,18 @@
|
||||||
%>
|
%>
|
||||||
|
|
||||||
<%def name="predefined_type(name, type, initial_value, parse_method='parse',
|
<%def name="predefined_type(name, type, initial_value, parse_method='parse',
|
||||||
needs_context=True, vector=False, initial_specified_value=None, **kwargs)">
|
needs_context=True, vector=False, computed_type=None, initial_specified_value=None, **kwargs)">
|
||||||
<%def name="predefined_type_inner(name, type, initial_value, parse_method)">
|
<%def name="predefined_type_inner(name, type, initial_value, parse_method)">
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use cssparser::{Color as CSSParserColor, RGBA};
|
use cssparser::{Color as CSSParserColor, RGBA};
|
||||||
pub use values::specified::${type} as SpecifiedValue;
|
pub use values::specified::${type} as SpecifiedValue;
|
||||||
pub mod computed_value {
|
pub mod computed_value {
|
||||||
|
% if computed_type:
|
||||||
|
pub use ${computed_type} as T;
|
||||||
|
% else:
|
||||||
pub use values::computed::${type} as T;
|
pub use values::computed::${type} as T;
|
||||||
|
% endif
|
||||||
}
|
}
|
||||||
#[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
|
#[inline] pub fn get_initial_value() -> computed_value::T { ${initial_value} }
|
||||||
% if initial_specified_value:
|
% if initial_specified_value:
|
||||||
|
@ -36,10 +40,16 @@
|
||||||
% if vector:
|
% if vector:
|
||||||
<%call expr="vector_longhand(name, predefined_type=type, **kwargs)">
|
<%call expr="vector_longhand(name, predefined_type=type, **kwargs)">
|
||||||
${predefined_type_inner(name, type, initial_value, parse_method)}
|
${predefined_type_inner(name, type, initial_value, parse_method)}
|
||||||
|
% if caller:
|
||||||
|
${caller.body()}
|
||||||
|
% endif
|
||||||
</%call>
|
</%call>
|
||||||
% else:
|
% else:
|
||||||
<%call expr="longhand(name, predefined_type=type, **kwargs)">
|
<%call expr="longhand(name, predefined_type=type, **kwargs)">
|
||||||
${predefined_type_inner(name, type, initial_value, parse_method)}
|
${predefined_type_inner(name, type, initial_value, parse_method)}
|
||||||
|
% if caller:
|
||||||
|
${caller.body()}
|
||||||
|
% endif
|
||||||
</%call>
|
</%call>
|
||||||
% endif
|
% endif
|
||||||
</%def>
|
</%def>
|
||||||
|
@ -238,7 +248,7 @@
|
||||||
use properties::style_structs;
|
use properties::style_structs;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use values::computed::{Context, ToComputedValue};
|
use values::computed::{Context, ToComputedValue};
|
||||||
use values::{computed, specified};
|
use values::{computed, generics, specified};
|
||||||
use Atom;
|
use Atom;
|
||||||
${caller.body()}
|
${caller.body()}
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
|
|
|
@ -31,14 +31,14 @@ use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use super::ComputedValues;
|
use super::ComputedValues;
|
||||||
use values::CSSFloat;
|
use values::CSSFloat;
|
||||||
use values::{Auto, Either, Normal};
|
use values::{Auto, Either, Normal, generics};
|
||||||
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
use values::computed::{Angle, LengthOrPercentageOrAuto, LengthOrPercentageOrNone};
|
||||||
use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone};
|
use values::computed::{BorderRadiusSize, ClipRect, LengthOrNone};
|
||||||
use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
|
use values::computed::{CalcLengthOrPercentage, Context, LengthOrPercentage};
|
||||||
use values::computed::{MaxLength, MinLength};
|
use values::computed::{MaxLength, MinLength};
|
||||||
use values::computed::position::{HorizontalPosition, Position, VerticalPosition};
|
use values::computed::position::{HorizontalPosition, VerticalPosition};
|
||||||
use values::computed::ToComputedValue;
|
use values::computed::ToComputedValue;
|
||||||
|
use values::generics::position as generic_position;
|
||||||
|
|
||||||
|
|
||||||
/// A given transition property, that is either `All`, or an animatable
|
/// A given transition property, that is either `All`, or an animatable
|
||||||
|
@ -711,7 +711,7 @@ impl<T: Interpolate + Copy> Interpolate for Point2D<T> {
|
||||||
impl Interpolate for BorderRadiusSize {
|
impl Interpolate for BorderRadiusSize {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||||
self.0.interpolate(&other.0, progress).map(BorderRadiusSize)
|
self.0.interpolate(&other.0, progress).map(generics::BorderRadiusSize)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -957,23 +957,24 @@ impl Interpolate for FontWeight {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
|
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
|
||||||
impl Interpolate for Position {
|
impl<H: Interpolate, V: Interpolate> Interpolate for generic_position::Position<H, V> {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||||
Ok(Position {
|
Ok(generic_position::Position {
|
||||||
horizontal: try!(self.horizontal.interpolate(&other.horizontal, progress)),
|
horizontal: try!(self.horizontal.interpolate(&other.horizontal, progress)),
|
||||||
vertical: try!(self.vertical.interpolate(&other.vertical, progress)),
|
vertical: try!(self.vertical.interpolate(&other.vertical, progress)),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RepeatableListInterpolate for Position {}
|
impl<H, V> RepeatableListInterpolate for generic_position::Position<H, V>
|
||||||
|
where H: RepeatableListInterpolate, V: RepeatableListInterpolate {}
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
|
/// https://drafts.csswg.org/css-transitions/#animtype-simple-list
|
||||||
impl Interpolate for HorizontalPosition {
|
impl Interpolate for HorizontalPosition {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||||
Ok(HorizontalPosition(try!(self.0.interpolate(&other.0, progress))))
|
self.0.interpolate(&other.0, progress).map(generic_position::HorizontalPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,7 +984,7 @@ impl RepeatableListInterpolate for HorizontalPosition {}
|
||||||
impl Interpolate for VerticalPosition {
|
impl Interpolate for VerticalPosition {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
fn interpolate(&self, other: &Self, progress: f64) -> Result<Self, ()> {
|
||||||
Ok(VerticalPosition(try!(self.0.interpolate(&other.0, progress))))
|
self.0.interpolate(&other.0, progress).map(generic_position::VerticalPosition)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2607,7 +2608,9 @@ impl ComputeDistance for FontWeight {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ComputeDistance for Position {
|
impl<H, V> ComputeDistance for generic_position::Position<H, V>
|
||||||
|
where H: ComputeDistance, V: ComputeDistance
|
||||||
|
{
|
||||||
#[inline]
|
#[inline]
|
||||||
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
fn compute_distance(&self, other: &Self) -> Result<f64, ()> {
|
||||||
self.compute_squared_distance(other).map(|sd| sd.sqrt())
|
self.compute_squared_distance(other).map(|sd| sd.sqrt())
|
||||||
|
|
|
@ -89,108 +89,38 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
||||||
}
|
}
|
||||||
</%helpers:vector_longhand>
|
</%helpers:vector_longhand>
|
||||||
|
|
||||||
<%helpers:vector_longhand name="background-position-x" animation_value_type="ComputedValue"
|
<%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"
|
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x"
|
||||||
delegate_animate="True">
|
animation_value_type="ComputedValue" vector="True" delegate_animate="True">
|
||||||
use std::fmt;
|
|
||||||
use style_traits::ToCss;
|
|
||||||
use values::HasViewportPercentage;
|
|
||||||
use values::specified::position::HorizontalPosition;
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub mod computed_value {
|
|
||||||
use values::computed::position::HorizontalPosition;
|
|
||||||
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
|
|
||||||
|
|
||||||
pub type T = HorizontalPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub type SpecifiedValue = HorizontalPosition;
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
#[allow(missing_docs)]
|
/// Get the initial value for horizontal position.
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
use values::computed::position::HorizontalPosition;
|
|
||||||
HorizontalPosition(computed::LengthOrPercentage::Percentage(0.0))
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
|
||||||
use values::specified::position::Keyword;
|
|
||||||
HorizontalPosition {
|
|
||||||
keyword: Some(Keyword::Left),
|
|
||||||
position: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn get_initial_position_value() -> SpecifiedValue {
|
pub fn get_initial_position_value() -> SpecifiedValue {
|
||||||
|
use values::generics::position::{HorizontalPosition, PositionValue};
|
||||||
use values::specified::{LengthOrPercentage, Percentage};
|
use values::specified::{LengthOrPercentage, Percentage};
|
||||||
HorizontalPosition {
|
HorizontalPosition(PositionValue {
|
||||||
keyword: None,
|
keyword: None,
|
||||||
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
|
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
</%helpers:predefined_type>
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
<%helpers:predefined_type name="background-position-y" type="position::VerticalPosition"
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser)
|
initial_value="computed::position::VerticalPosition::zero()"
|
||||||
-> Result<SpecifiedValue, ()> {
|
initial_specified_value="specified::position::VerticalPosition::top()"
|
||||||
HorizontalPosition::parse(context, input)
|
|
||||||
}
|
|
||||||
</%helpers:vector_longhand>
|
|
||||||
|
|
||||||
<%helpers:vector_longhand name="background-position-y" animation_value_type="ComputedValue"
|
|
||||||
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y"
|
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-y"
|
||||||
delegate_animate="True">
|
animation_value_type="ComputedValue" vector="True" delegate_animate="True">
|
||||||
use std::fmt;
|
/// Get the initial value for vertical position.
|
||||||
use style_traits::ToCss;
|
|
||||||
use values::HasViewportPercentage;
|
|
||||||
use values::specified::position::VerticalPosition;
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub mod computed_value {
|
|
||||||
use values::computed::position::VerticalPosition;
|
|
||||||
use properties::animated_properties::{Interpolate, RepeatableListInterpolate};
|
|
||||||
|
|
||||||
pub type T = VerticalPosition;
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub type SpecifiedValue = VerticalPosition;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
use values::computed::position::VerticalPosition;
|
|
||||||
VerticalPosition(computed::LengthOrPercentage::Percentage(0.0))
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
|
||||||
use values::specified::position::Keyword;
|
|
||||||
VerticalPosition {
|
|
||||||
keyword: Some(Keyword::Top),
|
|
||||||
position: None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn get_initial_position_value() -> SpecifiedValue {
|
pub fn get_initial_position_value() -> SpecifiedValue {
|
||||||
|
use values::generics::position::{VerticalPosition, PositionValue};
|
||||||
use values::specified::{LengthOrPercentage, Percentage};
|
use values::specified::{LengthOrPercentage, Percentage};
|
||||||
VerticalPosition {
|
VerticalPosition(PositionValue {
|
||||||
keyword: None,
|
keyword: None,
|
||||||
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
|
position: Some(LengthOrPercentage::Percentage(Percentage(0.0))),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
</%helpers:predefined_type>
|
||||||
#[inline]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser)
|
|
||||||
-> Result<SpecifiedValue, ()> {
|
|
||||||
VerticalPosition::parse(context, input)
|
|
||||||
}
|
|
||||||
</%helpers:vector_longhand>
|
|
||||||
|
|
||||||
<%helpers:vector_longhand name="background-repeat" animation_value_type="none"
|
<%helpers:vector_longhand name="background-repeat" animation_value_type="none"
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#the-background-repeat">
|
spec="https://drafts.csswg.org/css-backgrounds/#the-background-repeat">
|
||||||
|
|
|
@ -21,47 +21,24 @@
|
||||||
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
|
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-color"),
|
||||||
spec=maybe_logical_spec(side, "color"),
|
spec=maybe_logical_spec(side, "color"),
|
||||||
animation_value_type="IntermediateColor", logical = side[1])}
|
animation_value_type="IntermediateColor", logical = side[1])}
|
||||||
% endfor
|
|
||||||
|
|
||||||
% for side in ALL_SIDES:
|
|
||||||
${helpers.predefined_type("border-%s-style" % side[0], "BorderStyle",
|
${helpers.predefined_type("border-%s-style" % side[0], "BorderStyle",
|
||||||
"specified::BorderStyle::none",
|
"specified::BorderStyle::none",
|
||||||
need_clone=True,
|
need_clone=True,
|
||||||
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
|
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-style"),
|
||||||
spec=maybe_logical_spec(side, "style"),
|
spec=maybe_logical_spec(side, "style"),
|
||||||
animation_value_type="none", logical = side[1])}
|
animation_value_type="none", logical=side[1])}
|
||||||
|
|
||||||
|
${helpers.predefined_type("border-%s-width" % side[0], "BorderWidth", "Au::from_px(3)",
|
||||||
|
computed_type="::app_units::Au",
|
||||||
|
alias=maybe_moz_logical_alias(product, side, "-moz-border-%s-width"),
|
||||||
|
spec=maybe_logical_spec(side, "width"),
|
||||||
|
animation_value_type="ComputedValue", logical=side[1])}
|
||||||
% endfor
|
% endfor
|
||||||
|
|
||||||
${helpers.gecko_keyword_conversion(Keyword('border-style',
|
${helpers.gecko_keyword_conversion(Keyword('border-style',
|
||||||
"none solid double dotted dashed hidden groove ridge inset outset"),
|
"none solid double dotted dashed hidden groove ridge inset outset"),
|
||||||
type="::values::specified::BorderStyle")}
|
type="::values::specified::BorderStyle")}
|
||||||
% for side in ALL_SIDES:
|
|
||||||
<%helpers:longhand name="border-${side[0]}-width" animation_value_type="ComputedValue" logical="${side[1]}"
|
|
||||||
alias="${maybe_moz_logical_alias(product, side, '-moz-border-%s-width')}"
|
|
||||||
spec="${maybe_logical_spec(side, 'width')}">
|
|
||||||
use app_units::Au;
|
|
||||||
use std::fmt;
|
|
||||||
use style_traits::ToCss;
|
|
||||||
use values::HasViewportPercentage;
|
|
||||||
use values::specified::BorderWidth;
|
|
||||||
|
|
||||||
pub type SpecifiedValue = BorderWidth;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser)
|
|
||||||
-> Result<SpecifiedValue, ()> {
|
|
||||||
BorderWidth::parse(context, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
use app_units::Au;
|
|
||||||
pub type T = Au;
|
|
||||||
}
|
|
||||||
#[inline] pub fn get_initial_value() -> computed_value::T {
|
|
||||||
Au::from_px(3) // medium
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
% endfor
|
|
||||||
|
|
||||||
// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage>
|
// FIXME(#4126): when gfx supports painting it, make this Size2D<LengthOrPercentage>
|
||||||
% for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
|
% for corner in ["top-left", "top-right", "bottom-right", "bottom-left"]:
|
||||||
|
|
|
@ -1113,7 +1113,6 @@ ${helpers.predefined_type("scroll-snap-coordinate",
|
||||||
delegate_animate=True)}
|
delegate_animate=True)}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<%helpers:longhand name="transform" extra_prefixes="webkit"
|
<%helpers:longhand name="transform" extra_prefixes="webkit"
|
||||||
animation_value_type="ComputedValue"
|
animation_value_type="ComputedValue"
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB"
|
flags="CREATES_STACKING_CONTEXT FIXPOS_CB"
|
||||||
|
@ -2096,83 +2095,13 @@ ${helpers.predefined_type("perspective",
|
||||||
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
flags="CREATES_STACKING_CONTEXT FIXPOS_CB",
|
||||||
animation_value_type="ComputedValue")}
|
animation_value_type="ComputedValue")}
|
||||||
|
|
||||||
<%helpers:longhand name="perspective-origin" boxed="True"
|
${helpers.predefined_type("perspective-origin",
|
||||||
animation_value_type="ComputedValue"
|
"position::OriginPosition",
|
||||||
extra_prefixes="moz webkit"
|
"computed::position::OriginPosition::center()",
|
||||||
spec="https://drafts.csswg.org/css-transforms/#perspective-origin-property">
|
boxed="True",
|
||||||
use std::fmt;
|
extra_prefixes="moz webkit",
|
||||||
use style_traits::ToCss;
|
spec="https://drafts.csswg.org/css-transforms/#perspective-origin-property",
|
||||||
use values::HasViewportPercentage;
|
animation_value_type="ComputedValue")}
|
||||||
use values::specified::{LengthOrPercentage, Percentage};
|
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
use properties::animated_properties::Interpolate;
|
|
||||||
use values::computed::LengthOrPercentage;
|
|
||||||
use values::computed::Position;
|
|
||||||
|
|
||||||
pub type T = Position;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasViewportPercentage for SpecifiedValue {
|
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
|
||||||
self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct SpecifiedValue {
|
|
||||||
horizontal: LengthOrPercentage,
|
|
||||||
vertical: LengthOrPercentage,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for SpecifiedValue {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(self.horizontal.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
self.vertical.to_css(dest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
computed_value::T {
|
|
||||||
horizontal: computed::LengthOrPercentage::Percentage(0.5),
|
|
||||||
vertical: computed::LengthOrPercentage::Percentage(0.5),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue,()> {
|
|
||||||
let result = try!(super::parse_origin(context, input));
|
|
||||||
match result.depth {
|
|
||||||
Some(_) => Err(()),
|
|
||||||
None => Ok(SpecifiedValue {
|
|
||||||
horizontal: result.horizontal.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))),
|
|
||||||
vertical: result.vertical.unwrap_or(LengthOrPercentage::Percentage(Percentage(0.5))),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for SpecifiedValue {
|
|
||||||
type ComputedValue = computed_value::T;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_value::T {
|
|
||||||
computed_value::T {
|
|
||||||
horizontal: self.horizontal.to_computed_value(context),
|
|
||||||
vertical: self.vertical.to_computed_value(context),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &computed_value::T) -> Self {
|
|
||||||
SpecifiedValue {
|
|
||||||
horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
|
|
||||||
vertical: ToComputedValue::from_computed_value(&computed.vertical),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
${helpers.single_keyword("backface-visibility",
|
${helpers.single_keyword("backface-visibility",
|
||||||
"visible hidden",
|
"visible hidden",
|
||||||
|
@ -2533,29 +2462,8 @@ ${helpers.single_keyword("-moz-orient",
|
||||||
}
|
}
|
||||||
</%helpers:longhand>
|
</%helpers:longhand>
|
||||||
|
|
||||||
<%helpers:longhand name="shape-outside" products="gecko" animation_value_type="none" boxed="True"
|
${helpers.predefined_type("shape-outside", "basic_shape::ShapeWithShapeBox",
|
||||||
spec="https://drafts.csswg.org/css-shapes/#shape-outside-property">
|
"generics::basic_shape::ShapeSource::None",
|
||||||
use std::fmt;
|
products="gecko", boxed="True",
|
||||||
use style_traits::ToCss;
|
animation_value_type="none",
|
||||||
use values::specified::basic_shape::{ShapeBox, ShapeSource};
|
spec="https://drafts.csswg.org/css-shapes/#shape-outside-property")}
|
||||||
use values::HasViewportPercentage;
|
|
||||||
|
|
||||||
no_viewport_percentage!(SpecifiedValue);
|
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
use values::computed::basic_shape::{ShapeBox, ShapeSource};
|
|
||||||
|
|
||||||
pub type T = ShapeSource<ShapeBox>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type SpecifiedValue = ShapeSource<ShapeBox>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
|
||||||
ShapeSource::parse(context, input)
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
|
@ -40,36 +40,11 @@ ${helpers.single_keyword("column-fill", "balance auto", extra_prefixes="moz",
|
||||||
products="gecko", animation_value_type="none",
|
products="gecko", animation_value_type="none",
|
||||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")}
|
spec="https://drafts.csswg.org/css-multicol/#propdef-column-fill")}
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-multicol-1/#propdef-column-rule-width
|
${helpers.predefined_type("column-rule-width", "BorderWidth", "Au::from_px(3)",
|
||||||
<%helpers:longhand name="column-rule-width" products="gecko" animation_value_type="ComputedValue" extra_prefixes="moz"
|
initial_specified_value="specified::BorderWidth::Medium",
|
||||||
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width">
|
products="gecko", computed_type="::app_units::Au",
|
||||||
use app_units::Au;
|
spec="https://drafts.csswg.org/css-multicol/#propdef-column-rule-width",
|
||||||
use std::fmt;
|
animation_value_type="ComputedValue", extra_prefixes="moz")}
|
||||||
use style_traits::ToCss;
|
|
||||||
use values::HasViewportPercentage;
|
|
||||||
use values::specified::BorderWidth;
|
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
use app_units::Au;
|
|
||||||
pub type T = Au;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type SpecifiedValue = BorderWidth;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
Au::from_px(3) // medium
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
|
||||||
BorderWidth::Medium
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
|
||||||
BorderWidth::parse(context, input)
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-multicol-1/#crc
|
// https://drafts.csswg.org/css-multicol-1/#crc
|
||||||
${helpers.predefined_type("column-rule-color", "CSSColor",
|
${helpers.predefined_type("column-rule-color", "CSSColor",
|
||||||
|
|
|
@ -1236,33 +1236,11 @@ ${helpers.predefined_type(
|
||||||
complex_color=True, need_clone=True,
|
complex_color=True, need_clone=True,
|
||||||
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")}
|
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-color")}
|
||||||
|
|
||||||
<%helpers:longhand products="gecko" name="-webkit-text-stroke-width" animation_value_type="none"
|
${helpers.predefined_type("-webkit-text-stroke-width", "BorderWidth", "Au::from_px(0)",
|
||||||
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width">
|
initial_specified_value="specified::BorderWidth::from_length(specified::Length::zero())",
|
||||||
use app_units::Au;
|
computed_type="::app_units::Au", products="gecko",
|
||||||
use std::fmt;
|
spec="https://compat.spec.whatwg.org/#the-webkit-text-stroke-width",
|
||||||
use style_traits::ToCss;
|
animation_value_type="none")}
|
||||||
use values::HasViewportPercentage;
|
|
||||||
use values::specified::{BorderWidth, Length};
|
|
||||||
|
|
||||||
pub type SpecifiedValue = BorderWidth;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
|
||||||
BorderWidth::parse(context, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
use app_units::Au;
|
|
||||||
pub type T = Au;
|
|
||||||
}
|
|
||||||
#[inline] pub fn get_initial_value() -> computed_value::T {
|
|
||||||
Au::from_px(0)
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_specified_value() -> SpecifiedValue {
|
|
||||||
BorderWidth::from_length(Length::zero())
|
|
||||||
}
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
|
|
||||||
// CSS Ruby Layout Module Level 1
|
// CSS Ruby Layout Module Level 1
|
||||||
|
|
|
@ -58,34 +58,11 @@ ${helpers.single_keyword("mask-type", "luminance alpha",
|
||||||
products="gecko", animation_value_type="none",
|
products="gecko", animation_value_type="none",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")}
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-type")}
|
||||||
|
|
||||||
<%helpers:longhand name="clip-path" animation_value_type="none" products="gecko" boxed="True"
|
${helpers.predefined_type("clip-path", "basic_shape::ShapeWithGeometryBox",
|
||||||
flags="CREATES_STACKING_CONTEXT"
|
"generics::basic_shape::ShapeSource::None",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path">
|
products="gecko", boxed="True",
|
||||||
use std::fmt;
|
animation_value_type="none", flags="CREATES_STACKING_CONTEXT",
|
||||||
use style_traits::ToCss;
|
spec="https://drafts.fxtf.org/css-masking/#propdef-clip-path")}
|
||||||
use values::HasViewportPercentage;
|
|
||||||
use values::specified::basic_shape::{ShapeSource, GeometryBox};
|
|
||||||
|
|
||||||
pub mod computed_value {
|
|
||||||
use app_units::Au;
|
|
||||||
use values::computed::basic_shape::{ShapeSource, GeometryBox};
|
|
||||||
|
|
||||||
pub type T = ShapeSource<GeometryBox>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub type SpecifiedValue = ShapeSource<GeometryBox>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
pub fn get_initial_value() -> computed_value::T {
|
|
||||||
Default::default()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
|
||||||
ShapeSource::parse(context, input)
|
|
||||||
}
|
|
||||||
|
|
||||||
no_viewport_percentage!(SpecifiedValue);
|
|
||||||
</%helpers:longhand>
|
|
||||||
|
|
||||||
${helpers.single_keyword("mask-mode",
|
${helpers.single_keyword("mask-mode",
|
||||||
"match-source alpha luminance",
|
"match-source alpha luminance",
|
||||||
|
|
|
@ -203,7 +203,8 @@ pub fn parse_border(context: &ParserContext, input: &mut Parser)
|
||||||
'border-%s-radius' % (corner)
|
'border-%s-radius' % (corner)
|
||||||
for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
|
for corner in ['top-left', 'top-right', 'bottom-right', 'bottom-left']
|
||||||
)}" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
|
)}" extra_prefixes="webkit" spec="https://drafts.csswg.org/css-backgrounds/#border-radius">
|
||||||
use values::specified::basic_shape::{BorderRadius, serialize_radius_values};
|
use values::generics::serialize_radius_values;
|
||||||
|
use values::specified::basic_shape::BorderRadius;
|
||||||
use parser::Parse;
|
use parser::Parse;
|
||||||
|
|
||||||
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
||||||
|
|
|
@ -68,7 +68,7 @@
|
||||||
for corner in ['topleft', 'topright', 'bottomright', 'bottomleft']
|
for corner in ['topleft', 'topright', 'bottomright', 'bottomleft']
|
||||||
)}" products="gecko" spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)">
|
)}" products="gecko" spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-outline-radius)">
|
||||||
use properties::shorthands;
|
use properties::shorthands;
|
||||||
use values::specified::basic_shape::serialize_radius_values;
|
use values::generics::serialize_radius_values;
|
||||||
|
|
||||||
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
pub fn parse_value(context: &ParserContext, input: &mut Parser) -> Result<Longhands, ()> {
|
||||||
// Re-use border-radius parsing.
|
// Re-use border-radius parsing.
|
||||||
|
|
|
@ -9,45 +9,19 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::computed::{BorderRadiusSize, LengthOrPercentage};
|
use values::computed::LengthOrPercentage;
|
||||||
use values::computed::position::Position;
|
use values::computed::position::Position;
|
||||||
use values::specified::url::SpecifiedUrl;
|
use values::generics::basic_shape::{BorderRadius as GenericBorderRadius, ShapeRadius as GenericShapeRadius};
|
||||||
|
use values::generics::basic_shape::{InsetRect as GenericInsetRect, Polygon as GenericPolygon, ShapeSource};
|
||||||
|
|
||||||
pub use values::specified::basic_shape::{self, FillRule, GeometryBox, ShapeBox};
|
pub use values::generics::basic_shape::FillRule;
|
||||||
|
pub use values::specified::basic_shape::{self, GeometryBox, ShapeBox};
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
/// The computed value used by `clip-path`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type ShapeWithGeometryBox = ShapeSource<BasicShape, GeometryBox>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum ShapeSource<T> {
|
|
||||||
Url(SpecifiedUrl),
|
|
||||||
Shape(BasicShape, Option<T>),
|
|
||||||
Box(T),
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for ShapeSource<T> {
|
|
||||||
fn default() -> Self {
|
|
||||||
ShapeSource::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ToCss> ToCss for ShapeSource<T> {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
ShapeSource::Url(ref url) => url.to_css(dest),
|
|
||||||
ShapeSource::Shape(ref shape, Some(ref reference)) => {
|
|
||||||
try!(shape.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
reference.to_css(dest)
|
|
||||||
}
|
|
||||||
ShapeSource::Shape(ref shape, None) => shape.to_css(dest),
|
|
||||||
ShapeSource::Box(ref reference) => reference.to_css(dest),
|
|
||||||
ShapeSource::None => dest.write_str("none"),
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// The computed value used by `shape-outside`
|
||||||
|
pub type ShapeWithShapeBox = ShapeSource<BasicShape, ShapeBox>;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
@ -70,35 +44,8 @@ impl ToCss for BasicShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
/// The computed value of `inset()`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type InsetRect = GenericInsetRect<LengthOrPercentage>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct InsetRect {
|
|
||||||
pub top: LengthOrPercentage,
|
|
||||||
pub right: LengthOrPercentage,
|
|
||||||
pub bottom: LengthOrPercentage,
|
|
||||||
pub left: LengthOrPercentage,
|
|
||||||
pub round: Option<BorderRadius>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for InsetRect {
|
|
||||||
// XXXManishearth again, we should try to reduce the number of values printed here
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(dest.write_str("inset("));
|
|
||||||
try!(self.top.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.right.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.bottom.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.left.to_css(dest));
|
|
||||||
if let Some(ref radius) = self.round {
|
|
||||||
try!(dest.write_str(" round "));
|
|
||||||
try!(radius.to_css(dest));
|
|
||||||
}
|
|
||||||
dest.write_str(")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
@ -140,77 +87,13 @@ impl ToCss for Ellipse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
/// The computed value of `Polygon`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type Polygon = GenericPolygon<LengthOrPercentage>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
|
|
||||||
pub struct Polygon {
|
|
||||||
pub fill: FillRule,
|
|
||||||
pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for Polygon {
|
/// The computed value of `BorderRadius`
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>;
|
||||||
try!(dest.write_str("polygon("));
|
|
||||||
let mut need_space = false;
|
|
||||||
if self.fill != Default::default() {
|
|
||||||
try!(self.fill.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
}
|
|
||||||
for coord in &self.coordinates {
|
|
||||||
if need_space {
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
}
|
|
||||||
try!(coord.0.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(coord.1.to_css(dest));
|
|
||||||
need_space = true;
|
|
||||||
}
|
|
||||||
dest.write_str(")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
/// The computed value of `ShapeRadius`
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
pub type ShapeRadius = GenericShapeRadius<LengthOrPercentage>;
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum ShapeRadius {
|
|
||||||
Length(LengthOrPercentage),
|
|
||||||
ClosestSide,
|
|
||||||
FarthestSide,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ShapeRadius {
|
impl Copy for ShapeRadius {}
|
||||||
fn default() -> Self {
|
|
||||||
ShapeRadius::ClosestSide
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for ShapeRadius {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
ShapeRadius::Length(lop) => lop.to_css(dest),
|
|
||||||
ShapeRadius::ClosestSide => dest.write_str("closest-side"),
|
|
||||||
ShapeRadius::FarthestSide => dest.write_str("farthest-side"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct BorderRadius {
|
|
||||||
pub top_left: BorderRadiusSize,
|
|
||||||
pub top_right: BorderRadiusSize,
|
|
||||||
pub bottom_right: BorderRadiusSize,
|
|
||||||
pub bottom_left: BorderRadiusSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for BorderRadius {
|
|
||||||
#[inline]
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
basic_shape::serialize_radius_values(dest, &self.top_left.0, &self.top_right.0,
|
|
||||||
&self.bottom_right.0, &self.bottom_left.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -4,16 +4,18 @@
|
||||||
|
|
||||||
//! Computed values.
|
//! Computed values.
|
||||||
|
|
||||||
use app_units::Au;
|
|
||||||
use euclid::size::Size2D;
|
use euclid::size::Size2D;
|
||||||
use font_metrics::FontMetricsProvider;
|
use font_metrics::FontMetricsProvider;
|
||||||
use media_queries::Device;
|
use media_queries::Device;
|
||||||
use properties::ComputedValues;
|
use properties::ComputedValues;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use super::{CSSFloat, CSSInteger, RGBA, specified};
|
use super::{CSSFloat, CSSInteger, RGBA};
|
||||||
|
use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
|
||||||
|
use super::specified;
|
||||||
use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
|
use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
|
||||||
|
|
||||||
|
pub use app_units::Au;
|
||||||
pub use cssparser::Color as CSSColor;
|
pub use cssparser::Color as CSSColor;
|
||||||
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image, ImageRect};
|
pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image, ImageRect};
|
||||||
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
|
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
|
||||||
|
@ -297,43 +299,19 @@ impl ComputedValueAsSpecified for specified::AlignJustifyContent {}
|
||||||
impl ComputedValueAsSpecified for specified::AlignJustifySelf {}
|
impl ComputedValueAsSpecified for specified::AlignJustifySelf {}
|
||||||
impl ComputedValueAsSpecified for specified::BorderStyle {}
|
impl ComputedValueAsSpecified for specified::BorderStyle {}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
/// The computed value of `BorderRadiusSize`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type BorderRadiusSize = GenericBorderRadiusSize<LengthOrPercentage>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);
|
|
||||||
|
|
||||||
impl BorderRadiusSize {
|
impl BorderRadiusSize {
|
||||||
#[allow(missing_docs)]
|
/// Create a null value.
|
||||||
|
#[inline]
|
||||||
pub fn zero() -> BorderRadiusSize {
|
pub fn zero() -> BorderRadiusSize {
|
||||||
BorderRadiusSize(Size2D::new(LengthOrPercentage::Length(Au(0)), LengthOrPercentage::Length(Au(0))))
|
let zero = LengthOrPercentage::zero();
|
||||||
|
GenericBorderRadiusSize(Size2D::new(zero.clone(), zero))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToComputedValue for specified::BorderRadiusSize {
|
impl Copy for BorderRadiusSize {}
|
||||||
type ComputedValue = BorderRadiusSize;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> BorderRadiusSize {
|
|
||||||
let w = self.0.width.to_computed_value(context);
|
|
||||||
let h = self.0.height.to_computed_value(context);
|
|
||||||
BorderRadiusSize(Size2D::new(w, h))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &BorderRadiusSize) -> Self {
|
|
||||||
let w = ToComputedValue::from_computed_value(&computed.0.width);
|
|
||||||
let h = ToComputedValue::from_computed_value(&computed.0.height);
|
|
||||||
specified::BorderRadiusSize(Size2D::new(w, h))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for BorderRadiusSize {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(self.0.width.to_css(dest));
|
|
||||||
try!(dest.write_str("/"));
|
|
||||||
self.0.height.to_css(dest)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
|
|
@ -3,59 +3,79 @@
|
||||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
//! CSS handling for the computed value of
|
//! CSS handling for the computed value of
|
||||||
//! [`position`][position]s
|
//! [`position`][position] values.
|
||||||
//!
|
//!
|
||||||
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::computed::LengthOrPercentage;
|
use values::computed::LengthOrPercentage;
|
||||||
|
use values::generics::position::{Position as GenericPosition, PositionWithKeyword};
|
||||||
|
use values::generics::position::HorizontalPosition as GenericHorizontalPosition;
|
||||||
|
use values::generics::position::VerticalPosition as GenericVerticalPosition;
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
/// The computed value of a CSS `<position>`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type Position = PositionWithKeyword<LengthOrPercentage>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct Position {
|
impl Copy for Position {}
|
||||||
pub horizontal: LengthOrPercentage,
|
|
||||||
pub vertical: LengthOrPercentage,
|
/// The computed value for `<position>` values without a keyword.
|
||||||
|
pub type OriginPosition = GenericPosition<LengthOrPercentage, LengthOrPercentage>;
|
||||||
|
|
||||||
|
impl Copy for OriginPosition {}
|
||||||
|
|
||||||
|
impl OriginPosition {
|
||||||
|
#[inline]
|
||||||
|
/// The initial value for `perspective-origin`
|
||||||
|
pub fn center() -> OriginPosition {
|
||||||
|
GenericPosition {
|
||||||
|
horizontal: LengthOrPercentage::Percentage(0.5),
|
||||||
|
vertical: LengthOrPercentage::Percentage(0.5),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
|
#[inline]
|
||||||
/// Construct a position at (0, 0)
|
/// Construct a position at (0, 0)
|
||||||
pub fn zero() -> Self {
|
pub fn zero() -> Self {
|
||||||
Position {
|
Position {
|
||||||
horizontal: LengthOrPercentage::zero(),
|
horizontal: GenericHorizontalPosition(LengthOrPercentage::zero()),
|
||||||
vertical: LengthOrPercentage::zero(),
|
vertical: GenericVerticalPosition(LengthOrPercentage::zero()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Position {
|
impl ToCss for Position {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
try!(self.horizontal.to_css(dest));
|
self.horizontal.to_css(dest)?;
|
||||||
try!(dest.write_str(" "));
|
dest.write_str(" ")?;
|
||||||
try!(self.vertical.to_css(dest));
|
self.vertical.to_css(dest)
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
/// The computed value of a horizontal `<position>`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type HorizontalPosition = GenericHorizontalPosition<LengthOrPercentage>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct HorizontalPosition(pub LengthOrPercentage);
|
|
||||||
|
|
||||||
impl ToCss for HorizontalPosition {
|
impl Copy for HorizontalPosition {}
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
self.0.to_css(dest)
|
impl HorizontalPosition {
|
||||||
|
#[inline]
|
||||||
|
/// Create a zero position value.
|
||||||
|
pub fn zero() -> HorizontalPosition {
|
||||||
|
GenericHorizontalPosition(LengthOrPercentage::Percentage(0.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq, Copy)]
|
/// The computed value of a vertical `<position>`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type VerticalPosition = GenericVerticalPosition<LengthOrPercentage>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct VerticalPosition(pub LengthOrPercentage);
|
|
||||||
|
|
||||||
impl ToCss for VerticalPosition {
|
impl Copy for VerticalPosition {}
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
self.0.to_css(dest)
|
impl VerticalPosition {
|
||||||
|
#[inline]
|
||||||
|
/// Create a zero position value.
|
||||||
|
pub fn zero() -> VerticalPosition {
|
||||||
|
GenericVerticalPosition(LengthOrPercentage::Percentage(0.0))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
397
components/style/values/generics/basic_shape.rs
Normal file
397
components/style/values/generics/basic_shape.rs
Normal file
|
@ -0,0 +1,397 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
//! CSS handling for the [`basic-shape`](https://drafts.csswg.org/css-shapes/#typedef-basic-shape)
|
||||||
|
//! types that are generic over their `ToCss` implementations.
|
||||||
|
|
||||||
|
use cssparser::Parser;
|
||||||
|
use euclid::size::Size2D;
|
||||||
|
use parser::{Parse, ParserContext};
|
||||||
|
use properties::shorthands::serialize_four_sides;
|
||||||
|
use std::ascii::AsciiExt;
|
||||||
|
use std::fmt;
|
||||||
|
use style_traits::ToCss;
|
||||||
|
use values::HasViewportPercentage;
|
||||||
|
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
||||||
|
use values::generics::BorderRadiusSize;
|
||||||
|
use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
|
/// A generic type used for `border-radius`, `outline-radius` and `inset()` values.
|
||||||
|
///
|
||||||
|
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct BorderRadius<L> {
|
||||||
|
/// The top left radius.
|
||||||
|
pub top_left: BorderRadiusSize<L>,
|
||||||
|
/// The top right radius.
|
||||||
|
pub top_right: BorderRadiusSize<L>,
|
||||||
|
/// The bottom right radius.
|
||||||
|
pub bottom_right: BorderRadiusSize<L>,
|
||||||
|
/// The bottom left radius.
|
||||||
|
pub bottom_left: BorderRadiusSize<L>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Serialization helper for types of longhands like `border-radius` and `outline-radius`
|
||||||
|
pub fn serialize_radius_values<L, W>(dest: &mut W, top_left: &Size2D<L>,
|
||||||
|
top_right: &Size2D<L>, bottom_right: &Size2D<L>,
|
||||||
|
bottom_left: &Size2D<L>) -> fmt::Result
|
||||||
|
where L: ToCss + PartialEq, W: fmt::Write
|
||||||
|
{
|
||||||
|
if top_left.width == top_left.height && top_right.width == top_right.height &&
|
||||||
|
bottom_right.width == bottom_right.height && bottom_left.width == bottom_left.height {
|
||||||
|
serialize_four_sides(dest, &top_left.width, &top_right.width,
|
||||||
|
&bottom_right.width, &bottom_left.width)
|
||||||
|
} else {
|
||||||
|
serialize_four_sides(dest, &top_left.width, &top_right.width,
|
||||||
|
&bottom_right.width, &bottom_left.width)?;
|
||||||
|
dest.write_str(" / ")?;
|
||||||
|
serialize_four_sides(dest, &top_left.height, &top_right.height,
|
||||||
|
&bottom_right.height, &bottom_left.height)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToCss + PartialEq> ToCss for BorderRadius<L> {
|
||||||
|
#[inline]
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
serialize_radius_values(dest, &self.top_left.0, &self.top_right.0,
|
||||||
|
&self.bottom_right.0, &self.bottom_left.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToComputedValue> ToComputedValue for BorderRadius<L> {
|
||||||
|
type ComputedValue = BorderRadius<L::ComputedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
||||||
|
BorderRadius {
|
||||||
|
top_left: self.top_left.to_computed_value(cx),
|
||||||
|
top_right: self.top_right.to_computed_value(cx),
|
||||||
|
bottom_right: self.bottom_right.to_computed_value(cx),
|
||||||
|
bottom_left: self.bottom_left.to_computed_value(cx),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
BorderRadius {
|
||||||
|
top_left: ToComputedValue::from_computed_value(&computed.top_left),
|
||||||
|
top_right: ToComputedValue::from_computed_value(&computed.top_right),
|
||||||
|
bottom_right: ToComputedValue::from_computed_value(&computed.bottom_right),
|
||||||
|
bottom_left: ToComputedValue::from_computed_value(&computed.bottom_left),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum ShapeRadius<L> {
|
||||||
|
Length(L),
|
||||||
|
ClosestSide,
|
||||||
|
FarthestSide,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L> Default for ShapeRadius<L> {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self { ShapeRadius::ClosestSide }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToCss> ToCss for ShapeRadius<L> {
|
||||||
|
#[inline]
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
ShapeRadius::Length(ref lop) => lop.to_css(dest),
|
||||||
|
ShapeRadius::ClosestSide => dest.write_str("closest-side"),
|
||||||
|
ShapeRadius::FarthestSide => dest.write_str("farthest-side"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToComputedValue> ToComputedValue for ShapeRadius<L> {
|
||||||
|
type ComputedValue = ShapeRadius<L::ComputedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
||||||
|
match *self {
|
||||||
|
ShapeRadius::Length(ref lop) => ShapeRadius::Length(lop.to_computed_value(cx)),
|
||||||
|
ShapeRadius::ClosestSide => ShapeRadius::ClosestSide,
|
||||||
|
ShapeRadius::FarthestSide => ShapeRadius::FarthestSide,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
match *computed {
|
||||||
|
ShapeRadius::Length(ref lop) => ShapeRadius::Length(ToComputedValue::from_computed_value(lop)),
|
||||||
|
ShapeRadius::ClosestSide => ShapeRadius::ClosestSide,
|
||||||
|
ShapeRadius::FarthestSide => ShapeRadius::FarthestSide,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
|
||||||
|
// NOTE: Basic shapes spec says that these are the only two values, however
|
||||||
|
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
|
||||||
|
// says that it can also be `inherit`
|
||||||
|
define_css_keyword_enum!(FillRule:
|
||||||
|
"nonzero" => NonZero,
|
||||||
|
"evenodd" => EvenOdd
|
||||||
|
);
|
||||||
|
|
||||||
|
impl ComputedValueAsSpecified for FillRule {}
|
||||||
|
|
||||||
|
impl Default for FillRule {
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self { FillRule::NonZero }
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
/// A generic type for representing the `polygon()` function
|
||||||
|
///
|
||||||
|
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
|
||||||
|
pub struct Polygon<L> {
|
||||||
|
/// The filling rule for a polygon.
|
||||||
|
pub fill: FillRule,
|
||||||
|
/// A collection of (x, y) coordinates to draw the polygon.
|
||||||
|
pub coordinates: Vec<(L, L)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: Parse> Polygon<L> {
|
||||||
|
/// Parse the inner arguments of a `polygon` function.
|
||||||
|
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
let fill = input.try(|i| -> Result<_, ()> {
|
||||||
|
let fill = FillRule::parse(i)?;
|
||||||
|
i.expect_comma()?; // only eat the comma if there is something before it
|
||||||
|
Ok(fill)
|
||||||
|
}).ok().unwrap_or_default();
|
||||||
|
|
||||||
|
let buf = input.parse_comma_separated(|i| {
|
||||||
|
Ok((L::parse(context, i)?, L::parse(context, i)?))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(Polygon {
|
||||||
|
fill: fill,
|
||||||
|
coordinates: buf,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: Parse> Parse for Polygon<L> {
|
||||||
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
match input.expect_function() {
|
||||||
|
Ok(ref s) if s.eq_ignore_ascii_case("polygon") =>
|
||||||
|
input.parse_nested_block(|i| Polygon::parse_function_arguments(context, i)),
|
||||||
|
_ => Err(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToCss> ToCss for Polygon<L> {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
dest.write_str("polygon(")?;
|
||||||
|
if self.fill != FillRule::default() {
|
||||||
|
self.fill.to_css(dest)?;
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, coord) in self.coordinates.iter().enumerate() {
|
||||||
|
if i > 0 {
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
}
|
||||||
|
|
||||||
|
coord.0.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
coord.1.to_css(dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToComputedValue> ToComputedValue for Polygon<L> {
|
||||||
|
type ComputedValue = Polygon<L::ComputedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
||||||
|
Polygon {
|
||||||
|
fill: self.fill.to_computed_value(cx),
|
||||||
|
coordinates: self.coordinates.iter().map(|c| {
|
||||||
|
(c.0.to_computed_value(cx), c.1.to_computed_value(cx))
|
||||||
|
}).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
Polygon {
|
||||||
|
fill: ToComputedValue::from_computed_value(&computed.fill),
|
||||||
|
coordinates: computed.coordinates.iter().map(|c| {
|
||||||
|
(ToComputedValue::from_computed_value(&c.0),
|
||||||
|
ToComputedValue::from_computed_value(&c.1))
|
||||||
|
}).collect(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
/// https://drafts.csswg.org/css-shapes/#funcdef-inset
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub struct InsetRect<L> {
|
||||||
|
pub top: L,
|
||||||
|
pub right: L,
|
||||||
|
pub bottom: L,
|
||||||
|
pub left: L,
|
||||||
|
pub round: Option<BorderRadius<L>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToCss + PartialEq> ToCss for InsetRect<L> {
|
||||||
|
// XXXManishearth We should try to reduce the number of values printed here
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
dest.write_str("inset(")?;
|
||||||
|
self.top.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.right.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.bottom.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.left.to_css(dest)?;
|
||||||
|
if let Some(ref radius) = self.round {
|
||||||
|
dest.write_str(" round ")?;
|
||||||
|
radius.to_css(dest)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToComputedValue> ToComputedValue for InsetRect<L> {
|
||||||
|
type ComputedValue = InsetRect<L::ComputedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
||||||
|
InsetRect {
|
||||||
|
top: self.top.to_computed_value(cx),
|
||||||
|
right: self.right.to_computed_value(cx),
|
||||||
|
bottom: self.bottom.to_computed_value(cx),
|
||||||
|
left: self.left.to_computed_value(cx),
|
||||||
|
round: self.round.as_ref().map(|r| r.to_computed_value(cx)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
InsetRect {
|
||||||
|
top: ToComputedValue::from_computed_value(&computed.top),
|
||||||
|
right: ToComputedValue::from_computed_value(&computed.right),
|
||||||
|
bottom: ToComputedValue::from_computed_value(&computed.bottom),
|
||||||
|
left: ToComputedValue::from_computed_value(&computed.left),
|
||||||
|
round: computed.round.as_ref().map(|r| ToComputedValue::from_computed_value(r)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A shape source, for some reference box
|
||||||
|
///
|
||||||
|
/// `clip-path` uses ShapeSource<BasicShape, GeometryBox>,
|
||||||
|
/// `shape-outside` uses ShapeSource<BasicShape, ShapeBox>
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub enum ShapeSource<B, T> {
|
||||||
|
Url(SpecifiedUrl),
|
||||||
|
Shape(B, Option<T>),
|
||||||
|
Box(T),
|
||||||
|
None,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B, T> HasViewportPercentage for ShapeSource<B, T> {
|
||||||
|
#[inline]
|
||||||
|
fn has_viewport_percentage(&self) -> bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: ToCss, T: ToCss> ToCss for ShapeSource<B, T> {
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
ShapeSource::Url(ref url) => url.to_css(dest),
|
||||||
|
ShapeSource::Shape(ref shape, Some(ref ref_box)) => {
|
||||||
|
shape.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
ref_box.to_css(dest)
|
||||||
|
},
|
||||||
|
ShapeSource::Shape(ref shape, None) => shape.to_css(dest),
|
||||||
|
ShapeSource::Box(ref val) => val.to_css(dest),
|
||||||
|
ShapeSource::None => dest.write_str("none"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: Parse, T: Parse> Parse for ShapeSource<B, T> {
|
||||||
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
if input.try(|i| i.expect_ident_matching("none")).is_ok() {
|
||||||
|
return Ok(ShapeSource::None)
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Ok(url) = input.try(|i| SpecifiedUrl::parse(context, i)) {
|
||||||
|
return Ok(ShapeSource::Url(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_component<U: Parse>(context: &ParserContext, input: &mut Parser,
|
||||||
|
component: &mut Option<U>) -> bool {
|
||||||
|
if component.is_some() {
|
||||||
|
return false // already parsed this component
|
||||||
|
}
|
||||||
|
|
||||||
|
*component = input.try(|i| U::parse(context, i)).ok();
|
||||||
|
component.is_some()
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut shape = None;
|
||||||
|
let mut ref_box = None;
|
||||||
|
|
||||||
|
while parse_component(context, input, &mut shape) ||
|
||||||
|
parse_component(context, input, &mut ref_box) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(shp) = shape {
|
||||||
|
return Ok(ShapeSource::Shape(shp, ref_box))
|
||||||
|
}
|
||||||
|
|
||||||
|
ref_box.map(|v| ShapeSource::Box(v)).ok_or(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<B: ToComputedValue, T: ToComputedValue> ToComputedValue for ShapeSource<B, T> {
|
||||||
|
type ComputedValue = ShapeSource<B::ComputedValue, T::ComputedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
||||||
|
match *self {
|
||||||
|
ShapeSource::Url(ref url) => ShapeSource::Url(url.to_computed_value(cx)),
|
||||||
|
ShapeSource::Shape(ref shape, ref ref_box) => {
|
||||||
|
ShapeSource::Shape(shape.to_computed_value(cx),
|
||||||
|
ref_box.as_ref().map(|ref val| val.to_computed_value(cx)))
|
||||||
|
},
|
||||||
|
ShapeSource::Box(ref ref_box) => ShapeSource::Box(ref_box.to_computed_value(cx)),
|
||||||
|
ShapeSource::None => ShapeSource::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
match *computed {
|
||||||
|
ShapeSource::Url(ref url) => ShapeSource::Url(SpecifiedUrl::from_computed_value(url)),
|
||||||
|
ShapeSource::Shape(ref shape, ref ref_box) => {
|
||||||
|
ShapeSource::Shape(ToComputedValue::from_computed_value(shape),
|
||||||
|
ref_box.as_ref().map(|val| ToComputedValue::from_computed_value(val)))
|
||||||
|
},
|
||||||
|
ShapeSource::Box(ref ref_box) => ShapeSource::Box(ToComputedValue::from_computed_value(ref_box)),
|
||||||
|
ShapeSource::None => ShapeSource::None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
70
components/style/values/generics/mod.rs
Normal file
70
components/style/values/generics/mod.rs
Normal file
|
@ -0,0 +1,70 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
//! Generic types that share their serialization implementations
|
||||||
|
//! for both specified and computed values.
|
||||||
|
|
||||||
|
use euclid::size::Size2D;
|
||||||
|
use std::fmt;
|
||||||
|
use style_traits::ToCss;
|
||||||
|
use super::HasViewportPercentage;
|
||||||
|
use super::computed::{Context, ToComputedValue};
|
||||||
|
|
||||||
|
pub use self::basic_shape::serialize_radius_values;
|
||||||
|
|
||||||
|
pub mod basic_shape;
|
||||||
|
pub mod position;
|
||||||
|
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
/// A type for representing CSS `widthh` and `height` values.
|
||||||
|
pub struct BorderRadiusSize<L>(pub Size2D<L>);
|
||||||
|
|
||||||
|
impl<L> HasViewportPercentage for BorderRadiusSize<L> {
|
||||||
|
#[inline]
|
||||||
|
fn has_viewport_percentage(&self) -> bool { false }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L> BorderRadiusSize<L> {
|
||||||
|
#[inline]
|
||||||
|
/// Create a new `BorderRadiusSize` for an area of given width and height.
|
||||||
|
pub fn new(width: L, height: L) -> BorderRadiusSize<L> {
|
||||||
|
BorderRadiusSize(Size2D::new(width, height))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: Clone> BorderRadiusSize<L> {
|
||||||
|
#[inline]
|
||||||
|
/// Create a new `BorderRadiusSize` for a circle of given radius.
|
||||||
|
pub fn circle(radius: L) -> BorderRadiusSize<L> {
|
||||||
|
BorderRadiusSize(Size2D::new(radius.clone(), radius))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToCss> ToCss for BorderRadiusSize<L> {
|
||||||
|
#[inline]
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
self.0.width.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
self.0.height.to_css(dest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L: ToComputedValue> ToComputedValue for BorderRadiusSize<L> {
|
||||||
|
type ComputedValue = BorderRadiusSize<L::ComputedValue>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
let w = self.0.width.to_computed_value(context);
|
||||||
|
let h = self.0.height.to_computed_value(context);
|
||||||
|
BorderRadiusSize(Size2D::new(w, h))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
let w = ToComputedValue::from_computed_value(&computed.0.width);
|
||||||
|
let h = ToComputedValue::from_computed_value(&computed.0.height);
|
||||||
|
BorderRadiusSize(Size2D::new(w, h))
|
||||||
|
}
|
||||||
|
}
|
302
components/style/values/generics/position.rs
Normal file
302
components/style/values/generics/position.rs
Normal file
|
@ -0,0 +1,302 @@
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* 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/. */
|
||||||
|
|
||||||
|
//! 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};
|
||||||
|
|
||||||
|
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)]
|
||||||
|
#[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,
|
||||||
|
/// The vertical component of position.
|
||||||
|
pub vertical: V,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A generic type for representing positions with keywords.
|
||||||
|
pub type PositionWithKeyword<L> = Position<HorizontalPosition<L>, VerticalPosition<L>>;
|
||||||
|
|
||||||
|
impl<H: HasViewportPercentage, V: HasViewportPercentage> HasViewportPercentage for Position<H, V> {
|
||||||
|
#[inline]
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>;
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
Position {
|
||||||
|
horizontal: self.horizontal.to_computed_value(context),
|
||||||
|
vertical: self.vertical.to_computed_value(context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
Position {
|
||||||
|
horizontal: ToComputedValue::from_computed_value(&computed.horizontal),
|
||||||
|
vertical: ToComputedValue::from_computed_value(&computed.vertical),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -82,6 +82,7 @@ macro_rules! add_impls_for_keyword_enum {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod computed;
|
pub mod computed;
|
||||||
|
pub mod generics;
|
||||||
pub mod specified;
|
pub mod specified;
|
||||||
|
|
||||||
/// A CSS float value.
|
/// A CSS float value.
|
||||||
|
|
|
@ -8,129 +8,25 @@
|
||||||
//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
|
//! [basic-shape]: https://drafts.csswg.org/css-shapes/#typedef-basic-shape
|
||||||
|
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
use euclid::size::Size2D;
|
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use properties::shorthands::{parse_four_sides, serialize_four_sides};
|
use properties::shorthands::parse_four_sides;
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use values::HasViewportPercentage;
|
use values::HasViewportPercentage;
|
||||||
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
use values::computed::{ComputedValueAsSpecified, Context, ToComputedValue};
|
||||||
use values::computed::basic_shape as computed_basic_shape;
|
use values::computed::basic_shape as computed_basic_shape;
|
||||||
use values::specified::{BorderRadiusSize, LengthOrPercentage, Percentage};
|
use values::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::position::{Keyword, Position};
|
||||||
use values::specified::url::SpecifiedUrl;
|
|
||||||
|
|
||||||
/// A shape source, for some reference box
|
/// The specified value used by `clip-path`
|
||||||
///
|
pub type ShapeWithGeometryBox = ShapeSource<BasicShape, GeometryBox>;
|
||||||
/// clip-path uses ShapeSource<GeometryBox>,
|
|
||||||
/// shape-outside uses ShapeSource<ShapeBox>
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum ShapeSource<T> {
|
|
||||||
Url(SpecifiedUrl),
|
|
||||||
Shape(BasicShape, Option<T>),
|
|
||||||
Box(T),
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Default for ShapeSource<T> {
|
/// The specified value used by `shape-outside`
|
||||||
fn default() -> Self {
|
pub type ShapeWithShapeBox = ShapeSource<BasicShape, ShapeBox>;
|
||||||
ShapeSource::None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ToCss> ToCss for ShapeSource<T> {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
ShapeSource::Url(ref url) => url.to_css(dest),
|
|
||||||
ShapeSource::Shape(ref shape, Some(ref reference)) => {
|
|
||||||
try!(shape.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
reference.to_css(dest)
|
|
||||||
}
|
|
||||||
ShapeSource::Shape(ref shape, None) => shape.to_css(dest),
|
|
||||||
ShapeSource::Box(ref reference) => reference.to_css(dest),
|
|
||||||
ShapeSource::None => dest.write_str("none"),
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: Parse> Parse for ShapeSource<T> {
|
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
|
||||||
if input.try(|input| input.expect_ident_matching("none")).is_ok() {
|
|
||||||
return Ok(ShapeSource::None)
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) {
|
|
||||||
return Ok(ShapeSource::Url(url))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_component<U: Parse>(context: &ParserContext, input: &mut Parser,
|
|
||||||
component: &mut Option<U>) -> bool {
|
|
||||||
if component.is_some() {
|
|
||||||
return false // already parsed this component
|
|
||||||
}
|
|
||||||
|
|
||||||
*component = input.try(|i| U::parse(context, i)).ok();
|
|
||||||
component.is_some()
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut shape = None;
|
|
||||||
let mut reference = None;
|
|
||||||
|
|
||||||
while parse_component(context, input, &mut shape) ||
|
|
||||||
parse_component(context, input, &mut reference) {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(shp) = shape {
|
|
||||||
return Ok(ShapeSource::Shape(shp, reference))
|
|
||||||
}
|
|
||||||
|
|
||||||
match reference {
|
|
||||||
Some(r) => Ok(ShapeSource::Box(r)),
|
|
||||||
None => Err(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: ToComputedValue> ToComputedValue for ShapeSource<T> {
|
|
||||||
type ComputedValue = computed_basic_shape::ShapeSource<T::ComputedValue>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
|
||||||
match *self {
|
|
||||||
ShapeSource::Url(ref url) => computed_basic_shape::ShapeSource::Url(url.to_computed_value(cx)),
|
|
||||||
ShapeSource::Shape(ref shape, ref reference) => {
|
|
||||||
computed_basic_shape::ShapeSource::Shape(
|
|
||||||
shape.to_computed_value(cx),
|
|
||||||
reference.as_ref().map(|ref r| r.to_computed_value(cx)))
|
|
||||||
},
|
|
||||||
ShapeSource::Box(ref reference) =>
|
|
||||||
computed_basic_shape::ShapeSource::Box(reference.to_computed_value(cx)),
|
|
||||||
ShapeSource::None => computed_basic_shape::ShapeSource::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
|
||||||
match *computed {
|
|
||||||
computed_basic_shape::ShapeSource::Url(ref url) =>
|
|
||||||
ShapeSource::Url(SpecifiedUrl::from_computed_value(url)),
|
|
||||||
computed_basic_shape::ShapeSource::Shape(ref shape, ref reference) => {
|
|
||||||
ShapeSource::Shape(
|
|
||||||
ToComputedValue::from_computed_value(shape),
|
|
||||||
reference.as_ref().map(|r| ToComputedValue::from_computed_value(r)))
|
|
||||||
}
|
|
||||||
computed_basic_shape::ShapeSource::Box(ref reference) =>
|
|
||||||
ShapeSource::Box(ToComputedValue::from_computed_value(reference)),
|
|
||||||
computed_basic_shape::ShapeSource::None => ShapeSource::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
@ -200,23 +96,14 @@ impl ToComputedValue for BasicShape {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
/// The specified value of `inset()`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type InsetRect = GenericInsetRect<LengthOrPercentage>;
|
||||||
/// https://drafts.csswg.org/css-shapes/#funcdef-inset
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct InsetRect {
|
|
||||||
pub top: LengthOrPercentage,
|
|
||||||
pub right: LengthOrPercentage,
|
|
||||||
pub bottom: LengthOrPercentage,
|
|
||||||
pub left: LengthOrPercentage,
|
|
||||||
pub round: Option<BorderRadius>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InsetRect {
|
impl InsetRect {
|
||||||
#[allow(missing_docs)]
|
/// Parse the inner function arguments of `inset()`
|
||||||
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<InsetRect, ()> {
|
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<InsetRect, ()> {
|
||||||
let (t, r, b, l) = try!(parse_four_sides(input, |i| LengthOrPercentage::parse(context, i)));
|
let (t, r, b, l) = parse_four_sides(input, |i| LengthOrPercentage::parse(context, i))?;
|
||||||
let mut rect = InsetRect {
|
let mut rect = GenericInsetRect {
|
||||||
top: t,
|
top: t,
|
||||||
right: r,
|
right: r,
|
||||||
bottom: b,
|
bottom: b,
|
||||||
|
@ -236,58 +123,12 @@ impl Parse for InsetRect {
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
match input.try(|i| i.expect_function()) {
|
match input.try(|i| i.expect_function()) {
|
||||||
Ok(ref s) if s.eq_ignore_ascii_case("inset") =>
|
Ok(ref s) if s.eq_ignore_ascii_case("inset") =>
|
||||||
input.parse_nested_block(|i| InsetRect::parse_function_arguments(context, i)),
|
input.parse_nested_block(|i| GenericInsetRect::parse_function_arguments(context, i)),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for InsetRect {
|
|
||||||
// XXXManishearth again, we should try to reduce the number of values printed here
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(dest.write_str("inset("));
|
|
||||||
try!(self.top.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.right.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.bottom.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(self.left.to_css(dest));
|
|
||||||
if let Some(ref radius) = self.round {
|
|
||||||
try!(dest.write_str(" round "));
|
|
||||||
try!(radius.to_css(dest));
|
|
||||||
}
|
|
||||||
|
|
||||||
dest.write_str(")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for InsetRect {
|
|
||||||
type ComputedValue = computed_basic_shape::InsetRect;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
|
||||||
computed_basic_shape::InsetRect {
|
|
||||||
top: self.top.to_computed_value(cx),
|
|
||||||
right: self.right.to_computed_value(cx),
|
|
||||||
bottom: self.bottom.to_computed_value(cx),
|
|
||||||
left: self.left.to_computed_value(cx),
|
|
||||||
round: self.round.as_ref().map(|r| r.to_computed_value(cx)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
|
||||||
InsetRect {
|
|
||||||
top: ToComputedValue::from_computed_value(&computed.top),
|
|
||||||
right: ToComputedValue::from_computed_value(&computed.right),
|
|
||||||
bottom: ToComputedValue::from_computed_value(&computed.bottom),
|
|
||||||
left: ToComputedValue::from_computed_value(&computed.left),
|
|
||||||
round: computed.round.map(|ref r| ToComputedValue::from_computed_value(r)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-shapes/#basic-shape-serialization
|
/// https://drafts.csswg.org/css-shapes/#basic-shape-serialization
|
||||||
///
|
///
|
||||||
/// Positions get serialized differently with basic shapes. Keywords
|
/// Positions get serialized differently with basic shapes. Keywords
|
||||||
|
@ -336,13 +177,11 @@ fn serialize_basicshape_position<W>(position: &Position, dest: &mut W) -> fmt::R
|
||||||
replace_with_percent(y).to_css(dest)
|
replace_with_percent(y).to_css(dest)
|
||||||
}
|
}
|
||||||
|
|
||||||
match (position.horizontal.keyword, position.horizontal.position.clone(),
|
match (position.horizontal.0.keyword, position.horizontal.0.position.clone(),
|
||||||
position.vertical.keyword, position.vertical.position.clone()) {
|
position.vertical.0.keyword, position.vertical.0.position.clone()) {
|
||||||
(Some(hk), None, Some(vk), None) => {
|
(Some(hk), None, Some(vk), None) => {
|
||||||
// two keywords: serialize as two lengths
|
// two keywords: serialize as two lengths
|
||||||
serialize_position_pair(hk.to_length_or_percentage(),
|
serialize_position_pair(hk.into(), vk.into(), dest)
|
||||||
vk.to_length_or_percentage(),
|
|
||||||
dest)
|
|
||||||
}
|
}
|
||||||
(None, Some(hp), None, Some(vp)) => {
|
(None, Some(hp), None, Some(vp)) => {
|
||||||
// two lengths: just serialize regularly
|
// two lengths: just serialize regularly
|
||||||
|
@ -410,7 +249,7 @@ impl Parse for Circle {
|
||||||
impl ToCss for Circle {
|
impl ToCss for Circle {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
try!(dest.write_str("circle("));
|
try!(dest.write_str("circle("));
|
||||||
if ShapeRadius::ClosestSide != self.radius {
|
if GenericShapeRadius::ClosestSide != self.radius {
|
||||||
try!(self.radius.to_css(dest));
|
try!(self.radius.to_css(dest));
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
}
|
}
|
||||||
|
@ -484,7 +323,7 @@ impl Parse for Ellipse {
|
||||||
impl ToCss for Ellipse {
|
impl ToCss for Ellipse {
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
try!(dest.write_str("ellipse("));
|
try!(dest.write_str("ellipse("));
|
||||||
if !self.semiaxis_x.is_default() || !self.semiaxis_y.is_default() {
|
if self.semiaxis_x != ShapeRadius::default() || self.semiaxis_y != ShapeRadius::default() {
|
||||||
try!(self.semiaxis_x.to_css(dest));
|
try!(self.semiaxis_x.to_css(dest));
|
||||||
try!(dest.write_str(" "));
|
try!(dest.write_str(" "));
|
||||||
try!(self.semiaxis_y.to_css(dest));
|
try!(self.semiaxis_y.to_css(dest));
|
||||||
|
@ -519,229 +358,41 @@ impl ToComputedValue for Ellipse {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The specified value of `Polygon`
|
||||||
|
pub type Polygon = GenericPolygon<LengthOrPercentage>;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
/// The specified value of `ShapeRadius`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type ShapeRadius = GenericShapeRadius<LengthOrPercentage>;
|
||||||
/// https://drafts.csswg.org/css-shapes/#funcdef-polygon
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct Polygon {
|
|
||||||
pub fill: FillRule,
|
|
||||||
pub coordinates: Vec<(LengthOrPercentage, LengthOrPercentage)>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Polygon {
|
impl Parse for ShapeRadius {
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn parse_function_arguments(context: &ParserContext, input: &mut Parser) -> Result<Polygon, ()> {
|
|
||||||
let fill = input.try(|input| {
|
|
||||||
let fill = FillRule::parse(input);
|
|
||||||
// only eat the comma if there is something before it
|
|
||||||
try!(input.expect_comma());
|
|
||||||
fill
|
|
||||||
}).ok().unwrap_or_else(Default::default);
|
|
||||||
|
|
||||||
let buf = try!(input.parse_comma_separated(|input| {
|
|
||||||
Ok((try!(LengthOrPercentage::parse(context, input)),
|
|
||||||
try!(LengthOrPercentage::parse(context, input))))
|
|
||||||
}));
|
|
||||||
|
|
||||||
Ok(Polygon {
|
|
||||||
fill: fill,
|
|
||||||
coordinates: buf,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for Polygon {
|
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
match input.try(|i| i.expect_function()) {
|
if let Ok(lop) = input.try(|i| LengthOrPercentage::parse_non_negative(context, i)) {
|
||||||
Ok(ref s) if s.eq_ignore_ascii_case("polygon") =>
|
return Ok(GenericShapeRadius::Length(lop))
|
||||||
input.parse_nested_block(|i| Polygon::parse_function_arguments(context, i)),
|
}
|
||||||
|
|
||||||
|
match_ignore_ascii_case! { &input.expect_ident()?,
|
||||||
|
"closest-side" => Ok(GenericShapeRadius::ClosestSide),
|
||||||
|
"farthest-side" => Ok(GenericShapeRadius::FarthestSide),
|
||||||
_ => Err(())
|
_ => Err(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToCss for Polygon {
|
/// The specified value of `BorderRadius`
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
pub type BorderRadius = GenericBorderRadius<LengthOrPercentage>;
|
||||||
try!(dest.write_str("polygon("));
|
|
||||||
let mut need_space = false;
|
|
||||||
if self.fill != Default::default() {
|
|
||||||
try!(self.fill.to_css(dest));
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
}
|
|
||||||
|
|
||||||
for coord in &self.coordinates {
|
|
||||||
if need_space {
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
}
|
|
||||||
|
|
||||||
try!(coord.0.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(coord.1.to_css(dest));
|
|
||||||
need_space = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
dest.write_str(")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for Polygon {
|
|
||||||
type ComputedValue = computed_basic_shape::Polygon;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
|
||||||
computed_basic_shape::Polygon {
|
|
||||||
fill: self.fill.to_computed_value(cx),
|
|
||||||
coordinates: self.coordinates.iter()
|
|
||||||
.map(|c| {
|
|
||||||
(c.0.to_computed_value(cx),
|
|
||||||
c.1.to_computed_value(cx))
|
|
||||||
}).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
|
||||||
Polygon {
|
|
||||||
fill: ToComputedValue::from_computed_value(&computed.fill),
|
|
||||||
coordinates: computed.coordinates.iter()
|
|
||||||
.map(|c| {
|
|
||||||
(ToComputedValue::from_computed_value(&c.0),
|
|
||||||
ToComputedValue::from_computed_value(&c.1))
|
|
||||||
}).collect(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-shapes/#typedef-shape-radius
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum ShapeRadius {
|
|
||||||
Length(LengthOrPercentage),
|
|
||||||
ClosestSide,
|
|
||||||
FarthestSide,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ShapeRadius {
|
|
||||||
fn is_default(&self) -> bool {
|
|
||||||
*self == ShapeRadius::ClosestSide
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ShapeRadius {
|
|
||||||
fn default() -> Self {
|
|
||||||
ShapeRadius::ClosestSide
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for ShapeRadius {
|
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
|
||||||
input.try(|i| LengthOrPercentage::parse_non_negative(context, i)).map(ShapeRadius::Length).or_else(|_| {
|
|
||||||
match_ignore_ascii_case! { &try!(input.expect_ident()),
|
|
||||||
"closest-side" => Ok(ShapeRadius::ClosestSide),
|
|
||||||
"farthest-side" => Ok(ShapeRadius::FarthestSide),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for ShapeRadius {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
ShapeRadius::Length(ref lop) => lop.to_css(dest),
|
|
||||||
ShapeRadius::ClosestSide => dest.write_str("closest-side"),
|
|
||||||
ShapeRadius::FarthestSide => dest.write_str("farthest-side"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
impl ToComputedValue for ShapeRadius {
|
|
||||||
type ComputedValue = computed_basic_shape::ShapeRadius;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
|
||||||
match *self {
|
|
||||||
ShapeRadius::Length(ref lop) =>
|
|
||||||
computed_basic_shape::ShapeRadius::Length(lop.to_computed_value(cx)),
|
|
||||||
ShapeRadius::ClosestSide => computed_basic_shape::ShapeRadius::ClosestSide,
|
|
||||||
ShapeRadius::FarthestSide => computed_basic_shape::ShapeRadius::FarthestSide,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
|
||||||
match *computed {
|
|
||||||
computed_basic_shape::ShapeRadius::Length(ref lop) =>
|
|
||||||
ShapeRadius::Length(ToComputedValue::from_computed_value(lop)),
|
|
||||||
computed_basic_shape::ShapeRadius::ClosestSide => ShapeRadius::ClosestSide,
|
|
||||||
computed_basic_shape::ShapeRadius::FarthestSide => ShapeRadius::FarthestSide,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-backgrounds-3/#border-radius
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct BorderRadius {
|
|
||||||
pub top_left: BorderRadiusSize,
|
|
||||||
pub top_right: BorderRadiusSize,
|
|
||||||
pub bottom_right: BorderRadiusSize,
|
|
||||||
pub bottom_left: BorderRadiusSize,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Serialization helper for types of longhands like `border-radius` and `outline-radius`
|
|
||||||
pub fn serialize_radius_values<L, W>(dest: &mut W, top_left: &Size2D<L>,
|
|
||||||
top_right: &Size2D<L>, bottom_right: &Size2D<L>,
|
|
||||||
bottom_left: &Size2D<L>) -> fmt::Result
|
|
||||||
where L: ToCss + PartialEq, W: fmt::Write
|
|
||||||
{
|
|
||||||
if top_left.width == top_left.height &&
|
|
||||||
top_right.width == top_right.height &&
|
|
||||||
bottom_right.width == bottom_right.height &&
|
|
||||||
bottom_left.width == bottom_left.height {
|
|
||||||
serialize_four_sides(dest,
|
|
||||||
&top_left.width,
|
|
||||||
&top_right.width,
|
|
||||||
&bottom_right.width,
|
|
||||||
&bottom_left.width)
|
|
||||||
} else {
|
|
||||||
serialize_four_sides(dest,
|
|
||||||
&top_left.width,
|
|
||||||
&top_right.width,
|
|
||||||
&bottom_right.width,
|
|
||||||
&bottom_left.width)?;
|
|
||||||
dest.write_str(" / ")?;
|
|
||||||
serialize_four_sides(dest,
|
|
||||||
&top_left.height,
|
|
||||||
&top_right.height,
|
|
||||||
&bottom_right.height,
|
|
||||||
&bottom_left.height)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for BorderRadius {
|
|
||||||
#[inline]
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
serialize_radius_values(dest, &self.top_left.0, &self.top_right.0,
|
|
||||||
&self.bottom_right.0, &self.bottom_left.0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for BorderRadius {
|
impl Parse for BorderRadius {
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
let mut widths = try!(parse_one_set_of_border_values(context, input));
|
let mut widths = parse_one_set_of_border_values(context, input)?;
|
||||||
let mut heights = if input.try(|input| input.expect_delim('/')).is_ok() {
|
let mut heights = if input.try(|input| input.expect_delim('/')).is_ok() {
|
||||||
try!(parse_one_set_of_border_values(context, input))
|
parse_one_set_of_border_values(context, input)?
|
||||||
} else {
|
} else {
|
||||||
[widths[0].clone(),
|
[widths[0].clone(),
|
||||||
widths[1].clone(),
|
widths[1].clone(),
|
||||||
widths[2].clone(),
|
widths[2].clone(),
|
||||||
widths[3].clone()]
|
widths[3].clone()]
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(BorderRadius {
|
Ok(BorderRadius {
|
||||||
top_left: BorderRadiusSize::new(widths[0].take(), heights[0].take()),
|
top_left: BorderRadiusSize::new(widths[0].take(), heights[0].take()),
|
||||||
top_right: BorderRadiusSize::new(widths[1].take(), heights[1].take()),
|
top_right: BorderRadiusSize::new(widths[1].take(), heights[1].take()),
|
||||||
|
@ -773,48 +424,6 @@ fn parse_one_set_of_border_values(context: &ParserContext, mut input: &mut Parse
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl ToComputedValue for BorderRadius {
|
|
||||||
type ComputedValue = computed_basic_shape::BorderRadius;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, cx: &Context) -> Self::ComputedValue {
|
|
||||||
computed_basic_shape::BorderRadius {
|
|
||||||
top_left: self.top_left.to_computed_value(cx),
|
|
||||||
top_right: self.top_right.to_computed_value(cx),
|
|
||||||
bottom_right: self.bottom_right.to_computed_value(cx),
|
|
||||||
bottom_left: self.bottom_left.to_computed_value(cx),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
|
||||||
BorderRadius {
|
|
||||||
top_left: ToComputedValue::from_computed_value(&computed.top_left),
|
|
||||||
top_right: ToComputedValue::from_computed_value(&computed.top_right),
|
|
||||||
bottom_right: ToComputedValue::from_computed_value(&computed.bottom_right),
|
|
||||||
bottom_left: ToComputedValue::from_computed_value(&computed.bottom_left),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// https://drafts.csswg.org/css-shapes/#typedef-fill-rule
|
|
||||||
// NOTE: Basic shapes spec says that these are the only two values, however
|
|
||||||
// https://www.w3.org/TR/SVG/painting.html#FillRuleProperty
|
|
||||||
// says that it can also be `inherit`
|
|
||||||
define_css_keyword_enum!(FillRule:
|
|
||||||
"nonzero" => NonZero,
|
|
||||||
"evenodd" => EvenOdd
|
|
||||||
);
|
|
||||||
|
|
||||||
impl ComputedValueAsSpecified for FillRule {}
|
|
||||||
|
|
||||||
impl Default for FillRule {
|
|
||||||
fn default() -> Self {
|
|
||||||
FillRule::NonZero
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
|
/// https://drafts.fxtf.org/css-masking-1/#typedef-geometry-box
|
||||||
#[derive(Clone, PartialEq, Copy, Debug)]
|
#[derive(Clone, PartialEq, Copy, Debug)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
|
|
@ -1146,7 +1146,9 @@ impl ToCss for LengthOrPercentage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl LengthOrPercentage {
|
impl LengthOrPercentage {
|
||||||
|
#[inline]
|
||||||
/// Returns a `zero` length.
|
/// Returns a `zero` length.
|
||||||
pub fn zero() -> LengthOrPercentage {
|
pub fn zero() -> LengthOrPercentage {
|
||||||
LengthOrPercentage::Length(NoCalcLength::zero())
|
LengthOrPercentage::Length(NoCalcLength::zero())
|
||||||
|
|
|
@ -22,6 +22,7 @@ use style_traits::values::specified::AllowedNumericType;
|
||||||
use super::{Auto, CSSFloat, CSSInteger, HasViewportPercentage, Either, None_};
|
use super::{Auto, CSSFloat, CSSInteger, HasViewportPercentage, Either, None_};
|
||||||
use super::computed::{self, Context};
|
use super::computed::{self, Context};
|
||||||
use super::computed::{Shadow as ComputedShadow, ToComputedValue};
|
use super::computed::{Shadow as ComputedShadow, ToComputedValue};
|
||||||
|
use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
|
||||||
|
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||||
|
@ -282,30 +283,8 @@ pub fn parse_number_with_clamping_mode(context: &ParserContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
/// The specified value of `BorderRadiusSize`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type BorderRadiusSize = GenericBorderRadiusSize<LengthOrPercentage>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct BorderRadiusSize(pub Size2D<LengthOrPercentage>);
|
|
||||||
|
|
||||||
no_viewport_percentage!(BorderRadiusSize);
|
|
||||||
|
|
||||||
impl BorderRadiusSize {
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn zero() -> BorderRadiusSize {
|
|
||||||
let zero = LengthOrPercentage::Length(NoCalcLength::zero());
|
|
||||||
BorderRadiusSize(Size2D::new(zero.clone(), zero))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn new(width: LengthOrPercentage, height: LengthOrPercentage) -> BorderRadiusSize {
|
|
||||||
BorderRadiusSize(Size2D::new(width, height))
|
|
||||||
}
|
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub fn circle(radius: LengthOrPercentage) -> BorderRadiusSize {
|
|
||||||
BorderRadiusSize(Size2D::new(radius.clone(), radius))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for BorderRadiusSize {
|
impl Parse for BorderRadiusSize {
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -313,15 +292,7 @@ impl Parse for BorderRadiusSize {
|
||||||
let first = try!(LengthOrPercentage::parse_non_negative(context, input));
|
let first = try!(LengthOrPercentage::parse_non_negative(context, input));
|
||||||
let second = input.try(|i| LengthOrPercentage::parse_non_negative(context, i))
|
let second = input.try(|i| LengthOrPercentage::parse_non_negative(context, i))
|
||||||
.unwrap_or_else(|()| first.clone());
|
.unwrap_or_else(|()| first.clone());
|
||||||
Ok(BorderRadiusSize(Size2D::new(first, second)))
|
Ok(GenericBorderRadiusSize(Size2D::new(first, second)))
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for BorderRadiusSize {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(self.0.width.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
self.0.height.to_css(dest)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -8,616 +8,256 @@
|
||||||
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
//! [position]: https://drafts.csswg.org/css-backgrounds-3/#position
|
||||||
|
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use cssparser::{Parser, Token};
|
use cssparser::Parser;
|
||||||
use parser::{Parse, ParserContext};
|
use parser::{Parse, ParserContext};
|
||||||
use std::fmt;
|
use properties::longhands::parse_origin;
|
||||||
use style_traits::ToCss;
|
use std::mem;
|
||||||
use values::HasViewportPercentage;
|
use values::Either;
|
||||||
use values::computed::{self, CalcLengthOrPercentage, Context};
|
use values::computed::{CalcLengthOrPercentage, Context};
|
||||||
use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, ToComputedValue};
|
use values::computed::{LengthOrPercentage as ComputedLengthOrPercentage, ToComputedValue};
|
||||||
use values::computed::position as computed_position;
|
use values::computed::position as computed_position;
|
||||||
|
use values::generics::position::{Position as GenericPosition, PositionValue, PositionWithKeyword};
|
||||||
|
use values::generics::position::HorizontalPosition as GenericHorizontalPosition;
|
||||||
|
use values::generics::position::VerticalPosition as GenericVerticalPosition;
|
||||||
use values::specified::{LengthOrPercentage, Percentage};
|
use values::specified::{LengthOrPercentage, Percentage};
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
pub use values::generics::position::Keyword;
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
/// A [position][pos].
|
|
||||||
///
|
|
||||||
/// [pos]: https://drafts.csswg.org/css-values/#position
|
|
||||||
pub struct Position {
|
|
||||||
/// The horizontal component.
|
|
||||||
pub horizontal: HorizontalPosition,
|
|
||||||
/// The vertical component.
|
|
||||||
pub vertical: VerticalPosition,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for Position {
|
/// The specified value of a CSS `<position>`
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
pub type Position = PositionWithKeyword<PositionValue<LengthOrPercentage>>;
|
||||||
macro_rules! to_css_with_keyword {
|
|
||||||
($pos:expr, $default_keyword:expr) => {
|
|
||||||
$pos.keyword.unwrap_or($default_keyword).to_css(dest)?;
|
|
||||||
|
|
||||||
if let Some(ref position) = $pos.position {
|
/// The specified value for `<position>` values without a keyword.
|
||||||
dest.write_str(" ")?;
|
pub type OriginPosition = GenericPosition<LengthOrPercentage, LengthOrPercentage>;
|
||||||
position.to_css(dest)?;
|
|
||||||
};
|
impl Parse for OriginPosition {
|
||||||
};
|
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))),
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut is_keyword_needed = false;
|
|
||||||
let position_x = &self.horizontal;
|
|
||||||
let position_y = &self.vertical;
|
|
||||||
|
|
||||||
if (position_x.keyword.is_some() && position_x.position.is_some()) ||
|
|
||||||
(position_y.keyword.is_some() && position_y.position.is_some()) {
|
|
||||||
is_keyword_needed = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if is_keyword_needed {
|
|
||||||
to_css_with_keyword!(position_x, Keyword::Left);
|
|
||||||
dest.write_str(" ")?;
|
|
||||||
to_css_with_keyword!(position_y, Keyword::Top);
|
|
||||||
} else {
|
|
||||||
position_x.to_css(dest)?;
|
|
||||||
dest.write_str(" ")?;
|
|
||||||
position_y.to_css(dest)?;
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl HasViewportPercentage for Position {
|
type PositionComponent = Either<LengthOrPercentage, Keyword>;
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
|
||||||
self.horizontal.has_viewport_percentage() || self.vertical.has_viewport_percentage()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Position {
|
impl Position {
|
||||||
/// Create a new position value.
|
/// Create a new position value from either a length or a keyword.
|
||||||
pub fn new(mut first_position: Option<PositionComponent>,
|
pub fn from_components(mut first_position: Option<PositionComponent>,
|
||||||
mut second_position: Option<PositionComponent>,
|
mut second_position: Option<PositionComponent>,
|
||||||
first_keyword: Option<PositionComponent>,
|
first_keyword: Option<PositionComponent>,
|
||||||
second_keyword: Option<PositionComponent>)
|
second_keyword: Option<PositionComponent>) -> Result<Position, ()> {
|
||||||
-> Result<Position, ()> {
|
|
||||||
// Unwrap for checking if values are at right place.
|
// Unwrap for checking if values are at right place.
|
||||||
let first_key = first_keyword.clone().unwrap_or(PositionComponent::Keyword(Keyword::Left));
|
let first_key = first_keyword.clone().unwrap_or(Either::Second(Keyword::Left));
|
||||||
let second_key = second_keyword.clone().unwrap_or(PositionComponent::Keyword(Keyword::Top));
|
let second_key = second_keyword.clone().unwrap_or(Either::Second(Keyword::Top));
|
||||||
|
|
||||||
// Check if position specified after center keyword.
|
let (horiz_keyword, vert_keyword) = match (&first_key, &second_key) {
|
||||||
if let PositionCategory::OtherKeyword = category(&first_key) {
|
// Check if a position is specified after center keyword.
|
||||||
if let Some(_) = first_position {
|
(&Either::Second(Keyword::Center), _) if first_position.is_some() => return Err(()),
|
||||||
return Err(());
|
(_, &Either::Second(Keyword::Center)) if second_position.is_some() => return Err(()),
|
||||||
};
|
|
||||||
};
|
|
||||||
if let PositionCategory::OtherKeyword = category(&second_key) {
|
|
||||||
if let Some(_) = second_position {
|
|
||||||
return Err(());
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// Check first and second keywords for both 2 and 4 value positions.
|
// Check first and second keywords for both 2 and 4 value positions.
|
||||||
let (horiz_keyword, vert_keyword) = match (category(&first_key), category(&second_key)) {
|
|
||||||
// Don't allow two vertical keywords or two horizontal keywords.
|
|
||||||
// also don't allow length/percentage values in the wrong position
|
|
||||||
(PositionCategory::HorizontalKeyword, PositionCategory::HorizontalKeyword) |
|
|
||||||
(PositionCategory::VerticalKeyword, PositionCategory::VerticalKeyword) |
|
|
||||||
(PositionCategory::LengthOrPercentage, PositionCategory::HorizontalKeyword) |
|
|
||||||
(PositionCategory::VerticalKeyword, PositionCategory::LengthOrPercentage) => return Err(()),
|
|
||||||
|
|
||||||
// FIXME(canaltinova): Allow logical keywords for Position. They are not in current spec yet.
|
// FIXME(canaltinova): Allow logical keywords for Position. They are not in current spec yet.
|
||||||
(PositionCategory::HorizontalLogicalKeyword, _) |
|
(&Either::Second(k), _) if k.is_logical() => return Err(()),
|
||||||
(PositionCategory::VerticalLogicalKeyword, _) |
|
(_, &Either::Second(k)) if k.is_logical() => return Err(()),
|
||||||
(_, PositionCategory::HorizontalLogicalKeyword) |
|
|
||||||
(_, PositionCategory::VerticalLogicalKeyword) => return Err(()),
|
// Don't allow two vertical keywords or two horizontal keywords.
|
||||||
|
(&Either::Second(k1), &Either::Second(k2))
|
||||||
|
if (k1.is_horizontal() && k2.is_horizontal()) || (k1.is_vertical() && k2.is_vertical()) =>
|
||||||
|
return Err(()),
|
||||||
|
|
||||||
|
// Also don't allow <length-percentage> values in the wrong position
|
||||||
|
(&Either::First(_), &Either::Second(k)) if k.is_horizontal() => return Err(()),
|
||||||
|
(&Either::Second(k), &Either::First(_)) if k.is_vertical() => return Err(()),
|
||||||
|
|
||||||
// Swap if both are keywords and vertical precedes horizontal.
|
// Swap if both are keywords and vertical precedes horizontal.
|
||||||
(PositionCategory::VerticalKeyword, PositionCategory::HorizontalKeyword) |
|
(&Either::Second(k1), &Either::Second(k2))
|
||||||
(PositionCategory::VerticalKeyword, PositionCategory::OtherKeyword) |
|
if (k1.is_vertical() && k2.is_horizontal()) || (k1.is_vertical() && k2 == Keyword::Center) ||
|
||||||
(PositionCategory::OtherKeyword, PositionCategory::HorizontalKeyword) => {
|
(k1 == Keyword::Center && k2.is_horizontal()) => {
|
||||||
let tmp = first_position;
|
mem::swap(&mut first_position, &mut second_position);
|
||||||
first_position = second_position;
|
|
||||||
second_position = tmp;
|
|
||||||
|
|
||||||
(second_keyword, first_keyword)
|
(second_keyword, first_keyword)
|
||||||
},
|
},
|
||||||
|
|
||||||
// By default, horizontal is first.
|
// By default, horizontal is first.
|
||||||
_ => (first_keyword, second_keyword),
|
_ => (first_keyword, second_keyword),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Unwrap positions from PositionComponent and wrap with Option
|
let (mut h_pos, mut h_key, mut v_pos, mut v_key) = (None, None, None, None);
|
||||||
let (first_position, second_position) = if let Some(PositionComponent::Length(horiz_pos)) = first_position {
|
if let Some(Either::First(l)) = first_position {
|
||||||
if let Some(PositionComponent::Length(vert_pos)) = second_position {
|
h_pos = Some(l);
|
||||||
(Some(horiz_pos), Some(vert_pos))
|
}
|
||||||
} else {
|
|
||||||
(Some(horiz_pos), None)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if let Some(PositionComponent::Length(vert_pos)) = second_position {
|
|
||||||
(None, Some(vert_pos))
|
|
||||||
} else {
|
|
||||||
(None, None)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unwrap keywords from PositionComponent and wrap with Option.
|
if let Some(Either::First(l)) = second_position {
|
||||||
let (horizontal_keyword, vertical_keyword) = if let Some(PositionComponent::Keyword(horiz_key)) =
|
v_pos = Some(l);
|
||||||
horiz_keyword {
|
}
|
||||||
if let Some(PositionComponent::Keyword(vert_key)) = vert_keyword {
|
|
||||||
(Some(horiz_key), Some(vert_key))
|
if let Some(Either::Second(k)) = horiz_keyword {
|
||||||
} else {
|
h_key = Some(k);
|
||||||
(Some(horiz_key), None)
|
}
|
||||||
}
|
|
||||||
} else {
|
if let Some(Either::Second(k)) = vert_keyword {
|
||||||
if let Some(PositionComponent::Keyword(vert_key)) = vert_keyword {
|
v_key = Some(k);
|
||||||
(None, Some(vert_key))
|
}
|
||||||
} else {
|
|
||||||
(None, None)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(Position {
|
Ok(Position {
|
||||||
horizontal: HorizontalPosition {
|
horizontal: GenericHorizontalPosition(PositionValue {
|
||||||
keyword: horizontal_keyword,
|
keyword: h_key,
|
||||||
position: first_position,
|
position: h_pos,
|
||||||
},
|
}),
|
||||||
vertical: VerticalPosition {
|
vertical: GenericVerticalPosition(PositionValue {
|
||||||
keyword: vertical_keyword,
|
keyword: v_key,
|
||||||
position: second_position,
|
position: v_pos,
|
||||||
},
|
}),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a "centered" position, as in "center center".
|
/// Returns a "centered" position, as in "center center".
|
||||||
pub fn center() -> Position {
|
pub fn center() -> Position {
|
||||||
Position {
|
Position {
|
||||||
horizontal: HorizontalPosition {
|
horizontal: GenericHorizontalPosition(PositionValue {
|
||||||
keyword: Some(Keyword::Center),
|
keyword: Some(Keyword::Center),
|
||||||
position: None,
|
position: None,
|
||||||
},
|
}),
|
||||||
vertical: VerticalPosition {
|
vertical: GenericVerticalPosition(PositionValue {
|
||||||
keyword: Some(Keyword::Center),
|
keyword: Some(Keyword::Center),
|
||||||
position: None,
|
position: None,
|
||||||
},
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Position {
|
impl Parse for Position {
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
let first = try!(PositionComponent::parse(context, input));
|
let first = input.try(|i| PositionComponent::parse(context, i))?;
|
||||||
let second = input.try(|i| PositionComponent::parse(context, i))
|
let second = input.try(|i| PositionComponent::parse(context, i))
|
||||||
.unwrap_or(PositionComponent::Keyword(Keyword::Center));
|
.unwrap_or(Either::Second(Keyword::Center));
|
||||||
|
|
||||||
// Try to parse third and fourth values
|
|
||||||
if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) {
|
if let Ok(third) = input.try(|i| PositionComponent::parse(context, i)) {
|
||||||
|
// There's a 3rd value.
|
||||||
if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) {
|
if let Ok(fourth) = input.try(|i| PositionComponent::parse(context, i)) {
|
||||||
// Handle 4 value background position
|
// There's a 4th value.
|
||||||
Position::new(Some(second), Some(fourth), Some(first), Some(third))
|
Position::from_components(Some(second), Some(fourth), Some(first), Some(third))
|
||||||
} else {
|
} else {
|
||||||
// Handle 3 value background position there are several options:
|
// For 3 value background position, there are several options.
|
||||||
if let PositionCategory::LengthOrPercentage = category(&first) {
|
if let Either::First(_) = first {
|
||||||
Err(())
|
return Err(()) // <length-percentage> must be preceded by <keyword>
|
||||||
} else {
|
}
|
||||||
if let PositionCategory::LengthOrPercentage = category(&second) {
|
|
||||||
if let PositionCategory::LengthOrPercentage = category(&third) {
|
// only 3 values.
|
||||||
Err(())
|
match (&second, &third) {
|
||||||
} else {
|
(&Either::First(_), &Either::First(_)) => Err(()),
|
||||||
// "keyword length keyword"
|
// "keyword length keyword"
|
||||||
Position::new(Some(second), None, Some(first), Some(third))
|
(&Either::First(_), _) => Position::from_components(Some(second), None,
|
||||||
}
|
Some(first), Some(third)),
|
||||||
} else {
|
// "keyword keyword length"
|
||||||
// "keyword keyword length"
|
_ => Position::from_components(None, Some(third), Some(first), Some(second)),
|
||||||
Position::new(None, Some(third), Some(first), Some(second))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Handle 2 value background position.
|
// only 2 values.
|
||||||
if let PositionCategory::LengthOrPercentage = category(&first) {
|
match (&first, &second) {
|
||||||
if let PositionCategory::LengthOrPercentage = category(&second) {
|
(&Either::First(_), &Either::First(_)) =>
|
||||||
Position::new(Some(first), Some(second), None, None)
|
Position::from_components(Some(first), Some(second), None, None),
|
||||||
} else {
|
(&Either::First(_), &Either::Second(_)) =>
|
||||||
Position::new(Some(first), None, None, Some(second))
|
Position::from_components(Some(first), None, None, Some(second)),
|
||||||
}
|
(&Either::Second(_), &Either::First(_)) =>
|
||||||
} else {
|
Position::from_components(None, Some(second), Some(first), None),
|
||||||
if let PositionCategory::LengthOrPercentage = category(&second) {
|
(&Either::Second(_), &Either::Second(_)) =>
|
||||||
Position::new(None, Some(second), Some(first), None)
|
Position::from_components(None, None, Some(first), Some(second)),
|
||||||
} else {
|
|
||||||
Position::new(None, None, Some(first), Some(second))
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToComputedValue for Position {
|
impl PositionValue<LengthOrPercentage> {
|
||||||
type ComputedValue = computed_position::Position;
|
/// Generic function for the computed value of a position.
|
||||||
|
fn computed_value(&self, context: &Context) -> ComputedLengthOrPercentage {
|
||||||
|
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),
|
||||||
|
};
|
||||||
|
|
||||||
#[inline]
|
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_position::Position {
|
length: length,
|
||||||
computed_position::Position {
|
percentage: percentage
|
||||||
horizontal: self.horizontal.to_computed_value(context).0,
|
})
|
||||||
vertical: self.vertical.to_computed_value(context).0,
|
},
|
||||||
}
|
None => ComputedLengthOrPercentage::Percentage(1.0),
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &computed_position::Position) -> Position {
|
|
||||||
Position {
|
|
||||||
horizontal: HorizontalPosition {
|
|
||||||
keyword: None,
|
|
||||||
position: Some(ToComputedValue::from_computed_value(&computed.horizontal)),
|
|
||||||
},
|
|
||||||
vertical: VerticalPosition {
|
|
||||||
keyword: None,
|
|
||||||
position: Some(ToComputedValue::from_computed_value(&computed.vertical)),
|
|
||||||
},
|
},
|
||||||
|
_ => self.position.as_ref().map(|l| l.to_computed_value(context))
|
||||||
|
.unwrap_or(ComputedLengthOrPercentage::Percentage(0.0)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
/// The specified value of horizontal `<position>`
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
pub type HorizontalPosition = GenericHorizontalPosition<PositionValue<LengthOrPercentage>>;
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct HorizontalPosition {
|
|
||||||
pub keyword: Option<Keyword>,
|
|
||||||
pub position: Option<LengthOrPercentage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasViewportPercentage for HorizontalPosition {
|
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
|
||||||
self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for HorizontalPosition {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
let mut keyword_present = false;
|
|
||||||
if let Some(keyword) = self.keyword {
|
|
||||||
try!(keyword.to_css(dest));
|
|
||||||
keyword_present = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(ref position) = self.position {
|
|
||||||
if keyword_present {
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
}
|
|
||||||
try!(position.to_css(dest));
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for HorizontalPosition {
|
|
||||||
#[inline]
|
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
|
||||||
let first = try!(PositionComponent::parse(context, input));
|
|
||||||
let second = input.try(|i| PositionComponent::parse(context, i)).ok();
|
|
||||||
|
|
||||||
let (keyword, position) = if let PositionCategory::LengthOrPercentage = category(&first) {
|
|
||||||
// "length keyword?"
|
|
||||||
(second, Some(first))
|
|
||||||
} else {
|
|
||||||
// "keyword length?"
|
|
||||||
(Some(first), second)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unwrapping and checking keyword.
|
|
||||||
let keyword = match keyword {
|
|
||||||
Some(PositionComponent::Keyword(key)) => {
|
|
||||||
match category(keyword.as_ref().unwrap()) {
|
|
||||||
PositionCategory::VerticalKeyword |
|
|
||||||
PositionCategory::VerticalLogicalKeyword => return Err(()),
|
|
||||||
_ => Some(key),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(_) => return Err(()),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unwrapping and checking position.
|
|
||||||
let position = match position {
|
|
||||||
Some(PositionComponent::Length(pos)) => {
|
|
||||||
// "center <length>" is not allowed
|
|
||||||
if let Some(Keyword::Center) = keyword {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
Some(pos)
|
|
||||||
},
|
|
||||||
Some(_) => return Err(()),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(HorizontalPosition {
|
|
||||||
keyword: keyword,
|
|
||||||
position: position,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for HorizontalPosition {
|
impl ToComputedValue for HorizontalPosition {
|
||||||
type ComputedValue = computed_position::HorizontalPosition;
|
type ComputedValue = computed_position::HorizontalPosition;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_position::HorizontalPosition {
|
fn to_computed_value(&self, context: &Context) -> computed_position::HorizontalPosition {
|
||||||
let keyword = self.keyword.unwrap_or(Keyword::Left);
|
GenericHorizontalPosition(self.0.computed_value(context))
|
||||||
|
|
||||||
// Construct horizontal computed LengthOrPercentage
|
|
||||||
let horizontal = match keyword {
|
|
||||||
// FIXME(canaltinova): Support logical keywords.
|
|
||||||
Keyword::Right | Keyword::XEnd => {
|
|
||||||
if let Some(ref x) = self.position {
|
|
||||||
let (length, percentage) = match *x {
|
|
||||||
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
|
||||||
LengthOrPercentage::Length(ref y) => (-y.to_computed_value(context), Some(1.0)),
|
|
||||||
_ => (Au(0), None),
|
|
||||||
};
|
|
||||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
|
||||||
length: length,
|
|
||||||
percentage: percentage
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ComputedLengthOrPercentage::Percentage(1.0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Keyword::Center => {
|
|
||||||
keyword.to_length_or_percentage().to_computed_value(context)
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let zero = LengthOrPercentage::Percentage(Percentage(0.0));
|
|
||||||
let horiz = self.position.as_ref().unwrap_or(&zero);
|
|
||||||
horiz.to_computed_value(context)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
computed_position::HorizontalPosition(horizontal)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &computed_position::HorizontalPosition) -> HorizontalPosition {
|
fn from_computed_value(computed: &computed_position::HorizontalPosition) -> HorizontalPosition {
|
||||||
HorizontalPosition {
|
GenericHorizontalPosition(PositionValue {
|
||||||
keyword: None,
|
keyword: None,
|
||||||
position: Some(ToComputedValue::from_computed_value(&computed.0)),
|
position: Some(ToComputedValue::from_computed_value(&computed.0)),
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct VerticalPosition {
|
|
||||||
pub keyword: Option<Keyword>,
|
|
||||||
pub position: Option<LengthOrPercentage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasViewportPercentage for VerticalPosition {
|
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
|
||||||
self.position.as_ref().map_or(false, |pos| pos.has_viewport_percentage())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for VerticalPosition {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
let mut keyword_present = false;
|
|
||||||
if let Some(keyword) = self.keyword {
|
|
||||||
try!(keyword.to_css(dest));
|
|
||||||
keyword_present = true;
|
|
||||||
};
|
|
||||||
|
|
||||||
if let Some(ref position) = self.position {
|
|
||||||
if keyword_present {
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
}
|
|
||||||
try!(position.to_css(dest));
|
|
||||||
};
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for VerticalPosition {
|
|
||||||
#[inline]
|
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
|
||||||
let first = try!(PositionComponent::parse(context, input));
|
|
||||||
let second = input.try(|i| PositionComponent::parse(context, i)).ok();
|
|
||||||
|
|
||||||
let (keyword, position) = if let PositionCategory::LengthOrPercentage = category(&first) {
|
|
||||||
// "length keyword?"
|
|
||||||
(second, Some(first))
|
|
||||||
} else {
|
|
||||||
// "keyword length?"
|
|
||||||
(Some(first), second)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unwrapping and checking keyword.
|
|
||||||
let keyword = match keyword {
|
|
||||||
Some(PositionComponent::Keyword(key)) => {
|
|
||||||
match category(keyword.as_ref().unwrap()) {
|
|
||||||
PositionCategory::HorizontalKeyword |
|
|
||||||
PositionCategory::HorizontalLogicalKeyword => return Err(()),
|
|
||||||
_ => Some(key),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Some(_) => return Err(()),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Unwrapping and checking position.
|
|
||||||
let position = match position {
|
|
||||||
Some(PositionComponent::Length(pos)) => {
|
|
||||||
// "center <length>" is not allowed
|
|
||||||
if let Some(Keyword::Center) = keyword {
|
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
Some(pos)
|
|
||||||
},
|
|
||||||
Some(_) => return Err(()),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
Ok(VerticalPosition {
|
|
||||||
keyword: keyword,
|
|
||||||
position: position,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl HorizontalPosition {
|
||||||
|
#[inline]
|
||||||
|
/// Initial specified value for vertical position (`top` keyword).
|
||||||
|
pub fn left() -> HorizontalPosition {
|
||||||
|
GenericHorizontalPosition(PositionValue {
|
||||||
|
keyword: Some(Keyword::Left),
|
||||||
|
position: None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// The specified value of vertical `<position>`
|
||||||
|
pub type VerticalPosition = GenericVerticalPosition<PositionValue<LengthOrPercentage>>;
|
||||||
|
|
||||||
impl ToComputedValue for VerticalPosition {
|
impl ToComputedValue for VerticalPosition {
|
||||||
type ComputedValue = computed_position::VerticalPosition;
|
type ComputedValue = computed_position::VerticalPosition;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn to_computed_value(&self, context: &Context) -> computed_position::VerticalPosition {
|
fn to_computed_value(&self, context: &Context) -> computed_position::VerticalPosition {
|
||||||
let keyword = self.keyword.unwrap_or(Keyword::Left);
|
GenericVerticalPosition(self.0.computed_value(context))
|
||||||
|
|
||||||
// Construct vertical computed LengthOrPercentage
|
|
||||||
let vertical = match keyword {
|
|
||||||
// FIXME(canaltinova): Support logical keywords.
|
|
||||||
Keyword::Bottom | Keyword::YEnd => {
|
|
||||||
if let Some(ref x) = self.position {
|
|
||||||
let (length, percentage) = match *x {
|
|
||||||
LengthOrPercentage::Percentage(Percentage(y)) => (Au(0), Some(1.0 - y)),
|
|
||||||
LengthOrPercentage::Length(ref y) => (-y.to_computed_value(context), Some(1.0)),
|
|
||||||
_ => (Au(0), None),
|
|
||||||
};
|
|
||||||
ComputedLengthOrPercentage::Calc(CalcLengthOrPercentage {
|
|
||||||
length: length,
|
|
||||||
percentage: percentage
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
ComputedLengthOrPercentage::Percentage(1.0)
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Keyword::Center => {
|
|
||||||
keyword.to_length_or_percentage().to_computed_value(context)
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let zero = LengthOrPercentage::Percentage(Percentage(0.0));
|
|
||||||
let vert = self.position.as_ref().unwrap_or(&zero);
|
|
||||||
vert.to_computed_value(context)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
computed_position::VerticalPosition(vertical)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn from_computed_value(computed: &computed_position::VerticalPosition) -> VerticalPosition {
|
fn from_computed_value(computed: &computed_position::VerticalPosition) -> VerticalPosition {
|
||||||
VerticalPosition {
|
GenericVerticalPosition(PositionValue {
|
||||||
keyword: None,
|
keyword: None,
|
||||||
position: Some(ToComputedValue::from_computed_value(&computed.0)),
|
position: Some(ToComputedValue::from_computed_value(&computed.0)),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
define_css_keyword_enum!(Keyword:
|
impl VerticalPosition {
|
||||||
"center" => Center,
|
|
||||||
"left" => Left,
|
|
||||||
"right" => Right,
|
|
||||||
"top" => Top,
|
|
||||||
"bottom" => Bottom,
|
|
||||||
"x-start" => XStart,
|
|
||||||
"x-end" => XEnd,
|
|
||||||
"y-start" => YStart,
|
|
||||||
"y-end" => YEnd);
|
|
||||||
|
|
||||||
impl Keyword {
|
|
||||||
/// Convert the given keyword to a length or a percentage.
|
|
||||||
pub fn to_length_or_percentage(self) -> LengthOrPercentage {
|
|
||||||
match self {
|
|
||||||
Keyword::Center => LengthOrPercentage::Percentage(Percentage(0.5)),
|
|
||||||
Keyword::Left | Keyword::Top => LengthOrPercentage::Percentage(Percentage(0.0)),
|
|
||||||
Keyword::Right | Keyword::Bottom => LengthOrPercentage::Percentage(Percentage(1.0)),
|
|
||||||
// FIXME(canaltinova): Support logical keywords
|
|
||||||
Keyword::XStart | Keyword::YStart => LengthOrPercentage::Percentage(Percentage(0.0)),
|
|
||||||
Keyword::XEnd | Keyword::YEnd => LengthOrPercentage::Percentage(Percentage(1.0)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Collapse `Position` into a few categories to simplify the above `match` expression.
|
|
||||||
enum PositionCategory {
|
|
||||||
HorizontalKeyword,
|
|
||||||
VerticalKeyword,
|
|
||||||
HorizontalLogicalKeyword,
|
|
||||||
VerticalLogicalKeyword,
|
|
||||||
OtherKeyword,
|
|
||||||
LengthOrPercentage,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A position component.
|
|
||||||
///
|
|
||||||
/// http://dev.w3.org/csswg/css2/colors.html#propdef-background-position
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
pub enum PositionComponent {
|
|
||||||
/// A `<length>`
|
|
||||||
Length(LengthOrPercentage),
|
|
||||||
/// A position keyword.
|
|
||||||
Keyword(Keyword),
|
|
||||||
}
|
|
||||||
|
|
||||||
fn category(p: &PositionComponent) -> PositionCategory {
|
|
||||||
if let PositionComponent::Keyword(keyword) = *p {
|
|
||||||
match keyword {
|
|
||||||
Keyword::Left | Keyword::Right =>
|
|
||||||
PositionCategory::HorizontalKeyword,
|
|
||||||
Keyword::Top | Keyword::Bottom =>
|
|
||||||
PositionCategory::VerticalKeyword,
|
|
||||||
Keyword::XStart | Keyword::XEnd =>
|
|
||||||
PositionCategory::HorizontalLogicalKeyword,
|
|
||||||
Keyword::YStart | Keyword::YEnd =>
|
|
||||||
PositionCategory::VerticalLogicalKeyword,
|
|
||||||
Keyword::Center =>
|
|
||||||
PositionCategory::OtherKeyword,
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
PositionCategory::LengthOrPercentage
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl HasViewportPercentage for PositionComponent {
|
|
||||||
fn has_viewport_percentage(&self) -> bool {
|
|
||||||
match *self {
|
|
||||||
PositionComponent::Length(ref length) => length.has_viewport_percentage(),
|
|
||||||
_ => false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PositionComponent {
|
|
||||||
/// Convert the given position component to a length or a percentage.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn to_length_or_percentage_computed(&self, cx: &Context) -> computed::LengthOrPercentage {
|
/// Initial specified value for vertical position (`top` keyword).
|
||||||
match *self {
|
pub fn top() -> VerticalPosition {
|
||||||
PositionComponent::Length(ref value) => value.to_computed_value(cx),
|
GenericVerticalPosition(PositionValue {
|
||||||
PositionComponent::Keyword(keyword) => {
|
keyword: Some(Keyword::Top),
|
||||||
keyword.to_length_or_percentage().to_computed_value(cx)
|
position: None,
|
||||||
}
|
})
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Parse for PositionComponent {
|
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
|
||||||
input.try(|i| LengthOrPercentage::parse(context, i))
|
|
||||||
.map(PositionComponent::Length)
|
|
||||||
.or_else(|()| {
|
|
||||||
match try!(input.next()) {
|
|
||||||
Token::Ident(value) => {
|
|
||||||
match_ignore_ascii_case! { &value,
|
|
||||||
"center" => Ok(PositionComponent::Keyword(Keyword::Center)),
|
|
||||||
"left" => Ok(PositionComponent::Keyword(Keyword::Left)),
|
|
||||||
"right" => Ok(PositionComponent::Keyword(Keyword::Right)),
|
|
||||||
"top" => Ok(PositionComponent::Keyword(Keyword::Top)),
|
|
||||||
"bottom" => Ok(PositionComponent::Keyword(Keyword::Bottom)),
|
|
||||||
"x-start" => Ok(PositionComponent::Keyword(Keyword::XStart)),
|
|
||||||
"x-end" => Ok(PositionComponent::Keyword(Keyword::XEnd)),
|
|
||||||
"y-start" => Ok(PositionComponent::Keyword(Keyword::YStart)),
|
|
||||||
"y-end" => Ok(PositionComponent::Keyword(Keyword::YEnd)),
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => Err(())
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -799,8 +799,8 @@ mod shorthand_serialization {
|
||||||
use style::properties::longhands::mask_position_y as position_y;
|
use style::properties::longhands::mask_position_y as position_y;
|
||||||
use style::properties::longhands::mask_repeat as repeat;
|
use style::properties::longhands::mask_repeat as repeat;
|
||||||
use style::properties::longhands::mask_size as size;
|
use style::properties::longhands::mask_size as size;
|
||||||
|
use style::values::generics::position::{HorizontalPosition, Keyword, PositionValue, VerticalPosition};
|
||||||
use style::values::specified::Image;
|
use style::values::specified::Image;
|
||||||
use style::values::specified::position::{HorizontalPosition, VerticalPosition, Keyword};
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
macro_rules! single_vec_value_typedef {
|
macro_rules! single_vec_value_typedef {
|
||||||
|
@ -836,16 +836,16 @@ mod shorthand_serialization {
|
||||||
let mode = single_vec_keyword_value!(mode, luminance);
|
let mode = single_vec_keyword_value!(mode, luminance);
|
||||||
|
|
||||||
let position_x = single_vec_value_typedef!(position_x,
|
let position_x = single_vec_value_typedef!(position_x,
|
||||||
HorizontalPosition {
|
HorizontalPosition(PositionValue {
|
||||||
keyword: None,
|
keyword: None,
|
||||||
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))),
|
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))),
|
||||||
}
|
})
|
||||||
);
|
);
|
||||||
let position_y = single_vec_value_typedef!(position_y,
|
let position_y = single_vec_value_typedef!(position_y,
|
||||||
VerticalPosition {
|
VerticalPosition(PositionValue {
|
||||||
keyword: Some(Keyword::Bottom),
|
keyword: Some(Keyword::Bottom),
|
||||||
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))),
|
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))),
|
||||||
}
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let size = single_vec_variant_value!(size,
|
let size = single_vec_variant_value!(size,
|
||||||
|
@ -891,17 +891,17 @@ mod shorthand_serialization {
|
||||||
let mode = single_vec_keyword_value!(mode, luminance);
|
let mode = single_vec_keyword_value!(mode, luminance);
|
||||||
|
|
||||||
let position_x = single_vec_value_typedef!(position_x,
|
let position_x = single_vec_value_typedef!(position_x,
|
||||||
HorizontalPosition {
|
HorizontalPosition(PositionValue {
|
||||||
keyword: None,
|
keyword: None,
|
||||||
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))),
|
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(7f32))),
|
||||||
}
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let position_y = single_vec_value_typedef!(position_y,
|
let position_y = single_vec_value_typedef!(position_y,
|
||||||
VerticalPosition {
|
VerticalPosition(PositionValue {
|
||||||
keyword: None,
|
keyword: None,
|
||||||
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))),
|
position: Some(LengthOrPercentage::Length(NoCalcLength::from_px(4f32))),
|
||||||
}
|
})
|
||||||
);
|
);
|
||||||
|
|
||||||
let size = single_vec_variant_value!(size,
|
let size = single_vec_variant_value!(size,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue