mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #16859 - nox:gradients, r=emilio
Rewrite style images with a good dose of generics 💉 <!-- 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/16859) <!-- Reviewable:end -->
This commit is contained in:
commit
eb7314b412
18 changed files with 1509 additions and 1476 deletions
|
@ -57,12 +57,14 @@ use style::properties::{self, ServoComputedValues};
|
||||||
use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword;
|
use style::properties::longhands::border_image_repeat::computed_value::RepeatKeyword;
|
||||||
use style::properties::style_structs;
|
use style::properties::style_structs;
|
||||||
use style::servo::restyle_damage::REPAINT;
|
use style::servo::restyle_damage::REPAINT;
|
||||||
use style::values::{Either, RGBA, computed};
|
use style::values::{Either, RGBA};
|
||||||
use style::values::computed::{AngleOrCorner, Gradient, GradientItem, GradientKind, LengthOrPercentage};
|
use style::values::computed::{Gradient, GradientItem, LengthOrPercentage};
|
||||||
use style::values::computed::{LengthOrPercentageOrAuto, LengthOrKeyword, LengthOrPercentageOrKeyword};
|
use style::values::computed::{LengthOrPercentageOrAuto, NumberOrPercentage, Position};
|
||||||
use style::values::computed::{NumberOrPercentage, Position};
|
use style::values::computed::image::{EndingShape, LineDirection};
|
||||||
use style::values::computed::image::{EndingShape, SizeKeyword};
|
use style::values::generics::image::{Circle, Ellipse, EndingShape as GenericEndingShape};
|
||||||
use style::values::specified::{HorizontalDirection, VerticalDirection};
|
use style::values::generics::image::{GradientItem as GenericGradientItem, GradientKind};
|
||||||
|
use style::values::generics::image::{Image, ShapeExtent};
|
||||||
|
use style::values::specified::position::{X, Y};
|
||||||
use style_traits::CSSPixel;
|
use style_traits::CSSPixel;
|
||||||
use style_traits::cursor::Cursor;
|
use style_traits::cursor::Cursor;
|
||||||
use table_cell::CollapsedBordersForCell;
|
use table_cell::CollapsedBordersForCell;
|
||||||
|
@ -390,7 +392,7 @@ pub trait FragmentDisplayListBuilding {
|
||||||
fn convert_linear_gradient(&self,
|
fn convert_linear_gradient(&self,
|
||||||
bounds: &Rect<Au>,
|
bounds: &Rect<Au>,
|
||||||
stops: &[GradientItem],
|
stops: &[GradientItem],
|
||||||
angle_or_corner: &AngleOrCorner,
|
direction: &LineDirection,
|
||||||
repeating: bool,
|
repeating: bool,
|
||||||
style: &ServoComputedValues)
|
style: &ServoComputedValues)
|
||||||
-> display_list::Gradient;
|
-> display_list::Gradient;
|
||||||
|
@ -610,7 +612,7 @@ fn convert_gradient_stops(gradient_items: &[GradientItem],
|
||||||
// Only keep the color stops, discard the color interpolation hints.
|
// Only keep the color stops, discard the color interpolation hints.
|
||||||
let mut stop_items = gradient_items.iter().filter_map(|item| {
|
let mut stop_items = gradient_items.iter().filter_map(|item| {
|
||||||
match *item {
|
match *item {
|
||||||
GradientItem::ColorStop(ref stop) => Some(*stop),
|
GenericGradientItem::ColorStop(ref stop) => Some(*stop),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}).collect::<Vec<_>>();
|
}).collect::<Vec<_>>();
|
||||||
|
@ -758,36 +760,46 @@ fn get_ellipse_radius<F>(size: &Size2D<Au>, center: &Point2D<Au>, cmp: F) -> Siz
|
||||||
|
|
||||||
/// Determines the radius of a circle if it was not explictly provided.
|
/// Determines the radius of a circle if it was not explictly provided.
|
||||||
/// https://drafts.csswg.org/css-images-3/#typedef-size
|
/// https://drafts.csswg.org/css-images-3/#typedef-size
|
||||||
fn convert_circle_size_keyword(keyword: SizeKeyword,
|
fn convert_circle_size_keyword(keyword: ShapeExtent,
|
||||||
size: &Size2D<Au>,
|
size: &Size2D<Au>,
|
||||||
center: &Point2D<Au>) -> Size2D<Au> {
|
center: &Point2D<Au>) -> Size2D<Au> {
|
||||||
use style::values::computed::image::SizeKeyword::*;
|
|
||||||
let radius = match keyword {
|
let radius = match keyword {
|
||||||
ClosestSide | Contain => {
|
ShapeExtent::ClosestSide | ShapeExtent::Contain => {
|
||||||
let dist = get_distance_to_sides(size, center, ::std::cmp::min);
|
let dist = get_distance_to_sides(size, center, ::std::cmp::min);
|
||||||
::std::cmp::min(dist.width, dist.height)
|
::std::cmp::min(dist.width, dist.height)
|
||||||
}
|
}
|
||||||
FarthestSide => {
|
ShapeExtent::FarthestSide => {
|
||||||
let dist = get_distance_to_sides(size, center, ::std::cmp::max);
|
let dist = get_distance_to_sides(size, center, ::std::cmp::max);
|
||||||
::std::cmp::max(dist.width, dist.height)
|
::std::cmp::max(dist.width, dist.height)
|
||||||
}
|
}
|
||||||
ClosestCorner => get_distance_to_corner(size, center, ::std::cmp::min),
|
ShapeExtent::ClosestCorner => {
|
||||||
FarthestCorner | Cover => get_distance_to_corner(size, center, ::std::cmp::max),
|
get_distance_to_corner(size, center, ::std::cmp::min)
|
||||||
|
},
|
||||||
|
ShapeExtent::FarthestCorner | ShapeExtent::Cover => {
|
||||||
|
get_distance_to_corner(size, center, ::std::cmp::max)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
Size2D::new(radius, radius)
|
Size2D::new(radius, radius)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Determines the radius of an ellipse if it was not explictly provided.
|
/// Determines the radius of an ellipse if it was not explictly provided.
|
||||||
/// https://drafts.csswg.org/css-images-3/#typedef-size
|
/// https://drafts.csswg.org/css-images-3/#typedef-size
|
||||||
fn convert_ellipse_size_keyword(keyword: SizeKeyword,
|
fn convert_ellipse_size_keyword(keyword: ShapeExtent,
|
||||||
size: &Size2D<Au>,
|
size: &Size2D<Au>,
|
||||||
center: &Point2D<Au>) -> Size2D<Au> {
|
center: &Point2D<Au>) -> Size2D<Au> {
|
||||||
use style::values::computed::image::SizeKeyword::*;
|
|
||||||
match keyword {
|
match keyword {
|
||||||
ClosestSide | Contain => get_distance_to_sides(size, center, ::std::cmp::min),
|
ShapeExtent::ClosestSide | ShapeExtent::Contain => {
|
||||||
FarthestSide => get_distance_to_sides(size, center, ::std::cmp::max),
|
get_distance_to_sides(size, center, ::std::cmp::min)
|
||||||
ClosestCorner => get_ellipse_radius(size, center, ::std::cmp::min),
|
},
|
||||||
FarthestCorner | Cover => get_ellipse_radius(size, center, ::std::cmp::max),
|
ShapeExtent::FarthestSide => {
|
||||||
|
get_distance_to_sides(size, center, ::std::cmp::max)
|
||||||
|
},
|
||||||
|
ShapeExtent::ClosestCorner => {
|
||||||
|
get_ellipse_radius(size, center, ::std::cmp::min)
|
||||||
|
},
|
||||||
|
ShapeExtent::FarthestCorner | ShapeExtent::Cover => {
|
||||||
|
get_ellipse_radius(size, center, ::std::cmp::max)
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,9 +865,9 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
// http://www.w3.org/TR/CSS21/colors.html#background
|
// http://www.w3.org/TR/CSS21/colors.html#background
|
||||||
let background = style.get_background();
|
let background = style.get_background();
|
||||||
for (i, background_image) in background.background_image.0.iter().enumerate().rev() {
|
for (i, background_image) in background.background_image.0.iter().enumerate().rev() {
|
||||||
match background_image.0 {
|
match *background_image {
|
||||||
None => {}
|
Either::First(_) => {}
|
||||||
Some(computed::Image::Gradient(ref gradient)) => {
|
Either::Second(Image::Gradient(ref gradient)) => {
|
||||||
self.build_display_list_for_background_gradient(state,
|
self.build_display_list_for_background_gradient(state,
|
||||||
display_list_section,
|
display_list_section,
|
||||||
&absolute_bounds,
|
&absolute_bounds,
|
||||||
|
@ -864,7 +876,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
gradient,
|
gradient,
|
||||||
style);
|
style);
|
||||||
}
|
}
|
||||||
Some(computed::Image::Url(ref image_url)) => {
|
Either::Second(Image::Url(ref image_url)) => {
|
||||||
if let Some(url) = image_url.url() {
|
if let Some(url) = image_url.url() {
|
||||||
self.build_display_list_for_background_image(state,
|
self.build_display_list_for_background_image(state,
|
||||||
style,
|
style,
|
||||||
|
@ -875,10 +887,10 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
i);
|
i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(computed::Image::ImageRect(_)) => {
|
Either::Second(Image::Rect(_)) => {
|
||||||
// TODO: Implement `-moz-image-rect`
|
// TODO: Implement `-moz-image-rect`
|
||||||
}
|
}
|
||||||
Some(computed::Image::Element(_)) => {
|
Either::Second(Image::Element(_)) => {
|
||||||
// TODO: Implement `-moz-element`
|
// TODO: Implement `-moz-element`
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1097,26 +1109,26 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
fn convert_linear_gradient(&self,
|
fn convert_linear_gradient(&self,
|
||||||
bounds: &Rect<Au>,
|
bounds: &Rect<Au>,
|
||||||
stops: &[GradientItem],
|
stops: &[GradientItem],
|
||||||
angle_or_corner: &AngleOrCorner,
|
direction: &LineDirection,
|
||||||
repeating: bool,
|
repeating: bool,
|
||||||
style: &ServoComputedValues)
|
style: &ServoComputedValues)
|
||||||
-> display_list::Gradient {
|
-> display_list::Gradient {
|
||||||
let angle = match *angle_or_corner {
|
let angle = match *direction {
|
||||||
AngleOrCorner::Angle(angle) => angle.radians(),
|
LineDirection::Angle(angle) => angle.radians(),
|
||||||
AngleOrCorner::Corner(horizontal, vertical) => {
|
LineDirection::Corner(horizontal, vertical) => {
|
||||||
// This the angle for one of the diagonals of the box. Our angle
|
// This the angle for one of the diagonals of the box. Our angle
|
||||||
// will either be this one, this one + PI, or one of the other
|
// will either be this one, this one + PI, or one of the other
|
||||||
// two perpendicular angles.
|
// two perpendicular angles.
|
||||||
let atan = (bounds.size.height.to_f32_px() /
|
let atan = (bounds.size.height.to_f32_px() /
|
||||||
bounds.size.width.to_f32_px()).atan();
|
bounds.size.width.to_f32_px()).atan();
|
||||||
match (horizontal, vertical) {
|
match (horizontal, vertical) {
|
||||||
(HorizontalDirection::Right, VerticalDirection::Bottom)
|
(X::Right, Y::Bottom)
|
||||||
=> f32::consts::PI - atan,
|
=> f32::consts::PI - atan,
|
||||||
(HorizontalDirection::Left, VerticalDirection::Bottom)
|
(X::Left, Y::Bottom)
|
||||||
=> f32::consts::PI + atan,
|
=> f32::consts::PI + atan,
|
||||||
(HorizontalDirection::Right, VerticalDirection::Top)
|
(X::Right, Y::Top)
|
||||||
=> atan,
|
=> atan,
|
||||||
(HorizontalDirection::Left, VerticalDirection::Top)
|
(X::Left, Y::Top)
|
||||||
=> -atan,
|
=> -atan,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1170,16 +1182,18 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
let center = Point2D::new(specified(center.horizontal, bounds.size.width),
|
let center = Point2D::new(specified(center.horizontal, bounds.size.width),
|
||||||
specified(center.vertical, bounds.size.height));
|
specified(center.vertical, bounds.size.height));
|
||||||
let radius = match *shape {
|
let radius = match *shape {
|
||||||
EndingShape::Circle(LengthOrKeyword::Length(length))
|
GenericEndingShape::Circle(Circle::Radius(length)) => {
|
||||||
=> Size2D::new(length, length),
|
Size2D::new(length, length)
|
||||||
EndingShape::Circle(LengthOrKeyword::Keyword(word))
|
},
|
||||||
=> convert_circle_size_keyword(word, &bounds.size, ¢er),
|
GenericEndingShape::Circle(Circle::Extent(extent)) => {
|
||||||
EndingShape::Ellipse(LengthOrPercentageOrKeyword::LengthOrPercentage(horizontal,
|
convert_circle_size_keyword(extent, &bounds.size, ¢er)
|
||||||
vertical))
|
},
|
||||||
=> Size2D::new(specified(horizontal, bounds.size.width),
|
GenericEndingShape::Ellipse(Ellipse::Radii(x, y)) => {
|
||||||
specified(vertical, bounds.size.height)),
|
Size2D::new(specified(x, bounds.size.width), specified(y, bounds.size.height))
|
||||||
EndingShape::Ellipse(LengthOrPercentageOrKeyword::Keyword(word))
|
},
|
||||||
=> convert_ellipse_size_keyword(word, &bounds.size, ¢er),
|
GenericEndingShape::Ellipse(Ellipse::Extent(extent)) => {
|
||||||
|
convert_ellipse_size_keyword(extent, &bounds.size, ¢er)
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut stops = convert_gradient_stops(stops, radius.width, style);
|
let mut stops = convert_gradient_stops(stops, radius.width, style);
|
||||||
|
@ -1221,7 +1235,7 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
style.get_cursor(Cursor::Default),
|
style.get_cursor(Cursor::Default),
|
||||||
display_list_section);
|
display_list_section);
|
||||||
|
|
||||||
let display_item = match gradient.gradient_kind {
|
let display_item = match gradient.kind {
|
||||||
GradientKind::Linear(ref angle_or_corner) => {
|
GradientKind::Linear(ref angle_or_corner) => {
|
||||||
let gradient = self.convert_linear_gradient(&bounds,
|
let gradient = self.convert_linear_gradient(&bounds,
|
||||||
&gradient.items[..],
|
&gradient.items[..],
|
||||||
|
@ -1342,8 +1356,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
style.get_cursor(Cursor::Default),
|
style.get_cursor(Cursor::Default),
|
||||||
display_list_section);
|
display_list_section);
|
||||||
|
|
||||||
match border_style_struct.border_image_source.0 {
|
match border_style_struct.border_image_source {
|
||||||
None => {
|
Either::First(_) => {
|
||||||
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
state.add_display_item(DisplayItem::Border(box BorderDisplayItem {
|
||||||
base: base,
|
base: base,
|
||||||
border_widths: border.to_physical(style.writing_mode),
|
border_widths: border.to_physical(style.writing_mode),
|
||||||
|
@ -1357,8 +1371,8 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}),
|
}),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
Some(computed::Image::Gradient(ref gradient)) => {
|
Either::Second(Image::Gradient(ref gradient)) => {
|
||||||
match gradient.gradient_kind {
|
match gradient.kind {
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
GradientKind::Linear(angle_or_corner) => {
|
||||||
let grad = self.convert_linear_gradient(&bounds,
|
let grad = self.convert_linear_gradient(&bounds,
|
||||||
&gradient.items[..],
|
&gradient.items[..],
|
||||||
|
@ -1398,13 +1412,13 @@ impl FragmentDisplayListBuilding for Fragment {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Some(computed::Image::ImageRect(..)) => {
|
Either::Second(Image::Rect(..)) => {
|
||||||
// TODO: Handle border-image with `-moz-image-rect`.
|
// TODO: Handle border-image with `-moz-image-rect`.
|
||||||
}
|
}
|
||||||
Some(computed::Image::Element(..)) => {
|
Either::Second(Image::Element(..)) => {
|
||||||
// TODO: Handle border-image with `-moz-element`.
|
// TODO: Handle border-image with `-moz-element`.
|
||||||
}
|
}
|
||||||
Some(computed::Image::Url(ref image_url)) => {
|
Either::Second(Image::Url(ref image_url)) => {
|
||||||
if let Some(url) = image_url.url() {
|
if let Some(url) = image_url.url() {
|
||||||
let webrender_image = state.layout_context
|
let webrender_image = state.layout_context
|
||||||
.get_webrender_image_for_url(self.node,
|
.get_webrender_image_for_url(self.node,
|
||||||
|
|
|
@ -109,7 +109,7 @@ use style::sink::Push;
|
||||||
use style::stylearc::Arc;
|
use style::stylearc::Arc;
|
||||||
use style::stylist::ApplicableDeclarationBlock;
|
use style::stylist::ApplicableDeclarationBlock;
|
||||||
use style::thread_state;
|
use style::thread_state;
|
||||||
use style::values::CSSFloat;
|
use style::values::{CSSFloat, Either};
|
||||||
use style::values::specified::{self, CSSColor};
|
use style::values::specified::{self, CSSColor};
|
||||||
use stylesheet_loader::StylesheetOwner;
|
use stylesheet_loader::StylesheetOwner;
|
||||||
|
|
||||||
|
@ -427,9 +427,7 @@ impl LayoutElementHelpers for LayoutJS<Element> {
|
||||||
shared_lock,
|
shared_lock,
|
||||||
PropertyDeclaration::BackgroundImage(
|
PropertyDeclaration::BackgroundImage(
|
||||||
background_image::SpecifiedValue(vec![
|
background_image::SpecifiedValue(vec![
|
||||||
background_image::single_value::SpecifiedValue(Some(
|
Either::Second(specified::Image::for_cascade(url.into()))
|
||||||
specified::Image::for_cascade(url.into())
|
|
||||||
))
|
|
||||||
]))));
|
]))));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,8 +16,9 @@ use gecko_bindings::structs::{nsCSSUnit, nsStyleCoord_CalcValue, nsStyleImage};
|
||||||
use gecko_bindings::structs::{nsresult, SheetType};
|
use gecko_bindings::structs::{nsresult, SheetType};
|
||||||
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
|
use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut};
|
||||||
use stylesheets::{Origin, RulesMutateError};
|
use stylesheets::{Origin, RulesMutateError};
|
||||||
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, GradientItem, Image};
|
use values::computed::{Angle, CalcLengthOrPercentage, Gradient, Image};
|
||||||
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
use values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
|
use values::generics::image::{CompatMode, Image as GenericImage, GradientItem};
|
||||||
|
|
||||||
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
|
impl From<CalcLengthOrPercentage> for nsStyleCoord_CalcValue {
|
||||||
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
|
fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue {
|
||||||
|
@ -138,10 +139,10 @@ 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, cacheable: &mut bool) {
|
pub fn set(&mut self, image: Image, cacheable: &mut bool) {
|
||||||
match image {
|
match image {
|
||||||
Image::Gradient(gradient) => {
|
GenericImage::Gradient(gradient) => {
|
||||||
self.set_gradient(gradient)
|
self.set_gradient(gradient)
|
||||||
},
|
},
|
||||||
Image::Url(ref url) => {
|
GenericImage::Url(ref url) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_SetUrlImageValue(self, url.for_ffi());
|
Gecko_SetUrlImageValue(self, url.for_ffi());
|
||||||
// We unfortunately must make any url() value uncacheable, since
|
// We unfortunately must make any url() value uncacheable, since
|
||||||
|
@ -154,7 +155,7 @@ impl nsStyleImage {
|
||||||
*cacheable = false;
|
*cacheable = false;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Image::ImageRect(ref image_rect) => {
|
GenericImage::Rect(ref image_rect) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_SetUrlImageValue(self, image_rect.url.for_ffi());
|
Gecko_SetUrlImageValue(self, image_rect.url.for_ffi());
|
||||||
Gecko_InitializeImageCropRect(self);
|
Gecko_InitializeImageCropRect(self);
|
||||||
|
@ -176,7 +177,7 @@ impl nsStyleImage {
|
||||||
image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3));
|
image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Image::Element(ref element) => {
|
GenericImage::Element(ref element) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
Gecko_SetImageElement(self, element.as_ptr());
|
Gecko_SetImageElement(self, element.as_ptr());
|
||||||
}
|
}
|
||||||
|
@ -191,9 +192,9 @@ impl nsStyleImage {
|
||||||
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
|
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE, NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE};
|
||||||
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
|
use gecko_bindings::structs::{NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER, NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE};
|
||||||
use gecko_bindings::structs::nsStyleCoord;
|
use gecko_bindings::structs::nsStyleCoord;
|
||||||
use values::computed::{AngleOrCorner, GradientKind, GradientShape, LengthOrKeyword};
|
use values::computed::image::LineDirection;
|
||||||
use values::computed::LengthOrPercentageOrKeyword;
|
use values::generics::image::{Circle, Ellipse, EndingShape, GradientKind, ShapeExtent};
|
||||||
use values::specified::{HorizontalDirection, SizeKeyword, VerticalDirection};
|
use values::specified::position::{X, Y};
|
||||||
|
|
||||||
let stop_count = gradient.items.len();
|
let stop_count = gradient.items.len();
|
||||||
if stop_count >= ::std::u32::MAX as usize {
|
if stop_count >= ::std::u32::MAX as usize {
|
||||||
|
@ -201,32 +202,32 @@ impl nsStyleImage {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let gecko_gradient = match gradient.gradient_kind {
|
let gecko_gradient = match gradient.kind {
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
GradientKind::Linear(direction) => {
|
||||||
let gecko_gradient = unsafe {
|
let gecko_gradient = unsafe {
|
||||||
Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
|
Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8,
|
||||||
NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
|
NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8,
|
||||||
gradient.repeating,
|
gradient.repeating,
|
||||||
/* legacy_syntax = */ false,
|
gradient.compat_mode == CompatMode::WebKit,
|
||||||
stop_count as u32)
|
stop_count as u32)
|
||||||
};
|
};
|
||||||
|
|
||||||
match angle_or_corner {
|
match direction {
|
||||||
AngleOrCorner::Angle(angle) => {
|
LineDirection::Angle(angle) => {
|
||||||
unsafe {
|
unsafe {
|
||||||
(*gecko_gradient).mAngle.set(angle);
|
(*gecko_gradient).mAngle.set(angle);
|
||||||
(*gecko_gradient).mBgPosX.set_value(CoordDataValue::None);
|
(*gecko_gradient).mBgPosX.set_value(CoordDataValue::None);
|
||||||
(*gecko_gradient).mBgPosY.set_value(CoordDataValue::None);
|
(*gecko_gradient).mBgPosY.set_value(CoordDataValue::None);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
AngleOrCorner::Corner(horiz, vert) => {
|
LineDirection::Corner(horiz, vert) => {
|
||||||
let percent_x = match horiz {
|
let percent_x = match horiz {
|
||||||
HorizontalDirection::Left => 0.0,
|
X::Left => 0.0,
|
||||||
HorizontalDirection::Right => 1.0,
|
X::Right => 1.0,
|
||||||
};
|
};
|
||||||
let percent_y = match vert {
|
let percent_y = match vert {
|
||||||
VerticalDirection::Top => 0.0,
|
Y::Top => 0.0,
|
||||||
VerticalDirection::Bottom => 1.0,
|
Y::Bottom => 1.0,
|
||||||
};
|
};
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -243,28 +244,28 @@ impl nsStyleImage {
|
||||||
GradientKind::Radial(shape, position) => {
|
GradientKind::Radial(shape, position) => {
|
||||||
let keyword_to_gecko_size = |keyword| {
|
let keyword_to_gecko_size = |keyword| {
|
||||||
match keyword {
|
match keyword {
|
||||||
SizeKeyword::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
|
ShapeExtent::ClosestSide => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
|
||||||
SizeKeyword::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE,
|
ShapeExtent::FarthestSide => NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE,
|
||||||
SizeKeyword::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER,
|
ShapeExtent::ClosestCorner => NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER,
|
||||||
SizeKeyword::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
|
ShapeExtent::FarthestCorner => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
|
||||||
SizeKeyword::Contain => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
|
ShapeExtent::Contain => NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE,
|
||||||
SizeKeyword::Cover => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
|
ShapeExtent::Cover => NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let (gecko_shape, gecko_size) = match shape {
|
let (gecko_shape, gecko_size) = match shape {
|
||||||
GradientShape::Circle(ref length) => {
|
EndingShape::Circle(ref circle) => {
|
||||||
let size = match *length {
|
let size = match *circle {
|
||||||
LengthOrKeyword::Keyword(keyword) => {
|
Circle::Extent(extent) => {
|
||||||
keyword_to_gecko_size(keyword)
|
keyword_to_gecko_size(extent)
|
||||||
},
|
},
|
||||||
_ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
|
_ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
|
||||||
};
|
};
|
||||||
(NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8)
|
(NS_STYLE_GRADIENT_SHAPE_CIRCULAR as u8, size as u8)
|
||||||
},
|
},
|
||||||
GradientShape::Ellipse(ref length) => {
|
EndingShape::Ellipse(ref ellipse) => {
|
||||||
let size = match *length {
|
let size = match *ellipse {
|
||||||
LengthOrPercentageOrKeyword::Keyword(keyword) => {
|
Ellipse::Extent(extent) => {
|
||||||
keyword_to_gecko_size(keyword)
|
keyword_to_gecko_size(extent)
|
||||||
},
|
},
|
||||||
_ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
|
_ => NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE,
|
||||||
};
|
};
|
||||||
|
@ -276,7 +277,7 @@ impl nsStyleImage {
|
||||||
Gecko_CreateGradient(gecko_shape,
|
Gecko_CreateGradient(gecko_shape,
|
||||||
gecko_size,
|
gecko_size,
|
||||||
gradient.repeating,
|
gradient.repeating,
|
||||||
/* legacy_syntax = */ false,
|
gradient.compat_mode == CompatMode::WebKit,
|
||||||
stop_count as u32)
|
stop_count as u32)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -289,22 +290,19 @@ impl nsStyleImage {
|
||||||
|
|
||||||
// Setting radius values depending shape
|
// Setting radius values depending shape
|
||||||
match shape {
|
match shape {
|
||||||
GradientShape::Circle(length) => {
|
EndingShape::Circle(Circle::Radius(length)) => {
|
||||||
if let LengthOrKeyword::Length(len) = length {
|
unsafe {
|
||||||
unsafe {
|
(*gecko_gradient).mRadiusX.set_value(CoordDataValue::Coord(length.0));
|
||||||
(*gecko_gradient).mRadiusX.set_value(CoordDataValue::Coord(len.0));
|
(*gecko_gradient).mRadiusY.set_value(CoordDataValue::Coord(length.0));
|
||||||
(*gecko_gradient).mRadiusY.set_value(CoordDataValue::Coord(len.0));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
GradientShape::Ellipse(length) => {
|
EndingShape::Ellipse(Ellipse::Radii(x, y)) => {
|
||||||
if let LengthOrPercentageOrKeyword::LengthOrPercentage(first_len, second_len) = length {
|
unsafe {
|
||||||
unsafe {
|
(*gecko_gradient).mRadiusX.set(x);
|
||||||
(*gecko_gradient).mRadiusX.set(first_len);
|
(*gecko_gradient).mRadiusY.set(y);
|
||||||
(*gecko_gradient).mRadiusY.set(second_len);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
_ => {},
|
||||||
}
|
}
|
||||||
unsafe {
|
unsafe {
|
||||||
(*gecko_gradient).mBgPosX.set(position.horizontal);
|
(*gecko_gradient).mBgPosX.set(position.horizontal);
|
||||||
|
|
|
@ -927,7 +927,7 @@ fn static_assert() {
|
||||||
Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
|
Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(image) = image.0 {
|
if let Either::Second(image) = image {
|
||||||
self.gecko.mBorderImageSource.set(image, &mut false)
|
self.gecko.mBorderImageSource.set(image, &mut false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2879,7 +2879,7 @@ 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 Some(image) = image.0 {
|
if let Either::Second(image) = image {
|
||||||
geckoimage.mImage.set(image, cacheable)
|
geckoimage.mImage.set(image, cacheable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,9 +12,9 @@ ${helpers.predefined_type("background-color", "CSSColor",
|
||||||
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
|
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
|
||||||
animation_value_type="IntermediateColor", complex_color=True)}
|
animation_value_type="IntermediateColor", complex_color=True)}
|
||||||
|
|
||||||
${helpers.predefined_type("background-image", "LayerImage",
|
${helpers.predefined_type("background-image", "ImageLayer",
|
||||||
initial_value="computed_value::T(None)",
|
initial_value="Either::First(None_)",
|
||||||
initial_specified_value="SpecifiedValue(None)",
|
initial_specified_value="Either::First(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="none",
|
animation_value_type="none",
|
||||||
|
|
|
@ -190,9 +190,9 @@ ${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
|
||||||
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
|
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
|
||||||
animation_value_type="none")}
|
animation_value_type="none")}
|
||||||
|
|
||||||
${helpers.predefined_type("border-image-source", "LayerImage",
|
${helpers.predefined_type("border-image-source", "ImageLayer",
|
||||||
initial_value="computed_value::T(None)",
|
initial_value="Either::First(None_)",
|
||||||
initial_specified_value="SpecifiedValue(None)",
|
initial_specified_value="Either::First(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="none",
|
animation_value_type="none",
|
||||||
|
@ -717,7 +717,7 @@ ${helpers.predefined_type("border-image-source", "LayerImage",
|
||||||
|
|
||||||
let mut values = vec![];
|
let mut values = vec![];
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
let value = input.try(|input| NumberOrPercentage::parse(context, input));
|
let value = input.try(|input| NumberOrPercentage::parse_non_negative(context, input));
|
||||||
match value {
|
match value {
|
||||||
Ok(val) => values.push(val),
|
Ok(val) => values.push(val),
|
||||||
Err(_) => break,
|
Err(_) => break,
|
||||||
|
|
|
@ -141,9 +141,10 @@ ${helpers.single_keyword("mask-composite",
|
||||||
extra_prefixes="webkit",
|
extra_prefixes="webkit",
|
||||||
animation_value_type="none",
|
animation_value_type="none",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}
|
||||||
${helpers.predefined_type("mask-image", "LayerImage",
|
|
||||||
initial_value="computed_value::T(None)",
|
${helpers.predefined_type("mask-image", "ImageLayer",
|
||||||
initial_specified_value="SpecifiedValue(None)",
|
initial_value="Either::First(None_)",
|
||||||
|
initial_specified_value="Either::First(None_)",
|
||||||
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
|
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
|
||||||
vector=True,
|
vector=True,
|
||||||
products="gecko",
|
products="gecko",
|
||||||
|
|
|
@ -7,687 +7,126 @@
|
||||||
//!
|
//!
|
||||||
//! [image]: https://drafts.csswg.org/css-images/#image-values
|
//! [image]: https://drafts.csswg.org/css-images/#image-values
|
||||||
|
|
||||||
use Atom;
|
use cssparser::Color as CSSColor;
|
||||||
use cssparser::{Color as CSSColor, serialize_identifier};
|
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
use values::{Either, None_};
|
||||||
use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
|
use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue};
|
||||||
use values::computed::position::Position;
|
use values::computed::position::Position;
|
||||||
use values::specified::{self, HorizontalDirection, VerticalDirection};
|
use values::generics::image::{CompatMode, ColorStop as GenericColorStop, EndingShape as GenericEndingShape};
|
||||||
use values::specified::image::CompatMode;
|
use values::generics::image::{Gradient as GenericGradient, GradientItem as GenericGradientItem};
|
||||||
use values::specified::url::SpecifiedUrl;
|
use values::generics::image::{Image as GenericImage, GradientKind as GenericGradientKind};
|
||||||
|
use values::generics::image::{ImageRect as GenericImageRect, LineDirection as GenericLineDirection};
|
||||||
|
use values::specified::image::LineDirection as SpecifiedLineDirection;
|
||||||
|
use values::specified::position::{X, Y};
|
||||||
|
|
||||||
pub use values::specified::SizeKeyword;
|
/// A computed image layer.
|
||||||
|
pub type ImageLayer = Either<None_, Image>;
|
||||||
impl ToComputedValue for specified::Image {
|
|
||||||
type ComputedValue = Image;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> Image {
|
|
||||||
match *self {
|
|
||||||
specified::Image::Url(ref url_value) => {
|
|
||||||
Image::Url(url_value.clone())
|
|
||||||
},
|
|
||||||
specified::Image::Gradient(ref gradient) => {
|
|
||||||
Image::Gradient(gradient.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::Image::ImageRect(ref image_rect) => {
|
|
||||||
Image::ImageRect(image_rect.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::Image::Element(ref selector) => {
|
|
||||||
Image::Element(selector.clone())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &Image) -> Self {
|
|
||||||
match *computed {
|
|
||||||
Image::Url(ref url_value) => {
|
|
||||||
specified::Image::Url(url_value.clone())
|
|
||||||
},
|
|
||||||
Image::Gradient(ref linear_gradient) => {
|
|
||||||
specified::Image::Gradient(
|
|
||||||
ToComputedValue::from_computed_value(linear_gradient)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Image::ImageRect(ref image_rect) => {
|
|
||||||
specified::Image::ImageRect(
|
|
||||||
ToComputedValue::from_computed_value(image_rect)
|
|
||||||
)
|
|
||||||
},
|
|
||||||
Image::Element(ref selector) => {
|
|
||||||
specified::Image::Element(selector.clone())
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
||||||
#[derive(Clone, PartialEq)]
|
pub type Image = GenericImage<Gradient, ImageRect>;
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum Image {
|
|
||||||
Url(SpecifiedUrl),
|
|
||||||
Gradient(Gradient),
|
|
||||||
ImageRect(ImageRect),
|
|
||||||
Element(Atom),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Image {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
Image::Url(ref url) => url.to_css(f),
|
|
||||||
Image::Gradient(ref grad) => {
|
|
||||||
if grad.repeating {
|
|
||||||
let _ = write!(f, "repeating-");
|
|
||||||
}
|
|
||||||
match grad.gradient_kind {
|
|
||||||
GradientKind::Linear(_) => write!(f, "linear-gradient({:?})", grad),
|
|
||||||
GradientKind::Radial(_, _) => write!(f, "radial-gradient({:?})", grad),
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Image::ImageRect(ref image_rect) => write!(f, "{:?}", image_rect),
|
|
||||||
Image::Element(ref selector) => {
|
|
||||||
f.write_str("-moz-element(#")?;
|
|
||||||
serialize_identifier(&*selector.to_string(), f)?;
|
|
||||||
f.write_str(")")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for Image {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
Image::Url(ref url) => url.to_css(dest),
|
|
||||||
Image::Gradient(ref gradient) => gradient.to_css(dest),
|
|
||||||
Image::ImageRect(ref image_rect) => image_rect.to_css(dest),
|
|
||||||
Image::Element(ref selector) => {
|
|
||||||
dest.write_str("-moz-element(#")?;
|
|
||||||
// FIXME: We should get rid of these intermediate strings.
|
|
||||||
serialize_identifier(&*selector.to_string(), dest)?;
|
|
||||||
dest.write_str(")")
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
||||||
#[derive(Clone, PartialEq)]
|
pub type Gradient = GenericGradient<
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
LineDirection,
|
||||||
pub struct Gradient {
|
Length,
|
||||||
/// The color stops.
|
LengthOrPercentage,
|
||||||
pub items: Vec<GradientItem>,
|
Position,
|
||||||
/// True if this is a repeating gradient.
|
CSSColor,
|
||||||
pub repeating: bool,
|
>;
|
||||||
/// Gradient kind can be linear or radial.
|
|
||||||
pub gradient_kind: GradientKind,
|
|
||||||
/// Compatibility mode.
|
|
||||||
pub compat_mode: CompatMode,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for Gradient {
|
/// A computed gradient kind.
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
pub type GradientKind = GenericGradientKind<
|
||||||
if self.compat_mode == CompatMode::WebKit {
|
LineDirection,
|
||||||
try!(dest.write_str("-webkit-"));
|
Length,
|
||||||
}
|
LengthOrPercentage,
|
||||||
if self.repeating {
|
Position,
|
||||||
try!(dest.write_str("repeating-"));
|
>;
|
||||||
}
|
|
||||||
match self.gradient_kind {
|
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
|
||||||
try!(dest.write_str("linear-gradient("));
|
|
||||||
try!(angle_or_corner.to_css(dest, self.compat_mode));
|
|
||||||
},
|
|
||||||
GradientKind::Radial(ref shape, position) => {
|
|
||||||
try!(dest.write_str("radial-gradient("));
|
|
||||||
try!(shape.to_css(dest));
|
|
||||||
try!(dest.write_str(" at "));
|
|
||||||
try!(position.to_css(dest));
|
|
||||||
},
|
|
||||||
}
|
|
||||||
for item in &self.items {
|
|
||||||
try!(dest.write_str(", "));
|
|
||||||
try!(item.to_css(dest));
|
|
||||||
}
|
|
||||||
try!(dest.write_str(")"));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for Gradient {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match self.gradient_kind {
|
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
|
||||||
let _ = write!(f, "{:?}", angle_or_corner);
|
|
||||||
},
|
|
||||||
GradientKind::Radial(ref shape, position) => {
|
|
||||||
let _ = write!(f, "{:?} at {:?}", shape, position);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
for item in &self.items {
|
|
||||||
let _ = write!(f, ", {:?}", item);
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::Gradient {
|
|
||||||
type ComputedValue = Gradient;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> Gradient {
|
|
||||||
let specified::Gradient {
|
|
||||||
ref items,
|
|
||||||
repeating,
|
|
||||||
ref gradient_kind,
|
|
||||||
compat_mode,
|
|
||||||
} = *self;
|
|
||||||
Gradient {
|
|
||||||
items: items.iter().map(|s| s.to_computed_value(context)).collect(),
|
|
||||||
repeating: repeating,
|
|
||||||
gradient_kind: gradient_kind.to_computed_value(context),
|
|
||||||
compat_mode: compat_mode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &Gradient) -> Self {
|
|
||||||
let Gradient {
|
|
||||||
ref items,
|
|
||||||
repeating,
|
|
||||||
ref gradient_kind,
|
|
||||||
compat_mode,
|
|
||||||
} = *computed;
|
|
||||||
specified::Gradient {
|
|
||||||
items: items.iter().map(ToComputedValue::from_computed_value).collect(),
|
|
||||||
repeating: repeating,
|
|
||||||
gradient_kind: ToComputedValue::from_computed_value(gradient_kind),
|
|
||||||
compat_mode: compat_mode,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computed values for CSS linear or radial gradients.
|
|
||||||
/// https://drafts.csswg.org/css-images/#gradients
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum GradientKind {
|
|
||||||
Linear(AngleOrCorner),
|
|
||||||
Radial(EndingShape, Position),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::GradientKind {
|
|
||||||
type ComputedValue = GradientKind;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> GradientKind {
|
|
||||||
match *self {
|
|
||||||
specified::GradientKind::Linear(angle_or_corner) => {
|
|
||||||
GradientKind::Linear(angle_or_corner.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::GradientKind::Radial(ref shape, ref position) => {
|
|
||||||
GradientKind::Radial(shape.to_computed_value(context),
|
|
||||||
position.to_computed_value(context))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &GradientKind) -> Self {
|
|
||||||
match *computed {
|
|
||||||
GradientKind::Linear(angle_or_corner) => {
|
|
||||||
specified::GradientKind::Linear(ToComputedValue::from_computed_value(&angle_or_corner))
|
|
||||||
},
|
|
||||||
GradientKind::Radial(ref shape, position) => {
|
|
||||||
specified::GradientKind::Radial(ToComputedValue::from_computed_value(shape),
|
|
||||||
ToComputedValue::from_computed_value(&position))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Specified values for color stops and interpolation hints.
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub enum GradientItem {
|
|
||||||
/// A color stop.
|
|
||||||
ColorStop(ColorStop),
|
|
||||||
/// An interpolation hint.
|
|
||||||
InterpolationHint(LengthOrPercentage),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for GradientItem {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
GradientItem::ColorStop(stop) => stop.to_css(dest),
|
|
||||||
GradientItem::InterpolationHint(hint) => hint.to_css(dest),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::GradientItem {
|
|
||||||
type ComputedValue = GradientItem;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> GradientItem {
|
|
||||||
match *self {
|
|
||||||
specified::GradientItem::ColorStop(ref stop) => {
|
|
||||||
GradientItem::ColorStop(stop.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::GradientItem::InterpolationHint(ref hint) => {
|
|
||||||
GradientItem::InterpolationHint(hint.to_computed_value(context))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &GradientItem) -> Self {
|
|
||||||
match *computed {
|
|
||||||
GradientItem::ColorStop(ref stop) => {
|
|
||||||
specified::GradientItem::ColorStop(ToComputedValue::from_computed_value(stop))
|
|
||||||
},
|
|
||||||
GradientItem::InterpolationHint(ref hint) => {
|
|
||||||
specified::GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computed values for one color stop in a linear gradient.
|
|
||||||
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
|
|
||||||
#[derive(Clone, PartialEq, Copy)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct ColorStop {
|
|
||||||
/// The color of this stop.
|
|
||||||
pub color: CSSColor,
|
|
||||||
|
|
||||||
/// The position of this stop. If not specified, this stop is placed halfway between the
|
|
||||||
/// point that precedes it and the point that follows it per CSS-IMAGES § 3.4.
|
|
||||||
pub position: Option<LengthOrPercentage>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for ColorStop {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
try!(self.color.to_css(dest));
|
|
||||||
if let Some(position) = self.position {
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(position.to_css(dest));
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for ColorStop {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
let _ = write!(f, "{:?}", self.color);
|
|
||||||
self.position.map(|pos| {
|
|
||||||
let _ = write!(f, " {:?}", pos);
|
|
||||||
});
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::ColorStop {
|
|
||||||
type ComputedValue = ColorStop;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> ColorStop {
|
|
||||||
ColorStop {
|
|
||||||
color: self.color.to_computed_value(context),
|
|
||||||
position: match self.position {
|
|
||||||
None => None,
|
|
||||||
Some(ref value) => Some(value.to_computed_value(context)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &ColorStop) -> Self {
|
|
||||||
specified::ColorStop {
|
|
||||||
color: ToComputedValue::from_computed_value(&computed.color),
|
|
||||||
position: match computed.position {
|
|
||||||
None => None,
|
|
||||||
Some(value) => Some(ToComputedValue::from_computed_value(&value)),
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computed values for EndingShape
|
|
||||||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-ending-shape
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum EndingShape {
|
|
||||||
Circle(LengthOrKeyword),
|
|
||||||
Ellipse(LengthOrPercentageOrKeyword),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for EndingShape {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
EndingShape::Circle(ref length) => {
|
|
||||||
try!(dest.write_str("circle "));
|
|
||||||
try!(length.to_css(dest));
|
|
||||||
},
|
|
||||||
EndingShape::Ellipse(ref length) => {
|
|
||||||
try!(dest.write_str("ellipse "));
|
|
||||||
try!(length.to_css(dest));
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for EndingShape {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
EndingShape::Circle(ref length) => {
|
|
||||||
let _ = write!(f, "circle {:?}", length);
|
|
||||||
},
|
|
||||||
EndingShape::Ellipse(ref length) => {
|
|
||||||
let _ = write!(f, "ellipse {:?}", length);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::GradientEndingShape {
|
|
||||||
type ComputedValue = EndingShape;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> EndingShape {
|
|
||||||
match *self {
|
|
||||||
specified::GradientEndingShape::Circle(ref length) => {
|
|
||||||
EndingShape::Circle(length.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::GradientEndingShape::Ellipse(ref length) => {
|
|
||||||
EndingShape::Ellipse(length.to_computed_value(context))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &EndingShape) -> Self {
|
|
||||||
match *computed {
|
|
||||||
EndingShape::Circle(ref length) => {
|
|
||||||
specified::GradientEndingShape::Circle(ToComputedValue::from_computed_value(length))
|
|
||||||
},
|
|
||||||
EndingShape::Ellipse(ref length) => {
|
|
||||||
specified::GradientEndingShape::Ellipse(ToComputedValue::from_computed_value(length))
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computed values for ImageRect
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub struct ImageRect {
|
|
||||||
pub url: SpecifiedUrl,
|
|
||||||
pub top: NumberOrPercentage,
|
|
||||||
pub bottom: NumberOrPercentage,
|
|
||||||
pub right: NumberOrPercentage,
|
|
||||||
pub left: NumberOrPercentage,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for ImageRect {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
dest.write_str("-moz-image-rect(")?;
|
|
||||||
self.url.to_css(dest)?;
|
|
||||||
dest.write_str(", ")?;
|
|
||||||
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)?;
|
|
||||||
dest.write_str(")")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::ImageRect {
|
|
||||||
type ComputedValue = ImageRect;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> ImageRect {
|
|
||||||
ImageRect {
|
|
||||||
url: self.url.to_computed_value(context),
|
|
||||||
top: self.top.to_computed_value(context),
|
|
||||||
right: self.right.to_computed_value(context),
|
|
||||||
bottom: self.bottom.to_computed_value(context),
|
|
||||||
left: self.left.to_computed_value(context),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &ImageRect) -> Self {
|
|
||||||
specified::ImageRect {
|
|
||||||
url: ToComputedValue::from_computed_value(&computed.url),
|
|
||||||
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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum LengthOrKeyword {
|
|
||||||
Length(Length),
|
|
||||||
Keyword(SizeKeyword),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for LengthOrKeyword {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
LengthOrKeyword::Length(ref length) => length.to_css(dest),
|
|
||||||
LengthOrKeyword::Keyword(keyword) => keyword.to_css(dest),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for LengthOrKeyword {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
LengthOrKeyword::Length(ref length) => {
|
|
||||||
let _ = write!(f, "{:?}", length);
|
|
||||||
},
|
|
||||||
LengthOrKeyword::Keyword(keyword) => {
|
|
||||||
let _ = write!(f, "{:?}", keyword);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::LengthOrKeyword {
|
|
||||||
type ComputedValue = LengthOrKeyword;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> LengthOrKeyword {
|
|
||||||
match *self {
|
|
||||||
specified::LengthOrKeyword::Length(ref length) => {
|
|
||||||
LengthOrKeyword::Length(length.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::LengthOrKeyword::Keyword(keyword) => {
|
|
||||||
LengthOrKeyword::Keyword(keyword)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &LengthOrKeyword) -> Self {
|
|
||||||
match *computed {
|
|
||||||
LengthOrKeyword::Length(length) => {
|
|
||||||
specified::LengthOrKeyword::Length(ToComputedValue::from_computed_value(&length))
|
|
||||||
},
|
|
||||||
LengthOrKeyword::Keyword(keyword) => {
|
|
||||||
specified::LengthOrKeyword::Keyword(keyword)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// https://drafts.csswg.org/css-images/#valdef-radial-gradient-size
|
|
||||||
#[derive(Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
#[allow(missing_docs)]
|
|
||||||
pub enum LengthOrPercentageOrKeyword {
|
|
||||||
LengthOrPercentage(LengthOrPercentage, LengthOrPercentage),
|
|
||||||
Keyword(SizeKeyword),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToCss for LengthOrPercentageOrKeyword {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, second_len) => {
|
|
||||||
try!(first_len.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
second_len.to_css(dest)
|
|
||||||
},
|
|
||||||
LengthOrPercentageOrKeyword::Keyword(keyword) => keyword.to_css(dest),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Debug for LengthOrPercentageOrKeyword {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
match *self {
|
|
||||||
LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, second_len) => {
|
|
||||||
let _ = write!(f, "{:?} {:?}", first_len, second_len);
|
|
||||||
},
|
|
||||||
LengthOrPercentageOrKeyword::Keyword(keyword) => {
|
|
||||||
let _ = write!(f, "{:?}", keyword);
|
|
||||||
},
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ToComputedValue for specified::LengthOrPercentageOrKeyword {
|
|
||||||
type ComputedValue = LengthOrPercentageOrKeyword;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn to_computed_value(&self, context: &Context) -> LengthOrPercentageOrKeyword {
|
|
||||||
match *self {
|
|
||||||
specified::LengthOrPercentageOrKeyword::LengthOrPercentage(ref first_len, ref second_len) => {
|
|
||||||
LengthOrPercentageOrKeyword::LengthOrPercentage(first_len.to_computed_value(context),
|
|
||||||
second_len.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::LengthOrPercentageOrKeyword::Keyword(keyword) => {
|
|
||||||
LengthOrPercentageOrKeyword::Keyword(keyword)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
fn from_computed_value(computed: &LengthOrPercentageOrKeyword) -> Self {
|
|
||||||
match *computed {
|
|
||||||
LengthOrPercentageOrKeyword::LengthOrPercentage(first_len, second_len) => {
|
|
||||||
specified::LengthOrPercentageOrKeyword::LengthOrPercentage(
|
|
||||||
ToComputedValue::from_computed_value(&first_len),
|
|
||||||
ToComputedValue::from_computed_value(&second_len))
|
|
||||||
},
|
|
||||||
LengthOrPercentageOrKeyword::Keyword(keyword) => {
|
|
||||||
specified::LengthOrPercentageOrKeyword::Keyword(keyword)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// A computed gradient line direction.
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
pub enum LineDirection {
|
||||||
pub enum AngleOrCorner {
|
/// An angle.
|
||||||
Angle(Angle),
|
Angle(Angle),
|
||||||
Corner(HorizontalDirection, VerticalDirection)
|
/// A corner.
|
||||||
|
Corner(X, Y),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToComputedValue for specified::AngleOrCorner {
|
/// A computed radial gradient ending shape.
|
||||||
type ComputedValue = AngleOrCorner;
|
pub type EndingShape = GenericEndingShape<Length, LengthOrPercentage>;
|
||||||
|
|
||||||
#[inline]
|
/// A computed gradient item.
|
||||||
fn to_computed_value(&self, context: &Context) -> AngleOrCorner {
|
pub type GradientItem = GenericGradientItem<CSSColor, LengthOrPercentage>;
|
||||||
|
|
||||||
|
/// A computed color stop.
|
||||||
|
pub type ColorStop = GenericColorStop<CSSColor, LengthOrPercentage>;
|
||||||
|
|
||||||
|
/// Computed values for ImageRect.
|
||||||
|
pub type ImageRect = GenericImageRect<NumberOrPercentage>;
|
||||||
|
|
||||||
|
impl GenericLineDirection for LineDirection {
|
||||||
|
fn points_downwards(&self) -> bool {
|
||||||
match *self {
|
match *self {
|
||||||
specified::AngleOrCorner::None => {
|
LineDirection::Angle(angle) => angle.radians() == PI,
|
||||||
AngleOrCorner::Angle(Angle::from_radians(PI))
|
LineDirection::Corner(..) => false,
|
||||||
},
|
|
||||||
specified::AngleOrCorner::Angle(angle) => {
|
|
||||||
AngleOrCorner::Angle(angle.to_computed_value(context))
|
|
||||||
},
|
|
||||||
specified::AngleOrCorner::Corner(horizontal, vertical) => {
|
|
||||||
match (horizontal, vertical) {
|
|
||||||
(None, Some(VerticalDirection::Top)) => {
|
|
||||||
AngleOrCorner::Angle(Angle::from_radians(0.0))
|
|
||||||
},
|
|
||||||
(Some(HorizontalDirection::Right), None) => {
|
|
||||||
AngleOrCorner::Angle(Angle::from_radians(PI * 0.5))
|
|
||||||
},
|
|
||||||
(None, Some(VerticalDirection::Bottom)) => {
|
|
||||||
AngleOrCorner::Angle(Angle::from_radians(PI))
|
|
||||||
},
|
|
||||||
(Some(HorizontalDirection::Left), None) => {
|
|
||||||
AngleOrCorner::Angle(Angle::from_radians(PI * 1.5))
|
|
||||||
},
|
|
||||||
(Some(horizontal), Some(vertical)) => {
|
|
||||||
AngleOrCorner::Corner(horizontal, vertical)
|
|
||||||
},
|
|
||||||
(None, None) => {
|
|
||||||
unreachable!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result
|
||||||
fn from_computed_value(computed: &AngleOrCorner) -> Self {
|
where W: fmt::Write
|
||||||
|
{
|
||||||
|
match *self {
|
||||||
|
LineDirection::Angle(ref angle) => angle.to_css(dest),
|
||||||
|
LineDirection::Corner(x, y) => {
|
||||||
|
if compat_mode == CompatMode::Modern {
|
||||||
|
dest.write_str("to ")?;
|
||||||
|
}
|
||||||
|
x.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
y.to_css(dest)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToComputedValue for SpecifiedLineDirection {
|
||||||
|
type ComputedValue = LineDirection;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
match *self {
|
||||||
|
SpecifiedLineDirection::Angle(ref angle) => {
|
||||||
|
LineDirection::Angle(angle.to_computed_value(context))
|
||||||
|
},
|
||||||
|
SpecifiedLineDirection::Horizontal(X::Left) => {
|
||||||
|
LineDirection::Angle(Angle::Degree(270.))
|
||||||
|
},
|
||||||
|
SpecifiedLineDirection::Horizontal(X::Right) => {
|
||||||
|
LineDirection::Angle(Angle::Degree(90.))
|
||||||
|
},
|
||||||
|
SpecifiedLineDirection::Vertical(Y::Top) => {
|
||||||
|
LineDirection::Angle(Angle::Degree(0.))
|
||||||
|
},
|
||||||
|
SpecifiedLineDirection::Vertical(Y::Bottom) => {
|
||||||
|
LineDirection::Angle(Angle::Degree(180.))
|
||||||
|
},
|
||||||
|
SpecifiedLineDirection::Corner(x, y) => {
|
||||||
|
LineDirection::Corner(x, y)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
match *computed {
|
match *computed {
|
||||||
AngleOrCorner::Angle(ref angle) => {
|
LineDirection::Angle(ref angle) => {
|
||||||
specified::AngleOrCorner::Angle(specified::Angle::from_computed_value(angle))
|
SpecifiedLineDirection::Angle(ToComputedValue::from_computed_value(angle))
|
||||||
|
},
|
||||||
|
LineDirection::Corner(x, y) => {
|
||||||
|
SpecifiedLineDirection::Corner(x, y)
|
||||||
},
|
},
|
||||||
AngleOrCorner::Corner(horizontal, vertical) => {
|
|
||||||
specified::AngleOrCorner::Corner(Some(horizontal), Some(vertical))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AngleOrCorner {
|
|
||||||
fn to_css<W>(&self, dest: &mut W, mode: CompatMode) -> fmt::Result where W: fmt::Write {
|
|
||||||
match *self {
|
|
||||||
AngleOrCorner::Angle(angle) => angle.to_css(dest),
|
|
||||||
AngleOrCorner::Corner(horizontal, vertical) => {
|
|
||||||
if mode == CompatMode::Modern {
|
|
||||||
try!(dest.write_str("to "));
|
|
||||||
}
|
|
||||||
try!(horizontal.to_css(dest));
|
|
||||||
try!(dest.write_str(" "));
|
|
||||||
try!(vertical.to_css(dest));
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Computed values for none | <image> | <mask-source>.
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
|
||||||
pub struct LayerImage(pub Option<Image>);
|
|
||||||
|
|
||||||
impl ToCss for LayerImage {
|
|
||||||
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
|
||||||
match self.0 {
|
|
||||||
None => dest.write_str("none"),
|
|
||||||
Some(ref image) => image.to_css(dest),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,8 +12,7 @@ use super::{Number, ToComputedValue, Context};
|
||||||
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
|
use values::{Auto, CSSFloat, Either, ExtremumLength, None_, Normal, specified};
|
||||||
use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
|
use values::specified::length::{AbsoluteLength, FontBaseSize, FontRelativeLength, ViewportPercentageLength};
|
||||||
|
|
||||||
pub use super::image::{EndingShape as GradientShape, Gradient, GradientKind, Image};
|
pub use super::image::Image;
|
||||||
pub use super::image::{LengthOrKeyword, LengthOrPercentageOrKeyword};
|
|
||||||
pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
|
pub use values::specified::{Angle, BorderStyle, Time, UrlOrNone};
|
||||||
|
|
||||||
impl ToComputedValue for specified::NoCalcLength {
|
impl ToComputedValue for specified::NoCalcLength {
|
||||||
|
|
|
@ -22,8 +22,7 @@ use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as G
|
||||||
|
|
||||||
pub use app_units::Au;
|
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, GradientItem, LayerImage};
|
pub use self::image::{Gradient, GradientItem, ImageLayer, LineDirection, Image, ImageRect};
|
||||||
pub use self::image::{GradientKind, Image, ImageRect, LengthOrKeyword, LengthOrPercentageOrKeyword};
|
|
||||||
pub use super::{Auto, Either, None_};
|
pub use super::{Auto, Either, None_};
|
||||||
#[cfg(feature = "gecko")]
|
#[cfg(feature = "gecko")]
|
||||||
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||||
|
|
636
components/style/values/generics/image.rs
Normal file
636
components/style/values/generics/image.rs
Normal file
|
@ -0,0 +1,636 @@
|
||||||
|
/* 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 the handling of [images].
|
||||||
|
//!
|
||||||
|
//! [images]: https://drafts.csswg.org/css-images/#image-values
|
||||||
|
|
||||||
|
use Atom;
|
||||||
|
use cssparser::serialize_identifier;
|
||||||
|
use std::fmt;
|
||||||
|
use style_traits::ToCss;
|
||||||
|
use values::HasViewportPercentage;
|
||||||
|
use values::computed::{Context, ToComputedValue};
|
||||||
|
use values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
|
/// An [image].
|
||||||
|
///
|
||||||
|
/// [image]: https://drafts.csswg.org/css-images/#image-values
|
||||||
|
#[derive(Clone, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum Image<Gradient, ImageRect> {
|
||||||
|
/// A `<url()>` image.
|
||||||
|
Url(SpecifiedUrl),
|
||||||
|
/// A `<gradient>` image.
|
||||||
|
Gradient(Gradient),
|
||||||
|
/// A `-moz-image-rect` image
|
||||||
|
Rect(ImageRect),
|
||||||
|
/// A `-moz-element(# <element-id>)`
|
||||||
|
Element(Atom),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A CSS gradient.
|
||||||
|
/// https://drafts.csswg.org/css-images/#gradients
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct Gradient<LineDirection, Length, LengthOrPercentage, Position, Color> {
|
||||||
|
/// Gradients can be linear or radial.
|
||||||
|
pub kind: GradientKind<LineDirection, Length, LengthOrPercentage, Position>,
|
||||||
|
/// The color stops and interpolation hints.
|
||||||
|
pub items: Vec<GradientItem<Color, LengthOrPercentage>>,
|
||||||
|
/// True if this is a repeating gradient.
|
||||||
|
pub repeating: bool,
|
||||||
|
/// Compatibility mode.
|
||||||
|
pub compat_mode: CompatMode,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
/// Whether we used the modern notation or the compatibility `-webkit` prefix.
|
||||||
|
pub enum CompatMode {
|
||||||
|
/// Modern syntax.
|
||||||
|
Modern,
|
||||||
|
/// `-webkit` prefix.
|
||||||
|
WebKit,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A gradient kind.
|
||||||
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum GradientKind<LineDirection, Length, LengthOrPercentage, Position> {
|
||||||
|
/// A linear gradient.
|
||||||
|
Linear(LineDirection),
|
||||||
|
/// A radial gradient.
|
||||||
|
Radial(EndingShape<Length, LengthOrPercentage>, Position),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A radial gradient's ending shape.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum EndingShape<Length, LengthOrPercentage> {
|
||||||
|
/// A circular gradient.
|
||||||
|
Circle(Circle<Length>),
|
||||||
|
/// An elliptic gradient.
|
||||||
|
Ellipse(Ellipse<LengthOrPercentage>),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A circle shape.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum Circle<Length> {
|
||||||
|
/// A circle radius.
|
||||||
|
Radius(Length),
|
||||||
|
/// A circle extent.
|
||||||
|
Extent(ShapeExtent),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// An ellipse shape.
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum Ellipse<LengthOrPercentage> {
|
||||||
|
/// An ellipse pair of radii.
|
||||||
|
Radii(LengthOrPercentage, LengthOrPercentage),
|
||||||
|
/// An ellipse extent.
|
||||||
|
Extent(ShapeExtent),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// https://drafts.csswg.org/css-images/#typedef-extent-keyword
|
||||||
|
define_css_keyword_enum!(ShapeExtent:
|
||||||
|
"closest-side" => ClosestSide,
|
||||||
|
"farthest-side" => FarthestSide,
|
||||||
|
"closest-corner" => ClosestCorner,
|
||||||
|
"farthest-corner" => FarthestCorner,
|
||||||
|
"contain" => Contain,
|
||||||
|
"cover" => Cover
|
||||||
|
);
|
||||||
|
|
||||||
|
/// A gradient item.
|
||||||
|
/// https://drafts.csswg.org/css-images-4/#color-stop-syntax
|
||||||
|
#[derive(Clone, Copy, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub enum GradientItem<Color, LengthOrPercentage> {
|
||||||
|
/// A color stop.
|
||||||
|
ColorStop(ColorStop<Color, LengthOrPercentage>),
|
||||||
|
/// An interpolation hint.
|
||||||
|
InterpolationHint(LengthOrPercentage),
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A color stop.
|
||||||
|
/// https://drafts.csswg.org/css-images/#typedef-color-stop-list
|
||||||
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
pub struct ColorStop<Color, LengthOrPercentage> {
|
||||||
|
/// The color of this stop.
|
||||||
|
pub color: Color,
|
||||||
|
/// The position of this stop.
|
||||||
|
pub position: Option<LengthOrPercentage>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Values for `moz-image-rect`.
|
||||||
|
///
|
||||||
|
/// `-moz-image-rect(<uri>, top, right, bottom, left);`
|
||||||
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
|
#[allow(missing_docs)]
|
||||||
|
pub struct ImageRect<NumberOrPercentage> {
|
||||||
|
pub url: SpecifiedUrl,
|
||||||
|
pub top: NumberOrPercentage,
|
||||||
|
pub bottom: NumberOrPercentage,
|
||||||
|
pub right: NumberOrPercentage,
|
||||||
|
pub left: NumberOrPercentage,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G, R> fmt::Debug for Image<G, R>
|
||||||
|
where G: fmt::Debug, R: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
Image::Url(ref url) => url.to_css(f),
|
||||||
|
Image::Gradient(ref grad) => grad.fmt(f),
|
||||||
|
Image::Rect(ref rect) => rect.fmt(f),
|
||||||
|
Image::Element(ref selector) => {
|
||||||
|
f.write_str("-moz-element(#")?;
|
||||||
|
serialize_identifier(&selector.to_string(), f)?;
|
||||||
|
f.write_str(")")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G, R> ToCss for Image<G, R>
|
||||||
|
where G: ToCss, R: ToCss,
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
Image::Url(ref url) => url.to_css(dest),
|
||||||
|
Image::Gradient(ref gradient) => gradient.to_css(dest),
|
||||||
|
Image::Rect(ref rect) => rect.to_css(dest),
|
||||||
|
Image::Element(ref selector) => {
|
||||||
|
dest.write_str("-moz-element(#")?;
|
||||||
|
serialize_identifier(&selector.to_string(), dest)?;
|
||||||
|
dest.write_str(")")
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G, R> HasViewportPercentage for Image<G, R>
|
||||||
|
where G: HasViewportPercentage
|
||||||
|
{
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
Image::Gradient(ref gradient) => gradient.has_viewport_percentage(),
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G, R> ToComputedValue for Image<G, R>
|
||||||
|
where G: ToComputedValue, R: ToComputedValue,
|
||||||
|
{
|
||||||
|
type ComputedValue = Image<<G as ToComputedValue>::ComputedValue,
|
||||||
|
<R as ToComputedValue>::ComputedValue>;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
match *self {
|
||||||
|
Image::Url(ref url) => {
|
||||||
|
Image::Url(url.clone())
|
||||||
|
},
|
||||||
|
Image::Gradient(ref gradient) => {
|
||||||
|
Image::Gradient(gradient.to_computed_value(context))
|
||||||
|
},
|
||||||
|
Image::Rect(ref rect) => {
|
||||||
|
Image::Rect(rect.to_computed_value(context))
|
||||||
|
},
|
||||||
|
Image::Element(ref selector) => {
|
||||||
|
Image::Element(selector.clone())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
match *computed {
|
||||||
|
Image::Url(ref url) => {
|
||||||
|
Image::Url(url.clone())
|
||||||
|
},
|
||||||
|
Image::Gradient(ref gradient) => {
|
||||||
|
Image::Gradient(ToComputedValue::from_computed_value(gradient))
|
||||||
|
},
|
||||||
|
Image::Rect(ref rect) => {
|
||||||
|
Image::Rect(ToComputedValue::from_computed_value(rect))
|
||||||
|
},
|
||||||
|
Image::Element(ref selector) => {
|
||||||
|
Image::Element(selector.clone())
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, L, LoP, P, C> ToCss for Gradient<D, L, LoP, P, C>
|
||||||
|
where D: LineDirection, L: ToCss, LoP: ToCss, P: ToCss, C: ToCss,
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
if self.compat_mode == CompatMode::WebKit {
|
||||||
|
dest.write_str("-webkit-")?;
|
||||||
|
}
|
||||||
|
if self.repeating {
|
||||||
|
dest.write_str("repeating-")?;
|
||||||
|
}
|
||||||
|
dest.write_str(self.kind.label())?;
|
||||||
|
dest.write_str("-gradient(")?;
|
||||||
|
let mut skip_comma = match self.kind {
|
||||||
|
GradientKind::Linear(ref direction) if direction.points_downwards() => true,
|
||||||
|
GradientKind::Linear(ref direction) => {
|
||||||
|
direction.to_css(dest, self.compat_mode)?;
|
||||||
|
false
|
||||||
|
},
|
||||||
|
GradientKind::Radial(ref shape, ref position) => {
|
||||||
|
let omit_shape = match *shape {
|
||||||
|
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::Cover)) |
|
||||||
|
EndingShape::Ellipse(Ellipse::Extent(ShapeExtent::FarthestCorner)) => {
|
||||||
|
true
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
};
|
||||||
|
if self.compat_mode == CompatMode::Modern {
|
||||||
|
if !omit_shape {
|
||||||
|
shape.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
}
|
||||||
|
dest.write_str("at ")?;
|
||||||
|
position.to_css(dest)?;
|
||||||
|
} else {
|
||||||
|
position.to_css(dest)?;
|
||||||
|
if !omit_shape {
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
shape.to_css(dest)?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
false
|
||||||
|
},
|
||||||
|
};
|
||||||
|
for item in &self.items {
|
||||||
|
if !skip_comma {
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
}
|
||||||
|
skip_comma = false;
|
||||||
|
item.to_css(dest)?;
|
||||||
|
}
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, L, LoP, P, C> HasViewportPercentage for Gradient<D, L, LoP, P, C>
|
||||||
|
where L: HasViewportPercentage,
|
||||||
|
LoP: HasViewportPercentage,
|
||||||
|
P: HasViewportPercentage,
|
||||||
|
{
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
self.kind.has_viewport_percentage() ||
|
||||||
|
self.items.iter().any(|i| i.has_viewport_percentage())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, L, LoP, P, C> ToComputedValue for Gradient<D, L, LoP, P, C>
|
||||||
|
where D: ToComputedValue,
|
||||||
|
L: ToComputedValue,
|
||||||
|
LoP: ToComputedValue,
|
||||||
|
P: ToComputedValue,
|
||||||
|
C: ToComputedValue,
|
||||||
|
{
|
||||||
|
type ComputedValue = Gradient<<D as ToComputedValue>::ComputedValue,
|
||||||
|
<L as ToComputedValue>::ComputedValue,
|
||||||
|
<LoP as ToComputedValue>::ComputedValue,
|
||||||
|
<P as ToComputedValue>::ComputedValue,
|
||||||
|
<C as ToComputedValue>::ComputedValue>;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
Gradient {
|
||||||
|
kind: self.kind.to_computed_value(context),
|
||||||
|
items: self.items.iter().map(|s| s.to_computed_value(context)).collect(),
|
||||||
|
repeating: self.repeating,
|
||||||
|
compat_mode: self.compat_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
Gradient {
|
||||||
|
kind: ToComputedValue::from_computed_value(&computed.kind),
|
||||||
|
items: computed.items.iter().map(ToComputedValue::from_computed_value).collect(),
|
||||||
|
repeating: computed.repeating,
|
||||||
|
compat_mode: computed.compat_mode,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, L, LoP, P> GradientKind<D, L, LoP, P> {
|
||||||
|
fn label(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
GradientKind::Linear(..) => "linear",
|
||||||
|
GradientKind::Radial(..) => "radial",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, L, LoP, P> HasViewportPercentage for GradientKind<D, L, LoP, P>
|
||||||
|
where L: HasViewportPercentage,
|
||||||
|
LoP: HasViewportPercentage,
|
||||||
|
P: HasViewportPercentage
|
||||||
|
{
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
GradientKind::Linear(_) => false,
|
||||||
|
GradientKind::Radial(ref shape, ref position) => {
|
||||||
|
shape.has_viewport_percentage() || position.has_viewport_percentage()
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<D, L, LoP, P> ToComputedValue for GradientKind<D, L, LoP, P>
|
||||||
|
where D: ToComputedValue,
|
||||||
|
L: ToComputedValue,
|
||||||
|
LoP: ToComputedValue,
|
||||||
|
P: ToComputedValue,
|
||||||
|
{
|
||||||
|
type ComputedValue = GradientKind<<D as ToComputedValue>::ComputedValue,
|
||||||
|
<L as ToComputedValue>::ComputedValue,
|
||||||
|
<LoP as ToComputedValue>::ComputedValue,
|
||||||
|
<P as ToComputedValue>::ComputedValue>;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
match *self {
|
||||||
|
GradientKind::Linear(ref direction) => {
|
||||||
|
GradientKind::Linear(direction.to_computed_value(context))
|
||||||
|
},
|
||||||
|
GradientKind::Radial(ref shape, ref position) => {
|
||||||
|
GradientKind::Radial(shape.to_computed_value(context), position.to_computed_value(context))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
match *computed {
|
||||||
|
GradientKind::Linear(ref direction) => {
|
||||||
|
GradientKind::Linear(ToComputedValue::from_computed_value(direction))
|
||||||
|
},
|
||||||
|
GradientKind::Radial(ref shape, ref position) => {
|
||||||
|
GradientKind::Radial(
|
||||||
|
ToComputedValue::from_computed_value(shape),
|
||||||
|
ToComputedValue::from_computed_value(position),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The direction of a linear gradient.
|
||||||
|
pub trait LineDirection {
|
||||||
|
/// Whether this direction points towards, and thus can be omitted.
|
||||||
|
fn points_downwards(&self) -> bool;
|
||||||
|
|
||||||
|
/// Serialises this direction according to the compatibility mode.
|
||||||
|
fn to_css<W>(&self, dest: &mut W, compat_mode: CompatMode) -> fmt::Result
|
||||||
|
where W: fmt::Write;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L, LoP> ToCss for EndingShape<L, LoP>
|
||||||
|
where L: ToCss, LoP: ToCss,
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
EndingShape::Circle(Circle::Extent(ShapeExtent::FarthestCorner)) |
|
||||||
|
EndingShape::Circle(Circle::Extent(ShapeExtent::Cover)) => {
|
||||||
|
dest.write_str("circle")
|
||||||
|
},
|
||||||
|
EndingShape::Circle(Circle::Extent(keyword)) => {
|
||||||
|
dest.write_str("circle ")?;
|
||||||
|
keyword.to_css(dest)
|
||||||
|
},
|
||||||
|
EndingShape::Circle(Circle::Radius(ref length)) => {
|
||||||
|
length.to_css(dest)
|
||||||
|
},
|
||||||
|
EndingShape::Ellipse(Ellipse::Extent(keyword)) => {
|
||||||
|
keyword.to_css(dest)
|
||||||
|
},
|
||||||
|
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
|
||||||
|
x.to_css(dest)?;
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
y.to_css(dest)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L, LoP> HasViewportPercentage for EndingShape<L, LoP>
|
||||||
|
where L: HasViewportPercentage, LoP: HasViewportPercentage,
|
||||||
|
{
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
EndingShape::Circle(Circle::Radius(ref length)) => {
|
||||||
|
length.has_viewport_percentage()
|
||||||
|
},
|
||||||
|
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
|
||||||
|
x.has_viewport_percentage() || y.has_viewport_percentage()
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<L, LoP> ToComputedValue for EndingShape<L, LoP>
|
||||||
|
where L: ToComputedValue, LoP: ToComputedValue,
|
||||||
|
{
|
||||||
|
type ComputedValue = EndingShape<<L as ToComputedValue>::ComputedValue,
|
||||||
|
<LoP as ToComputedValue>::ComputedValue>;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
match *self {
|
||||||
|
EndingShape::Circle(Circle::Radius(ref length)) => {
|
||||||
|
EndingShape::Circle(Circle::Radius(length.to_computed_value(context)))
|
||||||
|
},
|
||||||
|
EndingShape::Circle(Circle::Extent(extent)) => {
|
||||||
|
EndingShape::Circle(Circle::Extent(extent))
|
||||||
|
},
|
||||||
|
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
|
||||||
|
EndingShape::Ellipse(Ellipse::Radii(
|
||||||
|
x.to_computed_value(context),
|
||||||
|
y.to_computed_value(context),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
EndingShape::Ellipse(Ellipse::Extent(extent)) => {
|
||||||
|
EndingShape::Ellipse(Ellipse::Extent(extent))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
match *computed {
|
||||||
|
EndingShape::Circle(Circle::Radius(ref length)) => {
|
||||||
|
EndingShape::Circle(Circle::Radius(ToComputedValue::from_computed_value(length)))
|
||||||
|
},
|
||||||
|
EndingShape::Circle(Circle::Extent(extent)) => {
|
||||||
|
EndingShape::Circle(Circle::Extent(extent))
|
||||||
|
},
|
||||||
|
EndingShape::Ellipse(Ellipse::Radii(ref x, ref y)) => {
|
||||||
|
EndingShape::Ellipse(Ellipse::Radii(
|
||||||
|
ToComputedValue::from_computed_value(x),
|
||||||
|
ToComputedValue::from_computed_value(y),
|
||||||
|
))
|
||||||
|
},
|
||||||
|
EndingShape::Ellipse(Ellipse::Extent(extent)) => {
|
||||||
|
EndingShape::Ellipse(Ellipse::Extent(extent))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, L> ToCss for GradientItem<C, L>
|
||||||
|
where C: ToCss, L: ToCss,
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
match *self {
|
||||||
|
GradientItem::ColorStop(ref stop) => stop.to_css(dest),
|
||||||
|
GradientItem::InterpolationHint(ref hint) => hint.to_css(dest),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, L> HasViewportPercentage for GradientItem<C, L>
|
||||||
|
where L: HasViewportPercentage,
|
||||||
|
{
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
match *self {
|
||||||
|
GradientItem::ColorStop(ref stop) => stop.has_viewport_percentage(),
|
||||||
|
GradientItem::InterpolationHint(ref hint) => hint.has_viewport_percentage(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, L> ToComputedValue for GradientItem<C, L>
|
||||||
|
where C: ToComputedValue, L: ToComputedValue,
|
||||||
|
{
|
||||||
|
type ComputedValue = GradientItem<<C as ToComputedValue>::ComputedValue,
|
||||||
|
<L as ToComputedValue>::ComputedValue>;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
match *self {
|
||||||
|
GradientItem::ColorStop(ref stop) => {
|
||||||
|
GradientItem::ColorStop(stop.to_computed_value(context))
|
||||||
|
},
|
||||||
|
GradientItem::InterpolationHint(ref hint) => {
|
||||||
|
GradientItem::InterpolationHint(hint.to_computed_value(context))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
match *computed {
|
||||||
|
GradientItem::ColorStop(ref stop) => {
|
||||||
|
GradientItem::ColorStop(ToComputedValue::from_computed_value(stop))
|
||||||
|
},
|
||||||
|
GradientItem::InterpolationHint(ref hint) => {
|
||||||
|
GradientItem::InterpolationHint(ToComputedValue::from_computed_value(hint))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, L> fmt::Debug for ColorStop<C, L>
|
||||||
|
where C: fmt::Debug, L: fmt::Debug,
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "{:?}", self.color)?;
|
||||||
|
if let Some(ref pos) = self.position {
|
||||||
|
write!(f, " {:?}", pos)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, L> ToCss for ColorStop<C, L>
|
||||||
|
where C: ToCss, L: ToCss,
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
self.color.to_css(dest)?;
|
||||||
|
if let Some(ref position) = self.position {
|
||||||
|
dest.write_str(" ")?;
|
||||||
|
position.to_css(dest)?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, L> HasViewportPercentage for ColorStop<C, L>
|
||||||
|
where L: HasViewportPercentage,
|
||||||
|
{
|
||||||
|
fn has_viewport_percentage(&self) -> bool {
|
||||||
|
self.position.as_ref().map_or(false, HasViewportPercentage::has_viewport_percentage)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C, L> ToComputedValue for ColorStop<C, L>
|
||||||
|
where C: ToComputedValue, L: ToComputedValue,
|
||||||
|
{
|
||||||
|
type ComputedValue = ColorStop<<C as ToComputedValue>::ComputedValue,
|
||||||
|
<L as ToComputedValue>::ComputedValue>;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
ColorStop {
|
||||||
|
color: self.color.to_computed_value(context),
|
||||||
|
position: self.position.as_ref().map(|p| p.to_computed_value(context)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
ColorStop {
|
||||||
|
color: ToComputedValue::from_computed_value(&computed.color),
|
||||||
|
position: computed.position.as_ref().map(ToComputedValue::from_computed_value),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> ToCss for ImageRect<C>
|
||||||
|
where C: ToCss,
|
||||||
|
{
|
||||||
|
fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
|
||||||
|
dest.write_str("-moz-image-rect(")?;
|
||||||
|
self.url.to_css(dest)?;
|
||||||
|
dest.write_str(", ")?;
|
||||||
|
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)?;
|
||||||
|
dest.write_str(")")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C> ToComputedValue for ImageRect<C>
|
||||||
|
where C: ToComputedValue,
|
||||||
|
{
|
||||||
|
type ComputedValue = ImageRect<<C as ToComputedValue>::ComputedValue>;
|
||||||
|
|
||||||
|
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
|
||||||
|
ImageRect {
|
||||||
|
url: self.url.to_computed_value(context),
|
||||||
|
top: self.top.to_computed_value(context),
|
||||||
|
right: self.right.to_computed_value(context),
|
||||||
|
bottom: self.bottom.to_computed_value(context),
|
||||||
|
left: self.left.to_computed_value(context),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn from_computed_value(computed: &Self::ComputedValue) -> Self {
|
||||||
|
ImageRect {
|
||||||
|
url: ToComputedValue::from_computed_value(&computed.url),
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -14,6 +14,7 @@ use super::computed::{Context, ToComputedValue};
|
||||||
pub use self::basic_shape::serialize_radius_values;
|
pub use self::basic_shape::serialize_radius_values;
|
||||||
|
|
||||||
pub mod basic_shape;
|
pub mod basic_shape;
|
||||||
|
pub mod image;
|
||||||
pub mod position;
|
pub mod position;
|
||||||
|
|
||||||
#[derive(Clone, PartialEq, Debug)]
|
#[derive(Clone, PartialEq, Debug)]
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -15,7 +15,7 @@ use std::{cmp, fmt, mem};
|
||||||
use std::ascii::AsciiExt;
|
use std::ascii::AsciiExt;
|
||||||
use std::ops::Mul;
|
use std::ops::Mul;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
use style_traits::values::specified::AllowedLengthType;
|
use style_traits::values::specified::{AllowedLengthType, AllowedNumericType};
|
||||||
use stylesheets::CssRuleType;
|
use stylesheets::CssRuleType;
|
||||||
use super::{AllowQuirks, Number, ToComputedValue};
|
use super::{AllowQuirks, Number, ToComputedValue};
|
||||||
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal};
|
use values::{Auto, CSSFloat, Either, FONT_MEDIUM_PX, HasViewportPercentage, None_, Normal};
|
||||||
|
@ -24,9 +24,8 @@ use values::computed::{ComputedValueAsSpecified, Context};
|
||||||
use values::specified::calc::CalcNode;
|
use values::specified::calc::CalcNode;
|
||||||
|
|
||||||
pub use values::specified::calc::CalcLengthOrPercentage;
|
pub use values::specified::calc::CalcLengthOrPercentage;
|
||||||
pub use super::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
|
pub use super::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
|
||||||
pub use super::image::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword};
|
pub use super::image::{GradientKind, Image};
|
||||||
pub use super::image::{SizeKeyword, VerticalDirection};
|
|
||||||
|
|
||||||
/// Number of app units per pixel
|
/// Number of app units per pixel
|
||||||
pub const AU_PER_PX: CSSFloat = 60.;
|
pub const AU_PER_PX: CSSFloat = 60.;
|
||||||
|
@ -730,7 +729,10 @@ impl ToCss for Percentage {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Percentage {
|
impl Percentage {
|
||||||
fn parse_internal(input: &mut Parser, context: AllowedLengthType) -> Result<Self, ()> {
|
/// Parse a specific kind of percentage.
|
||||||
|
pub fn parse_with_clamping_mode(input: &mut Parser,
|
||||||
|
context: AllowedNumericType)
|
||||||
|
-> Result<Self, ()> {
|
||||||
match try!(input.next()) {
|
match try!(input.next()) {
|
||||||
Token::Percentage(ref value) if context.is_ok(value.unit_value) => {
|
Token::Percentage(ref value) if context.is_ok(value.unit_value) => {
|
||||||
Ok(Percentage(value.unit_value))
|
Ok(Percentage(value.unit_value))
|
||||||
|
@ -741,14 +743,14 @@ impl Percentage {
|
||||||
|
|
||||||
/// Parses a percentage token, but rejects it if it's negative.
|
/// Parses a percentage token, but rejects it if it's negative.
|
||||||
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
|
pub fn parse_non_negative(input: &mut Parser) -> Result<Self, ()> {
|
||||||
Self::parse_internal(input, AllowedLengthType::NonNegative)
|
Self::parse_with_clamping_mode(input, AllowedNumericType::NonNegative)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Parse for Percentage {
|
impl Parse for Percentage {
|
||||||
#[inline]
|
#[inline]
|
||||||
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse(_context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
Self::parse_internal(input, AllowedLengthType::All)
|
Self::parse_with_clamping_mode(input, AllowedNumericType::All)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,9 +28,8 @@ use values::specified::calc::CalcNode;
|
||||||
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
|
||||||
pub use self::color::Color;
|
pub use self::color::Color;
|
||||||
pub use self::grid::{GridLine, TrackKeyword};
|
pub use self::grid::{GridLine, TrackKeyword};
|
||||||
pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
|
pub use self::image::{ColorStop, EndingShape as GradientEndingShape, Gradient};
|
||||||
pub use self::image::{GradientItem, GradientKind, HorizontalDirection, Image, ImageRect, LayerImage};
|
pub use self::image::{GradientItem, GradientKind, Image, ImageRect, ImageLayer};
|
||||||
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword, SizeKeyword, VerticalDirection};
|
|
||||||
pub use self::length::AbsoluteLength;
|
pub use self::length::AbsoluteLength;
|
||||||
pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
|
pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
|
||||||
pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
|
||||||
|
@ -681,7 +680,7 @@ impl ToCss for Number {
|
||||||
|
|
||||||
/// <number-percentage>
|
/// <number-percentage>
|
||||||
/// Accepts only non-negative numbers.
|
/// Accepts only non-negative numbers.
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub enum NumberOrPercentage {
|
pub enum NumberOrPercentage {
|
||||||
|
@ -691,13 +690,27 @@ pub enum NumberOrPercentage {
|
||||||
|
|
||||||
no_viewport_percentage!(NumberOrPercentage);
|
no_viewport_percentage!(NumberOrPercentage);
|
||||||
|
|
||||||
impl Parse for NumberOrPercentage {
|
impl NumberOrPercentage {
|
||||||
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
fn parse_with_clamping_mode(context: &ParserContext,
|
||||||
if let Ok(per) = input.try(Percentage::parse_non_negative) {
|
input: &mut Parser,
|
||||||
|
type_: AllowedNumericType)
|
||||||
|
-> Result<Self, ()> {
|
||||||
|
if let Ok(per) = input.try(|i| Percentage::parse_with_clamping_mode(i, type_)) {
|
||||||
return Ok(NumberOrPercentage::Percentage(per));
|
return Ok(NumberOrPercentage::Percentage(per));
|
||||||
}
|
}
|
||||||
|
|
||||||
Number::parse_non_negative(context, input).map(NumberOrPercentage::Number)
|
parse_number_with_clamping_mode(context, input, type_).map(NumberOrPercentage::Number)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parse a non-negative number or percentage.
|
||||||
|
pub fn parse_non_negative(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
Self::parse_with_clamping_mode(context, input, AllowedNumericType::NonNegative)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for NumberOrPercentage {
|
||||||
|
fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
|
||||||
|
Self::parse_with_clamping_mode(context, input, AllowedNumericType::All)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1835,8 +1835,8 @@ pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(declarations:
|
||||||
raw_extra_data: *mut URLExtraData) {
|
raw_extra_data: *mut URLExtraData) {
|
||||||
use style::properties::PropertyDeclaration;
|
use style::properties::PropertyDeclaration;
|
||||||
use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
|
use style::properties::longhands::background_image::SpecifiedValue as BackgroundImage;
|
||||||
use style::properties::longhands::background_image::single_value::SpecifiedValue as SingleBackgroundImage;
|
use style::values::Either;
|
||||||
use style::values::specified::image::Image;
|
use style::values::generics::image::Image;
|
||||||
use style::values::specified::url::SpecifiedUrl;
|
use style::values::specified::url::SpecifiedUrl;
|
||||||
|
|
||||||
let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
|
let url_data = unsafe { RefPtr::from_ptr_ref(&raw_extra_data) };
|
||||||
|
@ -1847,9 +1847,7 @@ pub extern "C" fn Servo_DeclarationBlock_SetBackgroundImage(declarations:
|
||||||
QuirksMode::NoQuirks);
|
QuirksMode::NoQuirks);
|
||||||
if let Ok(url) = SpecifiedUrl::parse_from_string(string.into(), &context) {
|
if let Ok(url) = SpecifiedUrl::parse_from_string(string.into(), &context) {
|
||||||
let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
|
let decl = PropertyDeclaration::BackgroundImage(BackgroundImage(
|
||||||
vec![SingleBackgroundImage(
|
vec![Either::Second(Image::Url(url))]
|
||||||
Some(Image::Url(url))
|
|
||||||
)]
|
|
||||||
));
|
));
|
||||||
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
write_locked_arc(declarations, |decls: &mut PropertyDeclarationBlock| {
|
||||||
decls.push(decl, Importance::Normal);
|
decls.push(decl, Importance::Normal);
|
||||||
|
|
|
@ -2,16 +2,8 @@
|
||||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
* 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/. */
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
use euclid::size::TypedSize2D;
|
|
||||||
use parsing::parse;
|
use parsing::parse;
|
||||||
use std::f32::consts::PI;
|
use style::parser::Parse;
|
||||||
use style::context::QuirksMode;
|
|
||||||
use style::font_metrics::ServoMetricsProvider;
|
|
||||||
use style::media_queries::{Device, MediaType};
|
|
||||||
use style::properties::{ComputedValues, StyleBuilder};
|
|
||||||
use style::values::computed;
|
|
||||||
use style::values::computed::{Angle, Context, ToComputedValue};
|
|
||||||
use style::values::specified;
|
|
||||||
use style::values::specified::image::*;
|
use style::values::specified::image::*;
|
||||||
use style_traits::ToCss;
|
use style_traits::ToCss;
|
||||||
|
|
||||||
|
@ -37,101 +29,77 @@ fn test_linear_gradient() {
|
||||||
|
|
||||||
// Parsing without <angle> and <side-or-corner>
|
// Parsing without <angle> and <side-or-corner>
|
||||||
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green)");
|
assert_roundtrip_with_context!(Image::parse, "linear-gradient(red, green)");
|
||||||
|
|
||||||
// AngleOrCorner::None should become AngleOrCorner::Angle(Angle(PI)) when parsed
|
|
||||||
// Note that Angle(PI) is correct for top-to-bottom rendering, whereas Angle(0) would render bottom-to-top.
|
|
||||||
// ref: https://developer.mozilla.org/en-US/docs/Web/CSS/angle
|
|
||||||
let viewport_size = TypedSize2D::new(0., 0.);
|
|
||||||
let initial_style = ComputedValues::initial_values();
|
|
||||||
let device = Device::new(MediaType::Screen, viewport_size);
|
|
||||||
let specified_context = Context {
|
|
||||||
is_root_element: true,
|
|
||||||
device: &device,
|
|
||||||
inherited_style: initial_style,
|
|
||||||
layout_parent_style: initial_style,
|
|
||||||
style: StyleBuilder::for_derived_style(&initial_style),
|
|
||||||
cached_system_font: None,
|
|
||||||
font_metrics_provider: &ServoMetricsProvider,
|
|
||||||
in_media_query: false,
|
|
||||||
quirks_mode: QuirksMode::NoQuirks,
|
|
||||||
};
|
|
||||||
assert_eq!(specified::AngleOrCorner::None.to_computed_value(&specified_context),
|
|
||||||
computed::AngleOrCorner::Angle(Angle::from_radians(PI)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_radial_gradient() {
|
fn test_radial_gradient() {
|
||||||
// Parsing with all values
|
// Parsing with all values
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(circle closest-side at 20px 30px, red, green)");
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(circle closest-side at 20px 30px, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(ellipse closest-side at 20px 30px, red, green)");
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(ellipse closest-side at 20px 30px, red, green)",
|
||||||
|
"radial-gradient(closest-side at 20px 30px, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side circle at 20px 30px, red, green)",
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side circle at 20px 30px, red, green)",
|
||||||
"radial-gradient(circle closest-side at 20px 30px, red, green)");
|
"radial-gradient(circle closest-side at 20px 30px, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side ellipse at 20px 30px, red, green)",
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side ellipse at 20px 30px, red, green)",
|
||||||
"radial-gradient(ellipse closest-side at 20px 30px, red, green)");
|
"radial-gradient(closest-side at 20px 30px, red, green)");
|
||||||
|
|
||||||
// Parsing with <shape-keyword> and <size> reversed
|
// Parsing with <shape-keyword> and <size> reversed
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side circle at 20px 30px, red, green)",
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-side circle at 20px 30px, red, green)",
|
||||||
"radial-gradient(circle closest-side at 20px 30px, red, green)");
|
"radial-gradient(circle closest-side at 20px 30px, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-corner ellipse at 20px 30px, red, green)",
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(closest-corner ellipse at 20px 30px, red, green)",
|
||||||
"radial-gradient(ellipse closest-corner at 20px 30px, red, green)");
|
"radial-gradient(closest-corner at 20px 30px, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(30px circle, red, green)",
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(30px circle, red, green)",
|
||||||
"radial-gradient(circle 30px at center center, red, green)");
|
"radial-gradient(30px at center center, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse, "radial-gradient(30px 40px ellipse, red, green)",
|
assert_roundtrip_with_context!(Image::parse, "radial-gradient(30px 40px ellipse, red, green)",
|
||||||
"radial-gradient(ellipse 30px 40px at center center, red, green)");
|
"radial-gradient(30px 40px at center center, red, green)");
|
||||||
|
|
||||||
// Parsing without <size>
|
// Parsing without <size>
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(circle, red, green)",
|
"radial-gradient(circle, red, green)",
|
||||||
"radial-gradient(circle farthest-corner at center center, red, green)");
|
"radial-gradient(circle at center center, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(ellipse, red, green)",
|
"radial-gradient(ellipse, red, green)",
|
||||||
"radial-gradient(ellipse farthest-corner at center center, red, green)");
|
"radial-gradient(at center center, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(circle at 20px 30px, red, green)",
|
"radial-gradient(circle at 20px 30px, red, green)");
|
||||||
"radial-gradient(circle farthest-corner at 20px 30px, red, green)");
|
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(ellipse at 20px 30px, red, green)",
|
"radial-gradient(ellipse at 20px 30px, red, green)",
|
||||||
"radial-gradient(ellipse farthest-corner at 20px 30px, red, green)");
|
"radial-gradient(at 20px 30px, red, green)");
|
||||||
|
|
||||||
|
|
||||||
// Parsing without <shape-keyword>
|
// Parsing without <shape-keyword>
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(20px at 20px 30px, red, green)",
|
"radial-gradient(20px at 20px 30px, red, green)");
|
||||||
"radial-gradient(circle 20px at 20px 30px, red, green)");
|
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(20px 30px at left center, red, green)",
|
"radial-gradient(20px 30px at left center, red, green)");
|
||||||
"radial-gradient(ellipse 20px 30px at left center, red, green)");
|
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(closest-side at center, red, green)",
|
"radial-gradient(closest-side at center, red, green)",
|
||||||
"radial-gradient(ellipse closest-side at center center, red, green)");
|
"radial-gradient(closest-side at center center, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(20px, red, green)",
|
"radial-gradient(20px, red, green)",
|
||||||
"radial-gradient(circle 20px at center center, red, green)");
|
"radial-gradient(20px at center center, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(20px 30px, red, green)",
|
"radial-gradient(20px 30px, red, green)",
|
||||||
"radial-gradient(ellipse 20px 30px at center center, red, green)");
|
"radial-gradient(20px 30px at center center, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(closest-side, red, green)",
|
"radial-gradient(closest-side, red, green)",
|
||||||
"radial-gradient(ellipse closest-side at center center, red, green)");
|
"radial-gradient(closest-side at center center, red, green)");
|
||||||
|
|
||||||
// Parsing without <shape-keyword> and <size>
|
// Parsing without <shape-keyword> and <size>
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(at center, red, green)",
|
"radial-gradient(at center, red, green)",
|
||||||
"radial-gradient(ellipse farthest-corner at center center, red, green)");
|
"radial-gradient(at center center, red, green)");
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(at center bottom, red, green)",
|
"radial-gradient(at center bottom, red, green)");
|
||||||
"radial-gradient(ellipse farthest-corner at center bottom, red, green)");
|
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(at 40px 50px, red, green)",
|
"radial-gradient(at 40px 50px, red, green)");
|
||||||
"radial-gradient(ellipse farthest-corner at 40px 50px, red, green)");
|
|
||||||
|
|
||||||
// Parsing with just color stops
|
// Parsing with just color stops
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"radial-gradient(red, green)",
|
"radial-gradient(red, green)",
|
||||||
"radial-gradient(ellipse farthest-corner at center center, red, green)");
|
"radial-gradient(at center center, red, green)");
|
||||||
|
|
||||||
// Parsing repeating radial gradient
|
// Parsing repeating radial gradient
|
||||||
assert_roundtrip_with_context!(Image::parse,
|
assert_roundtrip_with_context!(Image::parse,
|
||||||
"repeating-radial-gradient(red, green)",
|
"repeating-radial-gradient(red, green)",
|
||||||
"repeating-radial-gradient(ellipse farthest-corner at center center, red, green)");
|
"repeating-radial-gradient(at center center, red, green)");
|
||||||
}
|
}
|
||||||
|
|
|
@ -799,7 +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::specified::Image;
|
use style::values::Either;
|
||||||
|
use style::values::generics::image::Image;
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
macro_rules! single_vec_value_typedef {
|
macro_rules! single_vec_value_typedef {
|
||||||
|
@ -828,9 +829,10 @@ mod shorthand_serialization {
|
||||||
fn mask_should_serialize_all_available_properties_when_specified() {
|
fn mask_should_serialize_all_available_properties_when_specified() {
|
||||||
let mut properties = Vec::new();
|
let mut properties = Vec::new();
|
||||||
|
|
||||||
let image = single_vec_value_typedef!(image,
|
let image = single_vec_value_typedef!(
|
||||||
image::single_value::SpecifiedValue(
|
image,
|
||||||
Some(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))));
|
Either::Second(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))
|
||||||
|
);
|
||||||
|
|
||||||
let mode = single_vec_keyword_value!(mode, luminance);
|
let mode = single_vec_keyword_value!(mode, luminance);
|
||||||
|
|
||||||
|
@ -880,9 +882,10 @@ mod shorthand_serialization {
|
||||||
fn mask_should_combine_origin_and_clip_properties_when_equal() {
|
fn mask_should_combine_origin_and_clip_properties_when_equal() {
|
||||||
let mut properties = Vec::new();
|
let mut properties = Vec::new();
|
||||||
|
|
||||||
let image = single_vec_value_typedef!(image,
|
let image = single_vec_value_typedef!(
|
||||||
image::single_value::SpecifiedValue(
|
image,
|
||||||
Some(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))));
|
Either::Second(Image::Url(SpecifiedUrl::new_for_testing("http://servo/test.png")))
|
||||||
|
);
|
||||||
|
|
||||||
let mode = single_vec_keyword_value!(mode, luminance);
|
let mode = single_vec_keyword_value!(mode, luminance);
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue