mirror of
https://github.com/servo/servo.git
synced 2025-08-04 05:00:08 +01:00
style: Use cbindgen for gradients.
Differential Revision: https://phabricator.services.mozilla.com/D33901
This commit is contained in:
parent
ad142f8f2f
commit
a4690ce158
10 changed files with 190 additions and 474 deletions
|
@ -16,18 +16,16 @@ use crate::gecko_bindings::structs::{self, nsStyleCoord_CalcValue, Matrix4x4Comp
|
||||||
use crate::gecko_bindings::structs::{nsStyleImage, nsresult};
|
use crate::gecko_bindings::structs::{nsStyleImage, nsresult};
|
||||||
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
use crate::gecko_bindings::sugar::ns_style_coord::{CoordData, CoordDataMut, CoordDataValue};
|
||||||
use crate::stylesheets::RulesMutateError;
|
use crate::stylesheets::RulesMutateError;
|
||||||
use crate::values::computed::image::LineDirection;
|
|
||||||
use crate::values::computed::transform::Matrix3D;
|
use crate::values::computed::transform::Matrix3D;
|
||||||
use crate::values::computed::url::ComputedImageUrl;
|
use crate::values::computed::url::ComputedImageUrl;
|
||||||
use crate::values::computed::{Angle, Gradient, Image};
|
use crate::values::computed::{Angle, Gradient, Image};
|
||||||
use crate::values::computed::{Integer, LengthPercentage};
|
use crate::values::computed::{Integer, LengthPercentage};
|
||||||
use crate::values::computed::{Length, Percentage, TextAlign};
|
use crate::values::computed::{Length, Percentage, TextAlign};
|
||||||
use crate::values::generics::grid::{TrackListValue, TrackSize};
|
use crate::values::generics::grid::{TrackListValue, TrackSize};
|
||||||
use crate::values::generics::image::{CompatMode, Image as GenericImage};
|
use crate::values::generics::image::GenericImage;
|
||||||
use crate::values::generics::rect::Rect;
|
use crate::values::generics::rect::Rect;
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
use app_units::Au;
|
use app_units::Au;
|
||||||
use std::f32::consts::PI;
|
|
||||||
use style_traits::values::specified::AllowedNumericType;
|
use style_traits::values::specified::AllowedNumericType;
|
||||||
|
|
||||||
impl From<LengthPercentage> for nsStyleCoord_CalcValue {
|
impl From<LengthPercentage> for nsStyleCoord_CalcValue {
|
||||||
|
@ -64,56 +62,11 @@ impl From<Angle> for CoordDataValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn line_direction(horizontal: LengthPercentage, vertical: LengthPercentage) -> LineDirection {
|
|
||||||
use crate::values::specified::position::{X, Y};
|
|
||||||
|
|
||||||
let horizontal_percentage = horizontal.as_percentage();
|
|
||||||
let vertical_percentage = vertical.as_percentage();
|
|
||||||
|
|
||||||
let horizontal_as_corner = horizontal_percentage.and_then(|percentage| {
|
|
||||||
if percentage.0 == 0.0 {
|
|
||||||
Some(X::Left)
|
|
||||||
} else if percentage.0 == 1.0 {
|
|
||||||
Some(X::Right)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let vertical_as_corner = vertical_percentage.and_then(|percentage| {
|
|
||||||
if percentage.0 == 0.0 {
|
|
||||||
Some(Y::Top)
|
|
||||||
} else if percentage.0 == 1.0 {
|
|
||||||
Some(Y::Bottom)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
if let (Some(hc), Some(vc)) = (horizontal_as_corner, vertical_as_corner) {
|
|
||||||
return LineDirection::Corner(hc, vc);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(hc) = horizontal_as_corner {
|
|
||||||
if vertical_percentage == Some(Percentage(0.5)) {
|
|
||||||
return LineDirection::Horizontal(hc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Some(vc) = vertical_as_corner {
|
|
||||||
if horizontal_percentage == Some(Percentage(0.5)) {
|
|
||||||
return LineDirection::Vertical(vc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
unreachable!("Unexpected line direction");
|
|
||||||
}
|
|
||||||
|
|
||||||
impl nsStyleImage {
|
impl nsStyleImage {
|
||||||
/// Set a given Servo `Image` value into this `nsStyleImage`.
|
/// Set a given Servo `Image` value into this `nsStyleImage`.
|
||||||
pub fn set(&mut self, image: Image) {
|
pub fn set(&mut self, image: Image) {
|
||||||
match image {
|
match image {
|
||||||
GenericImage::Gradient(boxed_gradient) => self.set_gradient(*boxed_gradient),
|
GenericImage::Gradient(boxed_gradient) => self.set_gradient(boxed_gradient),
|
||||||
GenericImage::Url(ref url) => unsafe {
|
GenericImage::Url(ref url) => unsafe {
|
||||||
bindings::Gecko_SetLayerImageImageValue(self, url);
|
bindings::Gecko_SetLayerImageImageValue(self, url);
|
||||||
},
|
},
|
||||||
|
@ -144,172 +97,9 @@ impl nsStyleImage {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME(emilio): This is really complex, we should use cbindgen for this.
|
fn set_gradient(&mut self, gradient: Box<Gradient>) {
|
||||||
fn set_gradient(&mut self, gradient: Gradient) {
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER;
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE;
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER;
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE;
|
|
||||||
use crate::values::generics::image::{
|
|
||||||
Circle, Ellipse, EndingShape, GradientKind, ShapeExtent,
|
|
||||||
};
|
|
||||||
use crate::values::specified::position::{X, Y};
|
|
||||||
|
|
||||||
let stop_count = gradient.items.len();
|
|
||||||
if stop_count >= ::std::u32::MAX as usize {
|
|
||||||
warn!("stylo: Prevented overflow due to too many gradient stops");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let gecko_gradient = match gradient.kind {
|
|
||||||
GradientKind::Linear(direction) => {
|
|
||||||
let gecko_gradient = unsafe {
|
|
||||||
bindings::Gecko_CreateGradient(
|
|
||||||
structs::NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
|
|
||||||
structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
|
|
||||||
gradient.repeating,
|
|
||||||
gradient.compat_mode != CompatMode::Modern,
|
|
||||||
gradient.compat_mode == CompatMode::Moz,
|
|
||||||
stop_count as u32,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
match direction {
|
|
||||||
LineDirection::Angle(angle) => {
|
|
||||||
// PI radians (180deg) is ignored because it is the default value.
|
|
||||||
if angle.radians() != PI {
|
|
||||||
unsafe {
|
unsafe {
|
||||||
(*gecko_gradient).mAngle.set(angle);
|
bindings::Gecko_SetGradientImageValue(self, Box::into_raw(gradient));
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
LineDirection::Horizontal(x) => {
|
|
||||||
let x = match x {
|
|
||||||
X::Left => 0.0,
|
|
||||||
X::Right => 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mBgPosX
|
|
||||||
.set_value(CoordDataValue::Percent(x));
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mBgPosY
|
|
||||||
.set_value(CoordDataValue::Percent(0.5));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
LineDirection::Vertical(y) => {
|
|
||||||
// Although bottom is the default value, we can not ignore
|
|
||||||
// it here, because the rendering code of Gecko relies on
|
|
||||||
// this to behave correctly for legacy mode.
|
|
||||||
let y = match y {
|
|
||||||
Y::Top => 0.0,
|
|
||||||
Y::Bottom => 1.0,
|
|
||||||
};
|
|
||||||
unsafe {
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mBgPosX
|
|
||||||
.set_value(CoordDataValue::Percent(0.5));
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mBgPosY
|
|
||||||
.set_value(CoordDataValue::Percent(y));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
LineDirection::Corner(horiz, vert) => {
|
|
||||||
let percent_x = match horiz {
|
|
||||||
X::Left => 0.0,
|
|
||||||
X::Right => 1.0,
|
|
||||||
};
|
|
||||||
let percent_y = match vert {
|
|
||||||
Y::Top => 0.0,
|
|
||||||
Y::Bottom => 1.0,
|
|
||||||
};
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mBgPosX
|
|
||||||
.set_value(CoordDataValue::Percent(percent_x));
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mBgPosY
|
|
||||||
.set_value(CoordDataValue::Percent(percent_y));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
gecko_gradient
|
|
||||||
},
|
|
||||||
GradientKind::Radial(shape, position) => {
|
|
||||||
let keyword_to_gecko_size = |keyword| match keyword {
|
|
||||||
ShapeExtent::ClosestSide => CLOSEST_SIDE,
|
|
||||||
ShapeExtent::FarthestSide => FARTHEST_SIDE,
|
|
||||||
ShapeExtent::ClosestCorner => CLOSEST_CORNER,
|
|
||||||
ShapeExtent::FarthestCorner => FARTHEST_CORNER,
|
|
||||||
ShapeExtent::Contain => CLOSEST_SIDE,
|
|
||||||
ShapeExtent::Cover => FARTHEST_CORNER,
|
|
||||||
};
|
|
||||||
let (gecko_shape, gecko_size) = match shape {
|
|
||||||
EndingShape::Circle(ref circle) => {
|
|
||||||
let size = match *circle {
|
|
||||||
Circle::Extent(extent) => keyword_to_gecko_size(extent),
|
|
||||||
_ => structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
|
|
||||||
};
|
|
||||||
(structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8)
|
|
||||||
},
|
|
||||||
EndingShape::Ellipse(ref ellipse) => {
|
|
||||||
let size = match *ellipse {
|
|
||||||
Ellipse::Extent(extent) => keyword_to_gecko_size(extent),
|
|
||||||
_ => structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
|
|
||||||
};
|
|
||||||
(
|
|
||||||
structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL as u8,
|
|
||||||
size as u8,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let gecko_gradient = unsafe {
|
|
||||||
bindings::Gecko_CreateGradient(
|
|
||||||
gecko_shape,
|
|
||||||
gecko_size,
|
|
||||||
gradient.repeating,
|
|
||||||
gradient.compat_mode == CompatMode::Moz,
|
|
||||||
gradient.compat_mode == CompatMode::Moz,
|
|
||||||
stop_count as u32,
|
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// Setting radius values depending shape
|
|
||||||
match shape {
|
|
||||||
EndingShape::Circle(Circle::Radius(length)) => unsafe {
|
|
||||||
let au = length.to_i32_au();
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mRadiusX
|
|
||||||
.set_value(CoordDataValue::Coord(au));
|
|
||||||
(*gecko_gradient)
|
|
||||||
.mRadiusY
|
|
||||||
.set_value(CoordDataValue::Coord(au));
|
|
||||||
},
|
|
||||||
EndingShape::Ellipse(Ellipse::Radii(x, y)) => unsafe {
|
|
||||||
(*gecko_gradient).mRadiusX.set(x);
|
|
||||||
(*gecko_gradient).mRadiusY.set(y);
|
|
||||||
},
|
|
||||||
_ => {},
|
|
||||||
}
|
|
||||||
unsafe {
|
|
||||||
(*gecko_gradient).mBgPosX.set(position.horizontal);
|
|
||||||
(*gecko_gradient).mBgPosY.set(position.vertical);
|
|
||||||
}
|
|
||||||
|
|
||||||
gecko_gradient
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
for (index, item) in gradient.items.into_iter().enumerate() {
|
|
||||||
let gecko_stop = unsafe { &mut (*gecko_gradient).mStops[index] };
|
|
||||||
*gecko_stop = item;
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
bindings::Gecko_SetGradientImageValue(self, gecko_gradient);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -352,7 +142,9 @@ impl nsStyleImage {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
nsStyleImageType::eStyleImageType_Gradient => {
|
nsStyleImageType::eStyleImageType_Gradient => {
|
||||||
Some(GenericImage::Gradient(self.get_gradient()))
|
let gradient: &Gradient =
|
||||||
|
&**self.__bindgen_anon_1.mGradient.as_ref();
|
||||||
|
Some(GenericImage::Gradient(Box::new(gradient.clone())))
|
||||||
},
|
},
|
||||||
nsStyleImageType::eStyleImageType_Element => {
|
nsStyleImageType::eStyleImageType_Element => {
|
||||||
use crate::gecko_string_cache::Atom;
|
use crate::gecko_string_cache::Atom;
|
||||||
|
@ -368,131 +160,6 @@ impl nsStyleImage {
|
||||||
.expect("Null image request?");
|
.expect("Null image request?");
|
||||||
ComputedImageUrl::from_image_request(image_request)
|
ComputedImageUrl::from_image_request(image_request)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn get_gradient(self: &nsStyleImage) -> Box<Gradient> {
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER as CLOSEST_CORNER;
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE as CLOSEST_SIDE;
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as FARTHEST_CORNER;
|
|
||||||
use self::structs::NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE as FARTHEST_SIDE;
|
|
||||||
use crate::values::computed::position::Position;
|
|
||||||
use crate::values::generics::image::{Circle, Ellipse};
|
|
||||||
use crate::values::generics::image::{EndingShape, GradientKind, ShapeExtent};
|
|
||||||
|
|
||||||
let gecko_gradient = bindings::Gecko_GetGradientImageValue(self)
|
|
||||||
.as_ref()
|
|
||||||
.unwrap();
|
|
||||||
let horizontal_style = LengthPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosX);
|
|
||||||
let vertical_style = LengthPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosY);
|
|
||||||
|
|
||||||
let kind = match gecko_gradient.mShape as u32 {
|
|
||||||
structs::NS_STYLE_GRADIENT_SHAPE_LINEAR => {
|
|
||||||
let angle = Angle::from_gecko_style_coord(&gecko_gradient.mAngle);
|
|
||||||
let line_direction = match (angle, horizontal_style, vertical_style) {
|
|
||||||
(Some(a), None, None) => LineDirection::Angle(a),
|
|
||||||
(None, None, None) => LineDirection::Angle(Angle::from_radians(PI)),
|
|
||||||
(None, Some(horizontal), Some(vertical)) => {
|
|
||||||
line_direction(horizontal, vertical)
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
unreachable!("unexpected line direction for linear gradient direction");
|
|
||||||
},
|
|
||||||
};
|
|
||||||
GradientKind::Linear(line_direction)
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
let gecko_size_to_keyword = |gecko_size| {
|
|
||||||
match gecko_size {
|
|
||||||
CLOSEST_SIDE => ShapeExtent::ClosestSide,
|
|
||||||
FARTHEST_SIDE => ShapeExtent::FarthestSide,
|
|
||||||
CLOSEST_CORNER => ShapeExtent::ClosestCorner,
|
|
||||||
FARTHEST_CORNER => ShapeExtent::FarthestCorner,
|
|
||||||
// FIXME: We should support ShapeExtent::Contain and ShapeExtent::Cover.
|
|
||||||
// But we can't choose those yet since Gecko does not support both values.
|
|
||||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1217664
|
|
||||||
_ => panic!("Found unexpected gecko_size"),
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let shape = match gecko_gradient.mShape as u32 {
|
|
||||||
structs::NS_STYLE_GRADIENT_SHAPE_CIRCULAR => {
|
|
||||||
let circle = match gecko_gradient.mSize as u32 {
|
|
||||||
structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => {
|
|
||||||
let radius =
|
|
||||||
Length::from_gecko_style_coord(&gecko_gradient.mRadiusX)
|
|
||||||
.expect("mRadiusX could not convert to Length");
|
|
||||||
debug_assert_eq!(
|
|
||||||
radius,
|
|
||||||
Length::from_gecko_style_coord(&gecko_gradient.mRadiusY)
|
|
||||||
.unwrap()
|
|
||||||
);
|
|
||||||
Circle::Radius(radius)
|
|
||||||
},
|
|
||||||
size => Circle::Extent(gecko_size_to_keyword(size)),
|
|
||||||
};
|
|
||||||
EndingShape::Circle(circle)
|
|
||||||
},
|
|
||||||
structs::NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL => {
|
|
||||||
let length_percentage_keyword = match gecko_gradient.mSize as u32 {
|
|
||||||
structs::NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => match (
|
|
||||||
LengthPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusX),
|
|
||||||
LengthPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusY),
|
|
||||||
) {
|
|
||||||
(Some(x), Some(y)) => Ellipse::Radii(x, y),
|
|
||||||
_ => {
|
|
||||||
debug_assert!(
|
|
||||||
false,
|
|
||||||
"mRadiusX, mRadiusY could not convert to LengthPercentage"
|
|
||||||
);
|
|
||||||
Ellipse::Radii(
|
|
||||||
LengthPercentage::zero(),
|
|
||||||
LengthPercentage::zero(),
|
|
||||||
)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
size => Ellipse::Extent(gecko_size_to_keyword(size)),
|
|
||||||
};
|
|
||||||
EndingShape::Ellipse(length_percentage_keyword)
|
|
||||||
},
|
|
||||||
_ => panic!("Found unexpected mShape"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let position = match (horizontal_style, vertical_style) {
|
|
||||||
(Some(horizontal), Some(vertical)) => Position {
|
|
||||||
horizontal,
|
|
||||||
vertical,
|
|
||||||
},
|
|
||||||
_ => {
|
|
||||||
debug_assert!(
|
|
||||||
false,
|
|
||||||
"mRadiusX, mRadiusY could not convert to LengthPercentage"
|
|
||||||
);
|
|
||||||
Position {
|
|
||||||
horizontal: LengthPercentage::zero(),
|
|
||||||
vertical: LengthPercentage::zero(),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
GradientKind::Radial(shape, position)
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
let items = gecko_gradient.mStops.iter().cloned().collect();
|
|
||||||
let compat_mode = if gecko_gradient.mMozLegacySyntax {
|
|
||||||
CompatMode::Moz
|
|
||||||
} else if gecko_gradient.mLegacySyntax {
|
|
||||||
CompatMode::WebKit
|
|
||||||
} else {
|
|
||||||
CompatMode::Modern
|
|
||||||
};
|
|
||||||
|
|
||||||
Box::new(Gradient {
|
|
||||||
items,
|
|
||||||
repeating: gecko_gradient.mRepeating,
|
|
||||||
kind,
|
|
||||||
compat_mode,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod basic_shape {
|
pub mod basic_shape {
|
||||||
|
|
|
@ -55,6 +55,7 @@ use crate::values::computed::url::ComputedImageUrl;
|
||||||
use crate::values::computed::BorderStyle;
|
use crate::values::computed::BorderStyle;
|
||||||
use crate::values::computed::font::FontSize;
|
use crate::values::computed::font::FontSize;
|
||||||
use crate::values::generics::column::ColumnCount;
|
use crate::values::generics::column::ColumnCount;
|
||||||
|
use crate::values::generics::image::ImageLayer;
|
||||||
use crate::values::generics::transform::TransformStyle;
|
use crate::values::generics::transform::TransformStyle;
|
||||||
use crate::values::generics::url::UrlOrNone;
|
use crate::values::generics::url::UrlOrNone;
|
||||||
|
|
||||||
|
@ -982,7 +983,7 @@ fn static_assert() {
|
||||||
Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
|
Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Either::Second(image) = image {
|
if let ImageLayer::Image(image) = image {
|
||||||
self.gecko.mBorderImageSource.set(image);
|
self.gecko.mBorderImageSource.set(image);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -999,11 +1000,9 @@ fn static_assert() {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T {
|
pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T {
|
||||||
use crate::values::None_;
|
|
||||||
|
|
||||||
match unsafe { self.gecko.mBorderImageSource.into_image() } {
|
match unsafe { self.gecko.mBorderImageSource.into_image() } {
|
||||||
Some(image) => Either::Second(image),
|
Some(image) => ImageLayer::Image(image),
|
||||||
None => Either::First(None_),
|
None => ImageLayer::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2714,22 +2713,20 @@ fn static_assert() {
|
||||||
|
|
||||||
for (image, geckoimage) in images.zip(self.gecko.${image_layers_field}
|
for (image, geckoimage) in images.zip(self.gecko.${image_layers_field}
|
||||||
.mLayers.iter_mut()) {
|
.mLayers.iter_mut()) {
|
||||||
if let Either::Second(image) = image {
|
if let ImageLayer::Image(image) = image {
|
||||||
geckoimage.mImage.set(image)
|
geckoimage.mImage.set(image)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T {
|
pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T {
|
||||||
use crate::values::None_;
|
|
||||||
|
|
||||||
longhands::${shorthand}_image::computed_value::List(
|
longhands::${shorthand}_image::computed_value::List(
|
||||||
self.gecko.${image_layers_field}.mLayers.iter()
|
self.gecko.${image_layers_field}.mLayers.iter()
|
||||||
.take(self.gecko.${image_layers_field}.mImageCount as usize)
|
.take(self.gecko.${image_layers_field}.mImageCount as usize)
|
||||||
.map(|ref layer| {
|
.map(|ref layer| {
|
||||||
match unsafe { layer.mImage.into_image() } {
|
match unsafe { layer.mImage.into_image() } {
|
||||||
Some(image) => Either::Second(image),
|
Some(image) => ImageLayer::Image(image),
|
||||||
None => Either::First(None_),
|
None => ImageLayer::None,
|
||||||
}
|
}
|
||||||
}).collect()
|
}).collect()
|
||||||
)
|
)
|
||||||
|
|
|
@ -22,8 +22,8 @@ ${helpers.predefined_type(
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"background-image",
|
"background-image",
|
||||||
"ImageLayer",
|
"ImageLayer",
|
||||||
initial_value="Either::First(None_)",
|
initial_value="computed::ImageLayer::none()",
|
||||||
initial_specified_value="Either::First(None_)",
|
initial_specified_value="specified::ImageLayer::none()",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
|
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
|
||||||
vector="True",
|
vector="True",
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
|
|
|
@ -107,8 +107,8 @@ ${helpers.single_keyword(
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"border-image-source",
|
"border-image-source",
|
||||||
"ImageLayer",
|
"ImageLayer",
|
||||||
initial_value="Either::First(None_)",
|
initial_value="computed::ImageLayer::none()",
|
||||||
initial_specified_value="Either::First(None_)",
|
initial_specified_value="specified::ImageLayer::none()",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
|
spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
|
||||||
vector=False,
|
vector=False,
|
||||||
animation_value_type="discrete",
|
animation_value_type="discrete",
|
||||||
|
|
|
@ -181,8 +181,8 @@ ${helpers.single_keyword(
|
||||||
${helpers.predefined_type(
|
${helpers.predefined_type(
|
||||||
"mask-image",
|
"mask-image",
|
||||||
"ImageLayer",
|
"ImageLayer",
|
||||||
"Either::First(None_)",
|
initial_value="computed::ImageLayer::none()",
|
||||||
initial_specified_value="Either::First(None_)",
|
initial_specified_value="specified::ImageLayer::none()",
|
||||||
parse_method="parse_with_cors_anonymous",
|
parse_method="parse_with_cors_anonymous",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
|
||||||
vector=True,
|
vector=True,
|
||||||
|
|
|
@ -11,41 +11,41 @@ use crate::values::computed::position::Position;
|
||||||
use crate::values::computed::url::ComputedImageUrl;
|
use crate::values::computed::url::ComputedImageUrl;
|
||||||
use crate::values::computed::{Angle, Color, Context};
|
use crate::values::computed::{Angle, Color, Context};
|
||||||
use crate::values::computed::{Length, LengthPercentage, NumberOrPercentage, ToComputedValue};
|
use crate::values::computed::{Length, LengthPercentage, NumberOrPercentage, ToComputedValue};
|
||||||
use crate::values::generics::image::{self as generic, CompatMode};
|
use crate::values::generics::image::{self as generic, GradientCompatMode};
|
||||||
use crate::values::specified::image::LineDirection as SpecifiedLineDirection;
|
use crate::values::specified::image::LineDirection as SpecifiedLineDirection;
|
||||||
use crate::values::specified::position::{X, Y};
|
use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword};
|
||||||
use crate::values::{Either, None_};
|
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ToCss};
|
use style_traits::{CssWriter, ToCss};
|
||||||
|
|
||||||
/// A computed image layer.
|
/// A computed image layer.
|
||||||
pub type ImageLayer = Either<None_, Image>;
|
pub type ImageLayer = generic::GenericImageLayer<Image>;
|
||||||
|
|
||||||
/// Computed values for an image according to CSS-IMAGES.
|
/// Computed values for an image according to CSS-IMAGES.
|
||||||
/// <https://drafts.csswg.org/css-images/#image-values>
|
/// <https://drafts.csswg.org/css-images/#image-values>
|
||||||
pub type Image = generic::Image<Gradient, MozImageRect, ComputedImageUrl>;
|
pub type Image = generic::GenericImage<Gradient, MozImageRect, ComputedImageUrl>;
|
||||||
|
|
||||||
/// Computed values for a CSS gradient.
|
/// Computed values for a CSS gradient.
|
||||||
/// <https://drafts.csswg.org/css-images/#gradients>
|
/// <https://drafts.csswg.org/css-images/#gradients>
|
||||||
pub type Gradient =
|
pub type Gradient =
|
||||||
generic::Gradient<LineDirection, Length, LengthPercentage, Position, Color>;
|
generic::GenericGradient<LineDirection, Length, LengthPercentage, Position, Color>;
|
||||||
|
|
||||||
/// A computed gradient kind.
|
/// A computed gradient kind.
|
||||||
pub type GradientKind =
|
pub type GradientKind =
|
||||||
generic::GradientKind<LineDirection, Length, LengthPercentage, Position>;
|
generic::GenericGradientKind<LineDirection, Length, LengthPercentage, Position>;
|
||||||
|
|
||||||
/// A computed gradient line direction.
|
/// A computed gradient line direction.
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToResolvedValue)]
|
||||||
|
#[repr(C, u8)]
|
||||||
pub enum LineDirection {
|
pub enum LineDirection {
|
||||||
/// An angle.
|
/// An angle.
|
||||||
Angle(Angle),
|
Angle(Angle),
|
||||||
/// A horizontal direction.
|
/// A horizontal direction.
|
||||||
Horizontal(X),
|
Horizontal(HorizontalPositionKeyword),
|
||||||
/// A vertical direction.
|
/// A vertical direction.
|
||||||
Vertical(Y),
|
Vertical(VerticalPositionKeyword),
|
||||||
/// A corner.
|
/// A corner.
|
||||||
Corner(X, Y),
|
Corner(HorizontalPositionKeyword, VerticalPositionKeyword),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A computed radial gradient ending shape.
|
/// A computed radial gradient ending shape.
|
||||||
|
@ -61,35 +61,39 @@ pub type ColorStop = generic::ColorStop<Color, LengthPercentage>;
|
||||||
pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, ComputedImageUrl>;
|
pub type MozImageRect = generic::MozImageRect<NumberOrPercentage, ComputedImageUrl>;
|
||||||
|
|
||||||
impl generic::LineDirection for LineDirection {
|
impl generic::LineDirection for LineDirection {
|
||||||
fn points_downwards(&self, compat_mode: CompatMode) -> bool {
|
fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
LineDirection::Angle(angle) => angle.radians() == PI,
|
LineDirection::Angle(angle) => angle.radians() == PI,
|
||||||
LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true,
|
LineDirection::Vertical(VerticalPositionKeyword::Bottom) => {
|
||||||
LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true,
|
compat_mode == GradientCompatMode::Modern
|
||||||
|
}
|
||||||
|
LineDirection::Vertical(VerticalPositionKeyword::Top) => {
|
||||||
|
compat_mode != GradientCompatMode::Modern
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>, compat_mode: CompatMode) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>, compat_mode: GradientCompatMode) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
LineDirection::Angle(ref angle) => angle.to_css(dest),
|
LineDirection::Angle(ref angle) => angle.to_css(dest),
|
||||||
LineDirection::Horizontal(x) => {
|
LineDirection::Horizontal(x) => {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
dest.write_str("to ")?;
|
dest.write_str("to ")?;
|
||||||
}
|
}
|
||||||
x.to_css(dest)
|
x.to_css(dest)
|
||||||
},
|
},
|
||||||
LineDirection::Vertical(y) => {
|
LineDirection::Vertical(y) => {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
dest.write_str("to ")?;
|
dest.write_str("to ")?;
|
||||||
}
|
}
|
||||||
y.to_css(dest)
|
y.to_css(dest)
|
||||||
},
|
},
|
||||||
LineDirection::Corner(x, y) => {
|
LineDirection::Corner(x, y) => {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
dest.write_str("to ")?;
|
dest.write_str("to ")?;
|
||||||
}
|
}
|
||||||
x.to_css(dest)?;
|
x.to_css(dest)?;
|
||||||
|
|
|
@ -13,13 +13,35 @@ use servo_arc::Arc;
|
||||||
use std::fmt::{self, Write};
|
use std::fmt::{self, Write};
|
||||||
use style_traits::{CssWriter, ToCss};
|
use style_traits::{CssWriter, ToCss};
|
||||||
|
|
||||||
|
/// An <image> | <none> (for background-image, for example).
|
||||||
|
#[derive(
|
||||||
|
Clone, Debug, MallocSizeOf, Parse, PartialEq, SpecifiedValueInfo, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
|
||||||
|
)]
|
||||||
|
pub enum GenericImageLayer<Image> {
|
||||||
|
/// The `none` value.
|
||||||
|
None,
|
||||||
|
/// The `<image>` value.
|
||||||
|
Image(Image),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub use self::GenericImageLayer as ImageLayer;
|
||||||
|
|
||||||
|
impl<I> ImageLayer<I> {
|
||||||
|
/// Returns `none`.
|
||||||
|
#[inline]
|
||||||
|
pub fn none() -> Self {
|
||||||
|
ImageLayer::None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// An [image].
|
/// An [image].
|
||||||
///
|
///
|
||||||
/// [image]: https://drafts.csswg.org/css-images/#image-values
|
/// [image]: https://drafts.csswg.org/css-images/#image-values
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem,
|
Clone, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToComputedValue, ToResolvedValue, ToShmem,
|
||||||
)]
|
)]
|
||||||
pub enum Image<Gradient, MozImageRect, ImageUrl> {
|
#[repr(C, u8)]
|
||||||
|
pub enum GenericImage<Gradient, MozImageRect, ImageUrl> {
|
||||||
/// A `<url()>` image.
|
/// A `<url()>` image.
|
||||||
Url(ImageUrl),
|
Url(ImageUrl),
|
||||||
/// A `<gradient>` image. Gradients are rather large, and not nearly as
|
/// A `<gradient>` image. Gradients are rather large, and not nearly as
|
||||||
|
@ -36,23 +58,29 @@ pub enum Image<Gradient, MozImageRect, ImageUrl> {
|
||||||
PaintWorklet(PaintWorklet),
|
PaintWorklet(PaintWorklet),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericImage as Image;
|
||||||
|
|
||||||
/// A CSS gradient.
|
/// A CSS gradient.
|
||||||
/// <https://drafts.csswg.org/css-images/#gradients>
|
/// <https://drafts.csswg.org/css-images/#gradients>
|
||||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||||
pub struct Gradient<LineDirection, Length, LengthPercentage, Position, Color> {
|
#[repr(C)]
|
||||||
|
pub struct GenericGradient<LineDirection, Length, LengthPercentage, Position, Color> {
|
||||||
/// Gradients can be linear or radial.
|
/// Gradients can be linear or radial.
|
||||||
pub kind: GradientKind<LineDirection, Length, LengthPercentage, Position>,
|
pub kind: GenericGradientKind<LineDirection, Length, LengthPercentage, Position>,
|
||||||
/// The color stops and interpolation hints.
|
/// The color stops and interpolation hints.
|
||||||
pub items: Vec<GradientItem<Color, LengthPercentage>>,
|
pub items: crate::OwnedSlice<GenericGradientItem<Color, LengthPercentage>>,
|
||||||
/// True if this is a repeating gradient.
|
/// True if this is a repeating gradient.
|
||||||
pub repeating: bool,
|
pub repeating: bool,
|
||||||
/// Compatibility mode.
|
/// Compatibility mode.
|
||||||
pub compat_mode: CompatMode,
|
pub compat_mode: GradientCompatMode,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericGradient as Gradient;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||||
|
#[repr(u8)]
|
||||||
/// Whether we used the modern notation or the compatibility `-webkit`, `-moz` prefixes.
|
/// Whether we used the modern notation or the compatibility `-webkit`, `-moz` prefixes.
|
||||||
pub enum CompatMode {
|
pub enum GradientCompatMode {
|
||||||
/// Modern syntax.
|
/// Modern syntax.
|
||||||
Modern,
|
Modern,
|
||||||
/// `-webkit` prefix.
|
/// `-webkit` prefix.
|
||||||
|
@ -63,44 +91,56 @@ pub enum CompatMode {
|
||||||
|
|
||||||
/// A gradient kind.
|
/// A gradient kind.
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||||
pub enum GradientKind<LineDirection, Length, LengthPercentage, Position> {
|
#[repr(C, u8)]
|
||||||
|
pub enum GenericGradientKind<LineDirection, Length, LengthPercentage, Position> {
|
||||||
/// A linear gradient.
|
/// A linear gradient.
|
||||||
Linear(LineDirection),
|
Linear(LineDirection),
|
||||||
/// A radial gradient.
|
/// A radial gradient.
|
||||||
Radial(EndingShape<Length, LengthPercentage>, Position),
|
Radial(GenericEndingShape<Length, LengthPercentage>, Position),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericGradientKind as GradientKind;
|
||||||
|
|
||||||
/// A radial gradient's ending shape.
|
/// A radial gradient's ending shape.
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
|
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
|
||||||
)]
|
)]
|
||||||
pub enum EndingShape<Length, LengthPercentage> {
|
#[repr(C, u8)]
|
||||||
|
pub enum GenericEndingShape<Length, LengthPercentage> {
|
||||||
/// A circular gradient.
|
/// A circular gradient.
|
||||||
Circle(Circle<Length>),
|
Circle(GenericCircle<Length>),
|
||||||
/// An elliptic gradient.
|
/// An elliptic gradient.
|
||||||
Ellipse(Ellipse<LengthPercentage>),
|
Ellipse(GenericEllipse<LengthPercentage>),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericEndingShape as EndingShape;
|
||||||
|
|
||||||
/// A circle shape.
|
/// A circle shape.
|
||||||
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
#[derive(Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToResolvedValue, ToShmem)]
|
||||||
pub enum Circle<Length> {
|
#[repr(C, u8)]
|
||||||
|
pub enum GenericCircle<Length> {
|
||||||
/// A circle radius.
|
/// A circle radius.
|
||||||
Radius(Length),
|
Radius(Length),
|
||||||
/// A circle extent.
|
/// A circle extent.
|
||||||
Extent(ShapeExtent),
|
Extent(ShapeExtent),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericCircle as Circle;
|
||||||
|
|
||||||
/// An ellipse shape.
|
/// An ellipse shape.
|
||||||
#[derive(
|
#[derive(
|
||||||
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
|
Clone, Copy, Debug, MallocSizeOf, PartialEq, ToComputedValue, ToCss, ToResolvedValue, ToShmem,
|
||||||
)]
|
)]
|
||||||
pub enum Ellipse<LengthPercentage> {
|
#[repr(C, u8)]
|
||||||
|
pub enum GenericEllipse<LengthPercentage> {
|
||||||
/// An ellipse pair of radii.
|
/// An ellipse pair of radii.
|
||||||
Radii(LengthPercentage, LengthPercentage),
|
Radii(LengthPercentage, LengthPercentage),
|
||||||
/// An ellipse extent.
|
/// An ellipse extent.
|
||||||
Extent(ShapeExtent),
|
Extent(ShapeExtent),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub use self::GenericEllipse as Ellipse;
|
||||||
|
|
||||||
/// <https://drafts.csswg.org/css-images/#typedef-extent-keyword>
|
/// <https://drafts.csswg.org/css-images/#typedef-extent-keyword>
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
|
||||||
|
@ -117,6 +157,7 @@ pub enum Ellipse<LengthPercentage> {
|
||||||
ToResolvedValue,
|
ToResolvedValue,
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
|
#[repr(u8)]
|
||||||
pub enum ShapeExtent {
|
pub enum ShapeExtent {
|
||||||
ClosestSide,
|
ClosestSide,
|
||||||
FarthestSide,
|
FarthestSide,
|
||||||
|
@ -277,8 +318,8 @@ where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
match self.compat_mode {
|
match self.compat_mode {
|
||||||
CompatMode::WebKit => dest.write_str("-webkit-")?,
|
GradientCompatMode::WebKit => dest.write_str("-webkit-")?,
|
||||||
CompatMode::Moz => dest.write_str("-moz-")?,
|
GradientCompatMode::Moz => dest.write_str("-moz-")?,
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -301,7 +342,7 @@ where
|
||||||
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true,
|
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => true,
|
||||||
_ => false,
|
_ => false,
|
||||||
};
|
};
|
||||||
if self.compat_mode == CompatMode::Modern {
|
if self.compat_mode == GradientCompatMode::Modern {
|
||||||
if !omit_shape {
|
if !omit_shape {
|
||||||
shape.to_css(dest)?;
|
shape.to_css(dest)?;
|
||||||
dest.write_str(" ")?;
|
dest.write_str(" ")?;
|
||||||
|
@ -318,7 +359,7 @@ where
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
for item in &self.items {
|
for item in &*self.items {
|
||||||
if !skip_comma {
|
if !skip_comma {
|
||||||
dest.write_str(", ")?;
|
dest.write_str(", ")?;
|
||||||
}
|
}
|
||||||
|
@ -341,10 +382,10 @@ impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
|
||||||
/// The direction of a linear gradient.
|
/// The direction of a linear gradient.
|
||||||
pub trait LineDirection {
|
pub trait LineDirection {
|
||||||
/// Whether this direction points towards, and thus can be omitted.
|
/// Whether this direction points towards, and thus can be omitted.
|
||||||
fn points_downwards(&self, compat_mode: CompatMode) -> bool;
|
fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool;
|
||||||
|
|
||||||
/// Serialises this direction according to the compatibility mode.
|
/// Serialises this direction according to the compatibility mode.
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>, compat_mode: CompatMode) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>, compat_mode: GradientCompatMode) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write;
|
W: Write;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,13 +11,13 @@ use crate::custom_properties::SpecifiedValue;
|
||||||
use crate::parser::{Parse, ParserContext};
|
use crate::parser::{Parse, ParserContext};
|
||||||
use crate::stylesheets::CorsMode;
|
use crate::stylesheets::CorsMode;
|
||||||
use crate::values::generics::image::PaintWorklet;
|
use crate::values::generics::image::PaintWorklet;
|
||||||
use crate::values::generics::image::{self as generic, Circle, CompatMode, Ellipse, ShapeExtent};
|
use crate::values::generics::image::{self as generic, Circle, GradientCompatMode, Ellipse, ShapeExtent};
|
||||||
use crate::values::generics::position::Position as GenericPosition;
|
use crate::values::generics::position::Position as GenericPosition;
|
||||||
use crate::values::specified::position::{Position, PositionComponent, Side, X, Y};
|
use crate::values::specified::position::{Position, PositionComponent, Side};
|
||||||
|
use crate::values::specified::position::{HorizontalPositionKeyword, VerticalPositionKeyword};
|
||||||
use crate::values::specified::url::SpecifiedImageUrl;
|
use crate::values::specified::url::SpecifiedImageUrl;
|
||||||
use crate::values::specified::{Angle, Color, Length, LengthPercentage};
|
use crate::values::specified::{Angle, Color, Length, LengthPercentage};
|
||||||
use crate::values::specified::{Number, NumberOrPercentage, Percentage};
|
use crate::values::specified::{Number, NumberOrPercentage, Percentage};
|
||||||
use crate::values::{Either, None_};
|
|
||||||
use crate::Atom;
|
use crate::Atom;
|
||||||
use cssparser::{Delimiter, Parser, Token};
|
use cssparser::{Delimiter, Parser, Token};
|
||||||
use selectors::parser::SelectorParseErrorKind;
|
use selectors::parser::SelectorParseErrorKind;
|
||||||
|
@ -29,7 +29,7 @@ use style_traits::{CssType, CssWriter, KeywordsCollectFn, ParseError};
|
||||||
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
|
use style_traits::{SpecifiedValueInfo, StyleParseErrorKind, ToCss};
|
||||||
|
|
||||||
/// A specified image layer.
|
/// A specified image layer.
|
||||||
pub type ImageLayer = Either<None_, Image>;
|
pub type ImageLayer = generic::GenericImageLayer<Image>;
|
||||||
|
|
||||||
impl ImageLayer {
|
impl ImageLayer {
|
||||||
/// This is a specialization of Either with an alternative parse
|
/// This is a specialization of Either with an alternative parse
|
||||||
|
@ -38,10 +38,11 @@ impl ImageLayer {
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
if let Ok(v) = input.try(|i| None_::parse(context, i)) {
|
if let Ok(v) = input.try(|i| Image::parse_with_cors_anonymous(context, i)) {
|
||||||
return Ok(Either::First(v));
|
return Ok(generic::GenericImageLayer::Image(v));
|
||||||
}
|
}
|
||||||
Image::parse_with_cors_anonymous(context, input).map(Either::Second)
|
input.expect_ident_matching("none")?;
|
||||||
|
Ok(generic::GenericImageLayer::None)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -87,11 +88,11 @@ pub enum LineDirection {
|
||||||
/// An angular direction.
|
/// An angular direction.
|
||||||
Angle(Angle),
|
Angle(Angle),
|
||||||
/// A horizontal direction.
|
/// A horizontal direction.
|
||||||
Horizontal(X),
|
Horizontal(HorizontalPositionKeyword),
|
||||||
/// A vertical direction.
|
/// A vertical direction.
|
||||||
Vertical(Y),
|
Vertical(VerticalPositionKeyword),
|
||||||
/// A direction towards a corner of a box.
|
/// A direction towards a corner of a box.
|
||||||
Corner(X, Y),
|
Corner(HorizontalPositionKeyword, VerticalPositionKeyword),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A specified ending shape.
|
/// A specified ending shape.
|
||||||
|
@ -182,44 +183,44 @@ impl Parse for Gradient {
|
||||||
let func = input.expect_function()?.clone();
|
let func = input.expect_function()?.clone();
|
||||||
let result = match_ignore_ascii_case! { &func,
|
let result = match_ignore_ascii_case! { &func,
|
||||||
"linear-gradient" => {
|
"linear-gradient" => {
|
||||||
Some((Shape::Linear, false, CompatMode::Modern))
|
Some((Shape::Linear, false, GradientCompatMode::Modern))
|
||||||
},
|
},
|
||||||
"-webkit-linear-gradient" => {
|
"-webkit-linear-gradient" => {
|
||||||
Some((Shape::Linear, false, CompatMode::WebKit))
|
Some((Shape::Linear, false, GradientCompatMode::WebKit))
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-linear-gradient" => {
|
"-moz-linear-gradient" => {
|
||||||
Some((Shape::Linear, false, CompatMode::Moz))
|
Some((Shape::Linear, false, GradientCompatMode::Moz))
|
||||||
},
|
},
|
||||||
"repeating-linear-gradient" => {
|
"repeating-linear-gradient" => {
|
||||||
Some((Shape::Linear, true, CompatMode::Modern))
|
Some((Shape::Linear, true, GradientCompatMode::Modern))
|
||||||
},
|
},
|
||||||
"-webkit-repeating-linear-gradient" => {
|
"-webkit-repeating-linear-gradient" => {
|
||||||
Some((Shape::Linear, true, CompatMode::WebKit))
|
Some((Shape::Linear, true, GradientCompatMode::WebKit))
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-repeating-linear-gradient" => {
|
"-moz-repeating-linear-gradient" => {
|
||||||
Some((Shape::Linear, true, CompatMode::Moz))
|
Some((Shape::Linear, true, GradientCompatMode::Moz))
|
||||||
},
|
},
|
||||||
"radial-gradient" => {
|
"radial-gradient" => {
|
||||||
Some((Shape::Radial, false, CompatMode::Modern))
|
Some((Shape::Radial, false, GradientCompatMode::Modern))
|
||||||
},
|
},
|
||||||
"-webkit-radial-gradient" => {
|
"-webkit-radial-gradient" => {
|
||||||
Some((Shape::Radial, false, CompatMode::WebKit))
|
Some((Shape::Radial, false, GradientCompatMode::WebKit))
|
||||||
}
|
}
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-radial-gradient" => {
|
"-moz-radial-gradient" => {
|
||||||
Some((Shape::Radial, false, CompatMode::Moz))
|
Some((Shape::Radial, false, GradientCompatMode::Moz))
|
||||||
},
|
},
|
||||||
"repeating-radial-gradient" => {
|
"repeating-radial-gradient" => {
|
||||||
Some((Shape::Radial, true, CompatMode::Modern))
|
Some((Shape::Radial, true, GradientCompatMode::Modern))
|
||||||
},
|
},
|
||||||
"-webkit-repeating-radial-gradient" => {
|
"-webkit-repeating-radial-gradient" => {
|
||||||
Some((Shape::Radial, true, CompatMode::WebKit))
|
Some((Shape::Radial, true, GradientCompatMode::WebKit))
|
||||||
},
|
},
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
"-moz-repeating-radial-gradient" => {
|
"-moz-repeating-radial-gradient" => {
|
||||||
Some((Shape::Radial, true, CompatMode::Moz))
|
Some((Shape::Radial, true, GradientCompatMode::Moz))
|
||||||
},
|
},
|
||||||
"-webkit-gradient" => {
|
"-webkit-gradient" => {
|
||||||
return input.parse_nested_block(|i| {
|
return input.parse_nested_block(|i| {
|
||||||
|
@ -249,12 +250,7 @@ impl Parse for Gradient {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Gradient {
|
Ok(Gradient { items, repeating, kind, compat_mode })
|
||||||
items: items,
|
|
||||||
repeating: repeating,
|
|
||||||
kind: kind,
|
|
||||||
compat_mode: compat_mode,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +259,7 @@ impl Gradient {
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
|
use crate::values::specified::position::{HorizontalPositionKeyword as X, VerticalPositionKeyword as Y};
|
||||||
type Point = GenericPosition<Component<X>, Component<Y>>;
|
type Point = GenericPosition<Component<X>, Component<Y>>;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Parse)]
|
#[derive(Clone, Copy, Parse)]
|
||||||
|
@ -493,21 +490,21 @@ impl Gradient {
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(generic::Gradient {
|
Ok(generic::Gradient {
|
||||||
kind: kind,
|
kind,
|
||||||
items: items,
|
items: items.into(),
|
||||||
repeating: false,
|
repeating: false,
|
||||||
compat_mode: CompatMode::Modern,
|
compat_mode: GradientCompatMode::Modern,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GradientKind {
|
impl GradientKind {
|
||||||
/// Parses a linear gradient.
|
/// Parses a linear gradient.
|
||||||
/// CompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword.
|
/// GradientCompatMode can change during `-moz-` prefixed gradient parsing if it come across a `to` keyword.
|
||||||
fn parse_linear<'i, 't>(
|
fn parse_linear<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
compat_mode: &mut CompatMode,
|
compat_mode: &mut GradientCompatMode,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode))
|
let direction = if let Ok(d) = input.try(|i| LineDirection::parse(context, i, compat_mode))
|
||||||
{
|
{
|
||||||
|
@ -515,8 +512,8 @@ impl GradientKind {
|
||||||
d
|
d
|
||||||
} else {
|
} else {
|
||||||
match *compat_mode {
|
match *compat_mode {
|
||||||
CompatMode::Modern => LineDirection::Vertical(Y::Bottom),
|
GradientCompatMode::Modern => LineDirection::Vertical(VerticalPositionKeyword::Bottom),
|
||||||
_ => LineDirection::Vertical(Y::Top),
|
_ => LineDirection::Vertical(VerticalPositionKeyword::Top),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Ok(generic::GradientKind::Linear(direction))
|
Ok(generic::GradientKind::Linear(direction))
|
||||||
|
@ -524,10 +521,10 @@ impl GradientKind {
|
||||||
fn parse_radial<'i, 't>(
|
fn parse_radial<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
compat_mode: &mut CompatMode,
|
compat_mode: &mut GradientCompatMode,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
let (shape, position) = match *compat_mode {
|
let (shape, position) = match *compat_mode {
|
||||||
CompatMode::Modern => {
|
GradientCompatMode::Modern => {
|
||||||
let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode));
|
let shape = input.try(|i| EndingShape::parse(context, i, *compat_mode));
|
||||||
let position = input.try(|i| {
|
let position = input.try(|i| {
|
||||||
i.expect_ident_matching("at")?;
|
i.expect_ident_matching("at")?;
|
||||||
|
@ -561,35 +558,39 @@ impl GradientKind {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl generic::LineDirection for LineDirection {
|
impl generic::LineDirection for LineDirection {
|
||||||
fn points_downwards(&self, compat_mode: CompatMode) -> bool {
|
fn points_downwards(&self, compat_mode: GradientCompatMode) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
LineDirection::Angle(ref angle) => angle.degrees() == 180.0,
|
LineDirection::Angle(ref angle) => angle.degrees() == 180.0,
|
||||||
LineDirection::Vertical(Y::Bottom) if compat_mode == CompatMode::Modern => true,
|
LineDirection::Vertical(VerticalPositionKeyword::Bottom) => {
|
||||||
LineDirection::Vertical(Y::Top) if compat_mode != CompatMode::Modern => true,
|
compat_mode == GradientCompatMode::Modern
|
||||||
|
}
|
||||||
|
LineDirection::Vertical(VerticalPositionKeyword::Top) => {
|
||||||
|
compat_mode != GradientCompatMode::Modern
|
||||||
|
}
|
||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_css<W>(&self, dest: &mut CssWriter<W>, compat_mode: CompatMode) -> fmt::Result
|
fn to_css<W>(&self, dest: &mut CssWriter<W>, compat_mode: GradientCompatMode) -> fmt::Result
|
||||||
where
|
where
|
||||||
W: Write,
|
W: Write,
|
||||||
{
|
{
|
||||||
match *self {
|
match *self {
|
||||||
LineDirection::Angle(angle) => angle.to_css(dest),
|
LineDirection::Angle(angle) => angle.to_css(dest),
|
||||||
LineDirection::Horizontal(x) => {
|
LineDirection::Horizontal(x) => {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
dest.write_str("to ")?;
|
dest.write_str("to ")?;
|
||||||
}
|
}
|
||||||
x.to_css(dest)
|
x.to_css(dest)
|
||||||
},
|
},
|
||||||
LineDirection::Vertical(y) => {
|
LineDirection::Vertical(y) => {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
dest.write_str("to ")?;
|
dest.write_str("to ")?;
|
||||||
}
|
}
|
||||||
y.to_css(dest)
|
y.to_css(dest)
|
||||||
},
|
},
|
||||||
LineDirection::Corner(x, y) => {
|
LineDirection::Corner(x, y) => {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
dest.write_str("to ")?;
|
dest.write_str("to ")?;
|
||||||
}
|
}
|
||||||
x.to_css(dest)?;
|
x.to_css(dest)?;
|
||||||
|
@ -604,7 +605,7 @@ impl LineDirection {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
compat_mode: &mut CompatMode,
|
compat_mode: &mut GradientCompatMode,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
// Gradients allow unitless zero angles as an exception, see:
|
// Gradients allow unitless zero angles as an exception, see:
|
||||||
// https://github.com/w3c/csswg-drafts/issues/1162
|
// https://github.com/w3c/csswg-drafts/issues/1162
|
||||||
|
@ -616,14 +617,14 @@ impl LineDirection {
|
||||||
let to_ident = i.try(|i| i.expect_ident_matching("to"));
|
let to_ident = i.try(|i| i.expect_ident_matching("to"));
|
||||||
match *compat_mode {
|
match *compat_mode {
|
||||||
// `to` keyword is mandatory in modern syntax.
|
// `to` keyword is mandatory in modern syntax.
|
||||||
CompatMode::Modern => to_ident?,
|
GradientCompatMode::Modern => to_ident?,
|
||||||
// Fall back to Modern compatibility mode in case there is a `to` keyword.
|
// Fall back to Modern compatibility mode in case there is a `to` keyword.
|
||||||
// According to Gecko, `-moz-linear-gradient(to ...)` should serialize like
|
// According to Gecko, `-moz-linear-gradient(to ...)` should serialize like
|
||||||
// `linear-gradient(to ...)`.
|
// `linear-gradient(to ...)`.
|
||||||
CompatMode::Moz if to_ident.is_ok() => *compat_mode = CompatMode::Modern,
|
GradientCompatMode::Moz if to_ident.is_ok() => *compat_mode = GradientCompatMode::Modern,
|
||||||
// There is no `to` keyword in webkit prefixed syntax. If it's consumed,
|
// There is no `to` keyword in webkit prefixed syntax. If it's consumed,
|
||||||
// parsing should throw an error.
|
// parsing should throw an error.
|
||||||
CompatMode::WebKit if to_ident.is_ok() => {
|
GradientCompatMode::WebKit if to_ident.is_ok() => {
|
||||||
return Err(
|
return Err(
|
||||||
i.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("to".into()))
|
i.new_custom_error(SelectorParseErrorKind::UnexpectedIdent("to".into()))
|
||||||
);
|
);
|
||||||
|
@ -631,14 +632,14 @@ impl LineDirection {
|
||||||
_ => {},
|
_ => {},
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Ok(x) = i.try(X::parse) {
|
if let Ok(x) = i.try(HorizontalPositionKeyword::parse) {
|
||||||
if let Ok(y) = i.try(Y::parse) {
|
if let Ok(y) = i.try(VerticalPositionKeyword::parse) {
|
||||||
return Ok(LineDirection::Corner(x, y));
|
return Ok(LineDirection::Corner(x, y));
|
||||||
}
|
}
|
||||||
return Ok(LineDirection::Horizontal(x));
|
return Ok(LineDirection::Horizontal(x));
|
||||||
}
|
}
|
||||||
let y = Y::parse(i)?;
|
let y = VerticalPositionKeyword::parse(i)?;
|
||||||
if let Ok(x) = i.try(X::parse) {
|
if let Ok(x) = i.try(HorizontalPositionKeyword::parse) {
|
||||||
return Ok(LineDirection::Corner(x, y));
|
return Ok(LineDirection::Corner(x, y));
|
||||||
}
|
}
|
||||||
Ok(LineDirection::Vertical(y))
|
Ok(LineDirection::Vertical(y))
|
||||||
|
@ -650,7 +651,7 @@ impl EndingShape {
|
||||||
fn parse<'i, 't>(
|
fn parse<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
compat_mode: CompatMode,
|
compat_mode: GradientCompatMode,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
||||||
if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
|
if input.try(|i| i.expect_ident_matching("circle")).is_ok() {
|
||||||
|
@ -663,7 +664,7 @@ impl EndingShape {
|
||||||
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
||||||
return Ok(generic::EndingShape::Circle(Circle::Extent(extent)));
|
return Ok(generic::EndingShape::Circle(Circle::Extent(extent)));
|
||||||
}
|
}
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
if let Ok(length) = input.try(|i| Length::parse(context, i)) {
|
if let Ok(length) = input.try(|i| Length::parse(context, i)) {
|
||||||
return Ok(generic::EndingShape::Circle(Circle::Radius(length)));
|
return Ok(generic::EndingShape::Circle(Circle::Radius(length)));
|
||||||
}
|
}
|
||||||
|
@ -676,7 +677,7 @@ impl EndingShape {
|
||||||
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
if let Ok(extent) = input.try(|i| ShapeExtent::parse_with_compat_mode(i, compat_mode)) {
|
||||||
return Ok(generic::EndingShape::Ellipse(Ellipse::Extent(extent)));
|
return Ok(generic::EndingShape::Ellipse(Ellipse::Extent(extent)));
|
||||||
}
|
}
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
let pair: Result<_, ParseError> = input.try(|i| {
|
let pair: Result<_, ParseError> = input.try(|i| {
|
||||||
let x = LengthPercentage::parse(context, i)?;
|
let x = LengthPercentage::parse(context, i)?;
|
||||||
let y = LengthPercentage::parse(context, i)?;
|
let y = LengthPercentage::parse(context, i)?;
|
||||||
|
@ -692,7 +693,7 @@ impl EndingShape {
|
||||||
}
|
}
|
||||||
if let Ok(length) = input.try(|i| Length::parse(context, i)) {
|
if let Ok(length) = input.try(|i| Length::parse(context, i)) {
|
||||||
if let Ok(y) = input.try(|i| LengthPercentage::parse(context, i)) {
|
if let Ok(y) = input.try(|i| LengthPercentage::parse(context, i)) {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
let _ = input.try(|i| i.expect_ident_matching("ellipse"));
|
let _ = input.try(|i| i.expect_ident_matching("ellipse"));
|
||||||
}
|
}
|
||||||
return Ok(generic::EndingShape::Ellipse(Ellipse::Radii(
|
return Ok(generic::EndingShape::Ellipse(Ellipse::Radii(
|
||||||
|
@ -700,7 +701,7 @@ impl EndingShape {
|
||||||
y,
|
y,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
let y = input.try(|i| {
|
let y = input.try(|i| {
|
||||||
i.expect_ident_matching("ellipse")?;
|
i.expect_ident_matching("ellipse")?;
|
||||||
LengthPercentage::parse(context, i)
|
LengthPercentage::parse(context, i)
|
||||||
|
@ -719,12 +720,12 @@ impl EndingShape {
|
||||||
input.try(|i| {
|
input.try(|i| {
|
||||||
let x = Percentage::parse(context, i)?;
|
let x = Percentage::parse(context, i)?;
|
||||||
let y = if let Ok(y) = i.try(|i| LengthPercentage::parse(context, i)) {
|
let y = if let Ok(y) = i.try(|i| LengthPercentage::parse(context, i)) {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
let _ = i.try(|i| i.expect_ident_matching("ellipse"));
|
let _ = i.try(|i| i.expect_ident_matching("ellipse"));
|
||||||
}
|
}
|
||||||
y
|
y
|
||||||
} else {
|
} else {
|
||||||
if compat_mode == CompatMode::Modern {
|
if compat_mode == GradientCompatMode::Modern {
|
||||||
i.expect_ident_matching("ellipse")?;
|
i.expect_ident_matching("ellipse")?;
|
||||||
}
|
}
|
||||||
LengthPercentage::parse(context, i)?
|
LengthPercentage::parse(context, i)?
|
||||||
|
@ -737,10 +738,10 @@ impl EndingShape {
|
||||||
impl ShapeExtent {
|
impl ShapeExtent {
|
||||||
fn parse_with_compat_mode<'i, 't>(
|
fn parse_with_compat_mode<'i, 't>(
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
compat_mode: CompatMode,
|
compat_mode: GradientCompatMode,
|
||||||
) -> Result<Self, ParseError<'i>> {
|
) -> Result<Self, ParseError<'i>> {
|
||||||
match Self::parse(input)? {
|
match Self::parse(input)? {
|
||||||
ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == CompatMode::Modern => {
|
ShapeExtent::Contain | ShapeExtent::Cover if compat_mode == GradientCompatMode::Modern => {
|
||||||
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError))
|
||||||
},
|
},
|
||||||
ShapeExtent::Contain => Ok(ShapeExtent::ClosestSide),
|
ShapeExtent::Contain => Ok(ShapeExtent::ClosestSide),
|
||||||
|
@ -754,7 +755,7 @@ impl GradientItem {
|
||||||
fn parse_comma_separated<'i, 't>(
|
fn parse_comma_separated<'i, 't>(
|
||||||
context: &ParserContext,
|
context: &ParserContext,
|
||||||
input: &mut Parser<'i, 't>,
|
input: &mut Parser<'i, 't>,
|
||||||
) -> Result<Vec<Self>, ParseError<'i>> {
|
) -> Result<crate::OwnedSlice<Self>, ParseError<'i>> {
|
||||||
let mut items = Vec::new();
|
let mut items = Vec::new();
|
||||||
let mut seen_stop = false;
|
let mut seen_stop = false;
|
||||||
|
|
||||||
|
@ -798,7 +799,7 @@ impl GradientItem {
|
||||||
if !seen_stop || items.len() < 2 {
|
if !seen_stop || items.len() < 2 {
|
||||||
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
return Err(input.new_custom_error(StyleParseErrorKind::UnspecifiedError));
|
||||||
}
|
}
|
||||||
Ok(items)
|
Ok(items.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,10 @@ use style_traits::{CssWriter, ParseError, StyleParseErrorKind, ToCss};
|
||||||
pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;
|
pub type Position = GenericPosition<HorizontalPosition, VerticalPosition>;
|
||||||
|
|
||||||
/// The specified value of a horizontal position.
|
/// The specified value of a horizontal position.
|
||||||
pub type HorizontalPosition = PositionComponent<X>;
|
pub type HorizontalPosition = PositionComponent<HorizontalPositionKeyword>;
|
||||||
|
|
||||||
/// The specified value of a vertical position.
|
/// The specified value of a vertical position.
|
||||||
pub type VerticalPosition = PositionComponent<Y>;
|
pub type VerticalPosition = PositionComponent<VerticalPositionKeyword>;
|
||||||
|
|
||||||
/// The specified value of a component of a CSS `<position>`.
|
/// The specified value of a component of a CSS `<position>`.
|
||||||
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
#[derive(Clone, Debug, MallocSizeOf, PartialEq, SpecifiedValueInfo, ToCss, ToShmem)]
|
||||||
|
@ -61,7 +61,8 @@ pub enum PositionComponent<S> {
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum X {
|
#[repr(u8)]
|
||||||
|
pub enum HorizontalPositionKeyword {
|
||||||
Left,
|
Left,
|
||||||
Right,
|
Right,
|
||||||
}
|
}
|
||||||
|
@ -83,7 +84,8 @@ pub enum X {
|
||||||
ToShmem,
|
ToShmem,
|
||||||
)]
|
)]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum Y {
|
#[repr(u8)]
|
||||||
|
pub enum VerticalPositionKeyword {
|
||||||
Top,
|
Top,
|
||||||
Bottom,
|
Bottom,
|
||||||
}
|
}
|
||||||
|
@ -123,7 +125,7 @@ impl Position {
|
||||||
let y_pos = PositionComponent::Center;
|
let y_pos = PositionComponent::Center;
|
||||||
return Ok(Self::new(x_pos, y_pos));
|
return Ok(Self::new(x_pos, y_pos));
|
||||||
}
|
}
|
||||||
if let Ok(y_keyword) = input.try(Y::parse) {
|
if let Ok(y_keyword) = input.try(VerticalPositionKeyword::parse) {
|
||||||
let y_lp = input
|
let y_lp = input
|
||||||
.try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
|
.try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -136,7 +138,7 @@ impl Position {
|
||||||
return Ok(Self::new(x_pos, y_pos));
|
return Ok(Self::new(x_pos, y_pos));
|
||||||
},
|
},
|
||||||
Ok(x_pos @ PositionComponent::Length(_)) => {
|
Ok(x_pos @ PositionComponent::Length(_)) => {
|
||||||
if let Ok(y_keyword) = input.try(Y::parse) {
|
if let Ok(y_keyword) = input.try(VerticalPositionKeyword::parse) {
|
||||||
let y_pos = PositionComponent::Side(y_keyword, None);
|
let y_pos = PositionComponent::Side(y_keyword, None);
|
||||||
return Ok(Self::new(x_pos, y_pos));
|
return Ok(Self::new(x_pos, y_pos));
|
||||||
}
|
}
|
||||||
|
@ -152,12 +154,12 @@ impl Position {
|
||||||
},
|
},
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
}
|
}
|
||||||
let y_keyword = Y::parse(input)?;
|
let y_keyword = VerticalPositionKeyword::parse(input)?;
|
||||||
let lp_and_x_pos: Result<_, ParseError> = input.try(|i| {
|
let lp_and_x_pos: Result<_, ParseError> = input.try(|i| {
|
||||||
let y_lp = i
|
let y_lp = i
|
||||||
.try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
|
.try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
|
||||||
.ok();
|
.ok();
|
||||||
if let Ok(x_keyword) = i.try(X::parse) {
|
if let Ok(x_keyword) = i.try(HorizontalPositionKeyword::parse) {
|
||||||
let x_lp = i
|
let x_lp = i
|
||||||
.try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
|
.try(|i| LengthPercentage::parse_quirky(context, i, allow_quirks))
|
||||||
.ok();
|
.ok();
|
||||||
|
@ -301,27 +303,27 @@ pub trait Side {
|
||||||
fn is_start(&self) -> bool;
|
fn is_start(&self) -> bool;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Side for X {
|
impl Side for HorizontalPositionKeyword {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn start() -> Self {
|
fn start() -> Self {
|
||||||
X::Left
|
HorizontalPositionKeyword::Left
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_start(&self) -> bool {
|
fn is_start(&self) -> bool {
|
||||||
*self == X::Left
|
*self == Self::start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Side for Y {
|
impl Side for VerticalPositionKeyword {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn start() -> Self {
|
fn start() -> Self {
|
||||||
Y::Top
|
VerticalPositionKeyword::Top
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn is_start(&self) -> bool {
|
fn is_start(&self) -> bool {
|
||||||
*self == Y::Top
|
*self == Self::start()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use crate::values::computed::{Context, LengthPercentage as ComputedLengthPercent
|
||||||
use crate::values::computed::{Percentage as ComputedPercentage, ToComputedValue};
|
use crate::values::computed::{Percentage as ComputedPercentage, ToComputedValue};
|
||||||
use crate::values::generics::transform as generic;
|
use crate::values::generics::transform as generic;
|
||||||
use crate::values::generics::transform::{Matrix, Matrix3D};
|
use crate::values::generics::transform::{Matrix, Matrix3D};
|
||||||
use crate::values::specified::position::{Side, X, Y};
|
use crate::values::specified::position::{Side, HorizontalPositionKeyword, VerticalPositionKeyword};
|
||||||
use crate::values::specified::{self, Angle, Integer, Length, LengthPercentage, Number};
|
use crate::values::specified::{self, Angle, Integer, Length, LengthPercentage, Number};
|
||||||
use crate::Zero;
|
use crate::Zero;
|
||||||
use cssparser::Parser;
|
use cssparser::Parser;
|
||||||
|
@ -25,7 +25,11 @@ pub type TransformOperation =
|
||||||
pub type Transform = generic::Transform<TransformOperation>;
|
pub type Transform = generic::Transform<TransformOperation>;
|
||||||
|
|
||||||
/// The specified value of a CSS `<transform-origin>`
|
/// The specified value of a CSS `<transform-origin>`
|
||||||
pub type TransformOrigin = generic::TransformOrigin<OriginComponent<X>, OriginComponent<Y>, Length>;
|
pub type TransformOrigin = generic::TransformOrigin<
|
||||||
|
OriginComponent<HorizontalPositionKeyword>,
|
||||||
|
OriginComponent<VerticalPositionKeyword>,
|
||||||
|
Length,
|
||||||
|
>;
|
||||||
|
|
||||||
impl Transform {
|
impl Transform {
|
||||||
/// Internal parse function for deciding if we wish to accept prefixed values or not
|
/// Internal parse function for deciding if we wish to accept prefixed values or not
|
||||||
|
@ -263,7 +267,7 @@ impl Parse for TransformOrigin {
|
||||||
return Ok(Self::new(x_origin, y_origin, depth));
|
return Ok(Self::new(x_origin, y_origin, depth));
|
||||||
}
|
}
|
||||||
let y_origin = OriginComponent::Center;
|
let y_origin = OriginComponent::Center;
|
||||||
if let Ok(x_keyword) = input.try(X::parse) {
|
if let Ok(x_keyword) = input.try(HorizontalPositionKeyword::parse) {
|
||||||
let x_origin = OriginComponent::Side(x_keyword);
|
let x_origin = OriginComponent::Side(x_keyword);
|
||||||
let depth = parse_depth(input);
|
let depth = parse_depth(input);
|
||||||
return Ok(Self::new(x_origin, y_origin, depth));
|
return Ok(Self::new(x_origin, y_origin, depth));
|
||||||
|
@ -282,9 +286,9 @@ impl Parse for TransformOrigin {
|
||||||
},
|
},
|
||||||
Err(_) => {},
|
Err(_) => {},
|
||||||
}
|
}
|
||||||
let y_keyword = Y::parse(input)?;
|
let y_keyword = VerticalPositionKeyword::parse(input)?;
|
||||||
let y_origin = OriginComponent::Side(y_keyword);
|
let y_origin = OriginComponent::Side(y_keyword);
|
||||||
if let Ok(x_keyword) = input.try(X::parse) {
|
if let Ok(x_keyword) = input.try(HorizontalPositionKeyword::parse) {
|
||||||
let x_origin = OriginComponent::Side(x_keyword);
|
let x_origin = OriginComponent::Side(x_keyword);
|
||||||
let depth = parse_depth(input);
|
let depth = parse_depth(input);
|
||||||
return Ok(Self::new(x_origin, y_origin, depth));
|
return Ok(Self::new(x_origin, y_origin, depth));
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue