Bug 1359787 - Implement {specified|computed}::LayerImage.
Since the way of parsing and serialization {specified|computed} value of
backgound-image, mask-image and border-image-source is the exactly the same,
create a new struct {specified|computed}::LayerImage to handling value parsing
and serialization, so that we can reuse the code among three properties.
MozReview-Commit-ID: 38e99H4k7mW
--- a/servo/components/style/properties/gecko.mako.rs
+++ b/servo/components/style/properties/gecko.mako.rs
@@ -916,23 +916,23 @@ fn static_assert() {
% for corner in CORNERS:
<% impl_corner_style_coord("border_%s_radius" % corner.ident,
"mBorderRadius",
corner.x_index,
corner.y_index,
need_clone=True) %>
% endfor
- pub fn set_border_image_source(&mut self, v: longhands::border_image_source::computed_value::T) {
+ pub fn set_border_image_source(&mut self, image: longhands::border_image_source::computed_value::T) {
unsafe {
// Prevent leaking of the last elements we did set
Gecko_SetNullImageValue(&mut self.gecko.mBorderImageSource);
}
- if let Some(image) = v.0 {
+ if let Some(image) = image.0 {
self.gecko.mBorderImageSource.set(image, &mut false)
}
}
pub fn copy_border_image_source_from(&mut self, other: &Self) {
unsafe {
Gecko_CopyImageValueFrom(&mut self.gecko.mBorderImageSource,
&other.gecko.mBorderImageSource);
@@ -2740,28 +2740,19 @@ fn static_assert() {
Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.0.len(),
LayerType::${shorthand.title()});
}
self.gecko.${image_layers_field}.mImageCount = images.0.len() as u32;
for (image, geckoimage) in images.0.into_iter().zip(self.gecko.${image_layers_field}
.mLayers.iter_mut()) {
- % if shorthand == "background":
- if let Some(image) = image.0 {
- geckoimage.mImage.set(image, cacheable)
- }
- % else:
- use properties::longhands::mask_image::single_value::computed_value::T;
- match image {
- T::Image(image) => geckoimage.mImage.set(image, cacheable),
- _ => ()
- }
- % endif
-
+ if let Some(image) = image.0 {
+ geckoimage.mImage.set(image, cacheable)
+ }
}
}
<%
fill_fields = "mRepeat mClip mOrigin mPositionX mPositionY mImage mSize"
if shorthand == "background":
fill_fields += " mAttachment mBlendMode"
else:
--- a/servo/components/style/properties/longhand/background.mako.rs
+++ b/servo/components/style/properties/longhand/background.mako.rs
@@ -7,92 +7,23 @@
<% data.new_style_struct("Background", inherited=False) %>
${helpers.predefined_type("background-color", "CSSColor",
"::cssparser::Color::RGBA(::cssparser::RGBA::transparent())",
initial_specified_value="SpecifiedValue::transparent()",
spec="https://drafts.csswg.org/css-backgrounds/#background-color",
animation_value_type="IntermediateColor", complex_color=True)}
-<%helpers:vector_longhand name="background-image" animation_value_type="none"
- spec="https://drafts.csswg.org/css-backgrounds/#the-background-image"
- has_uncacheable_values="${product == 'gecko'}">
- use std::fmt;
- use style_traits::ToCss;
- use values::HasViewportPercentage;
- use values::specified::Image;
-
- pub mod computed_value {
- use values::computed;
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct T(pub Option<computed::Image>);
- }
-
- impl ToCss for computed_value::T {
- 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),
- }
- }
- }
-
- no_viewport_percentage!(SpecifiedValue);
-
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct SpecifiedValue(pub Option<Image>);
-
- impl ToCss for SpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- SpecifiedValue(Some(ref image)) => image.to_css(dest),
- SpecifiedValue(None) => dest.write_str("none"),
- }
- }
- }
-
- #[inline]
- pub fn get_initial_value() -> computed_value::T {
- computed_value::T(None)
- }
- #[inline]
- pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue(None)
- }
- pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
- if input.try(|input| input.expect_ident_matching("none")).is_ok() {
- Ok(SpecifiedValue(None))
- } else {
- Ok(SpecifiedValue(Some(try!(Image::parse(context, input)))))
- }
- }
- impl ToComputedValue for SpecifiedValue {
- type ComputedValue = computed_value::T;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::T {
- match *self {
- SpecifiedValue(None) => computed_value::T(None),
- SpecifiedValue(Some(ref image)) =>
- computed_value::T(Some(image.to_computed_value(context))),
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &computed_value::T) -> Self {
- match *computed {
- computed_value::T(None) => SpecifiedValue(None),
- computed_value::T(Some(ref image)) =>
- SpecifiedValue(Some(ToComputedValue::from_computed_value(image))),
- }
- }
- }
-</%helpers:vector_longhand>
+${helpers.predefined_type("background-image", "LayerImage",
+ initial_value="computed_value::T(None)",
+ initial_specified_value="SpecifiedValue(None)",
+ spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
+ vector="True",
+ animation_value_type="none",
+ has_uncacheable_values="${product == 'gecko'}")}
<%helpers:predefined_type name="background-position-x" type="position::HorizontalPosition"
initial_value="computed::position::HorizontalPosition::zero()"
initial_specified_value="specified::position::HorizontalPosition::left()"
spec="https://drafts.csswg.org/css-backgrounds-4/#propdef-background-position-x"
animation_value_type="ComputedValue" vector="True" delegate_animate="True">
#[inline]
/// Get the initial value for horizontal position.
--- a/servo/components/style/properties/longhand/border.mako.rs
+++ b/servo/components/style/properties/longhand/border.mako.rs
@@ -185,91 +185,24 @@
${helpers.single_keyword("-moz-float-edge", "content-box margin-box",
gecko_ffi_name="mFloatEdge",
gecko_enum_prefix="StyleFloatEdge",
gecko_inexhaustive=True,
products="gecko",
spec="Nonstandard (https://developer.mozilla.org/en-US/docs/Web/CSS/-moz-float-edge)",
animation_value_type="none")}
-<%helpers:longhand name="border-image-source" animation_value_type="none" boxed="True"
- spec="https://drafts.csswg.org/css-backgrounds/#border-image-source">
- use std::fmt;
- use style_traits::ToCss;
- use values::HasViewportPercentage;
- use values::specified::Image;
-
- no_viewport_percentage!(SpecifiedValue);
-
- pub mod computed_value {
- use values::computed;
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct T(pub Option<computed::Image>);
- }
-
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub struct SpecifiedValue(pub Option<Image>);
-
- impl ToCss for computed_value::T {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match self.0 {
- Some(ref image) => image.to_css(dest),
- None => dest.write_str("none"),
- }
- }
- }
- impl ToCss for SpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match self.0 {
- Some(ref image) => image.to_css(dest),
- None => dest.write_str("none"),
- }
- }
- }
-
- #[inline]
- pub fn get_initial_value() -> computed_value::T {
- computed_value::T(None)
- }
-
- #[inline]
- pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue(None)
- }
-
- impl ToComputedValue for SpecifiedValue {
- type ComputedValue = computed_value::T;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::T {
- match self.0 {
- Some(ref image) => computed_value::T(Some(image.to_computed_value(context))),
- None => computed_value::T(None),
- }
- }
- #[inline]
- fn from_computed_value(computed: &computed_value::T) -> Self {
- match computed.0 {
- Some(ref image) =>
- SpecifiedValue(Some(ToComputedValue::from_computed_value(image))),
- None => SpecifiedValue(None),
- }
- }
- }
-
- pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
- if input.try(|input| input.expect_ident_matching("none")).is_ok() {
- return Ok(SpecifiedValue(None));
- }
-
- Ok(SpecifiedValue(Some(try!(Image::parse(context, input)))))
- }
-</%helpers:longhand>
+${helpers.predefined_type("border-image-source", "LayerImage",
+ initial_value="computed_value::T(None)",
+ initial_specified_value="SpecifiedValue(None)",
+ spec="https://drafts.csswg.org/css-backgrounds/#the-background-image",
+ vector=False,
+ animation_value_type="none",
+ has_uncacheable_values=False,
+ boxed="True")}
<%helpers:longhand name="border-image-outset" animation_value_type="none"
spec="https://drafts.csswg.org/css-backgrounds/#border-image-outset">
use std::fmt;
use style_traits::ToCss;
use values::HasViewportPercentage;
use values::specified::{LengthOrNumber, Number};
--- a/servo/components/style/properties/longhand/svg.mako.rs
+++ b/servo/components/style/properties/longhand/svg.mako.rs
@@ -186,102 +186,18 @@
${helpers.single_keyword("mask-composite",
"add subtract intersect exclude",
vector=True,
products="gecko",
extra_prefixes="webkit",
animation_value_type="none",
spec="https://drafts.fxtf.org/css-masking/#propdef-mask-composite")}
-<%helpers:vector_longhand name="mask-image" products="gecko" animation_value_type="none" extra_prefixes="webkit"
- has_uncacheable_values="${product == 'gecko'}"
- flags="CREATES_STACKING_CONTEXT",
- spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image">
- use std::fmt;
- use style_traits::ToCss;
- use std::sync::Arc;
- use values::specified::Image;
- use values::specified::url::SpecifiedUrl;
- use values::HasViewportPercentage;
-
- pub mod computed_value {
- use std::fmt;
- use style_traits::ToCss;
- use values::computed;
- use values::specified::url::SpecifiedUrl;
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub enum T {
- Image(computed::Image),
- None
- }
-
- impl ToCss for T {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- T::None => dest.write_str("none"),
- T::Image(ref image) => image.to_css(dest),
- }
- }
- }
- }
-
- no_viewport_percentage!(SpecifiedValue);
-
- #[derive(Debug, Clone, PartialEq)]
- #[cfg_attr(feature = "servo", derive(HeapSizeOf))]
- pub enum SpecifiedValue {
- Image(Image),
- None
- }
-
- impl ToCss for SpecifiedValue {
- fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
- match *self {
- SpecifiedValue::Image(ref image) => image.to_css(dest),
- SpecifiedValue::None => dest.write_str("none"),
- }
- }
- }
-
- #[inline]
- pub fn get_initial_value() -> computed_value::T {
- computed_value::T::None
- }
- #[inline]
- pub fn get_initial_specified_value() -> SpecifiedValue {
- SpecifiedValue::None
- }
- pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
- if input.try(|input| input.expect_ident_matching("none")).is_ok() {
- Ok(SpecifiedValue::None)
- } else {
- let image = try!(Image::parse(context, input));
- match image {
- Image::Url(url_value) => {
- Ok(SpecifiedValue::Image(Image::Url(url_value)))
- }
- image => Ok(SpecifiedValue::Image(image))
- }
- }
- }
- impl ToComputedValue for SpecifiedValue {
- type ComputedValue = computed_value::T;
-
- #[inline]
- fn to_computed_value(&self, context: &Context) -> computed_value::T {
- match *self {
- SpecifiedValue::None => computed_value::T::None,
- SpecifiedValue::Image(ref image) =>
- computed_value::T::Image(image.to_computed_value(context)),
- }
- }
-
- #[inline]
- fn from_computed_value(computed: &computed_value::T) -> Self {
- match *computed {
- computed_value::T::None => SpecifiedValue::None,
- computed_value::T::Image(ref image) =>
- SpecifiedValue::Image(ToComputedValue::from_computed_value(image)),
- }
- }
- }
-</%helpers:vector_longhand>
+${helpers.predefined_type("mask-image", "LayerImage",
+ initial_value="computed_value::T(None)",
+ initial_specified_value="SpecifiedValue(None)",
+ spec="https://drafts.fxtf.org/css-masking/#propdef-mask-image",
+ vector=True,
+ products="gecko",
+ extra_prefixes="webkit",
+ animation_value_type="none",
+ flags="CREATES_STACKING_CONTEXT",
+ has_uncacheable_values="${product == 'gecko'}")}
\ No newline at end of file
--- a/servo/components/style/values/computed/image.rs
+++ b/servo/components/style/values/computed/image.rs
@@ -672,8 +672,22 @@ impl AngleOrCorner {
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),
+ }
+ }
+}
\ No newline at end of file
--- a/servo/components/style/values/computed/mod.rs
+++ b/servo/components/style/values/computed/mod.rs
@@ -17,17 +17,17 @@ use std::fmt;
use style_traits::ToCss;
use super::{CSSFloat, CSSInteger, RGBA};
use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
use super::specified;
use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize};
pub use app_units::Au;
pub use cssparser::Color as CSSColor;
-pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientItem};
+pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientItem, LayerImage};
pub use self::image::{GradientKind, Image, ImageRect, LengthOrKeyword, LengthOrPercentageOrKeyword};
pub use super::{Auto, Either, None_};
#[cfg(feature = "gecko")]
pub use super::specified::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use super::specified::{BorderStyle, GridLine, Percentage, UrlOrNone};
pub use super::specified::url::SpecifiedUrl;
pub use self::length::{CalcLengthOrPercentage, Length, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
pub use self::length::{LengthOrPercentageOrAutoOrContent, LengthOrPercentageOrNone, LengthOrNone};
--- a/servo/components/style/values/specified/image.rs
+++ b/servo/components/style/values/specified/image.rs
@@ -661,8 +661,58 @@ define_css_keyword_enum!(SizeKeyword: "c
impl SizeKeyword {
fn parse_modern(input: &mut Parser) -> Result<Self, ()> {
match try!(SizeKeyword::parse(input)) {
SizeKeyword::Contain | SizeKeyword::Cover => Err(()),
keyword => Ok(keyword),
}
}
}
+
+/// Specified values for none | <image> | <mask-source>.
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(feature = "servo", derive(HeapSizeOf))]
+#[allow(missing_docs)]
+pub struct LayerImage(pub Option<Image>);
+use values::HasViewportPercentage;
+no_viewport_percentage!(LayerImage);
+
+impl ToCss for LayerImage {
+ fn to_css<W>(&self, dest: &mut W) -> fmt::Result where W: fmt::Write {
+ match *self {
+ LayerImage(Some(ref image)) => image.to_css(dest),
+ LayerImage(None) => dest.write_str("none"),
+ }
+ }
+}
+
+use super::computed::{ToComputedValue, Context};
+impl ToComputedValue for LayerImage {
+ type ComputedValue = super::computed::LayerImage;
+
+ #[inline]
+ fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
+ match *self {
+ LayerImage(None) => super::computed::LayerImage(None),
+ LayerImage(Some(ref image)) =>
+ super::computed::LayerImage(Some(image.to_computed_value(context))),
+ }
+ }
+
+ #[inline]
+ fn from_computed_value(computed: &Self::ComputedValue) -> Self {
+ match *computed {
+ super::computed::LayerImage(None) => LayerImage(None),
+ super::computed::LayerImage(Some(ref image)) =>
+ LayerImage(Some(ToComputedValue::from_computed_value(image))),
+ }
+ }
+}
+
+impl Parse for LayerImage {
+ fn parse(context: &ParserContext, input: &mut Parser) -> Result<Self, ()> {
+ if input.try(|input| input.expect_ident_matching("none")).is_ok() {
+ Ok(LayerImage(None))
+ } else {
+ Ok(LayerImage(Some(try!(Image::parse(context, input)))))
+ }
+ }
+}
--- a/servo/components/style/values/specified/mod.rs
+++ b/servo/components/style/values/specified/mod.rs
@@ -24,17 +24,17 @@ use super::computed::{self, Context};
use super::computed::{Shadow as ComputedShadow, ToComputedValue};
use super::generics::BorderRadiusSize as GenericBorderRadiusSize;
#[cfg(feature = "gecko")]
pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, JustifyItems};
pub use self::color::Color;
pub use self::grid::{GridLine, TrackKeyword};
pub use self::image::{AngleOrCorner, ColorStop, EndingShape as GradientEndingShape, Gradient};
-pub use self::image::{GradientItem, GradientKind, HorizontalDirection, Image, ImageRect};
+pub use self::image::{GradientItem, GradientKind, HorizontalDirection, Image, ImageRect, LayerImage};
pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword, SizeKeyword, VerticalDirection};
pub use self::length::AbsoluteLength;
pub use self::length::{FontRelativeLength, ViewportPercentageLength, CharacterWidth, Length, CalcLengthOrPercentage};
pub use self::length::{Percentage, LengthOrNone, LengthOrNumber, LengthOrPercentage, LengthOrPercentageOrAuto};
pub use self::length::{LengthOrPercentageOrNone, LengthOrPercentageOrAutoOrContent, NoCalcLength, CalcUnit};
pub use self::length::{MaxLength, MinLength};
pub use self::position::{HorizontalPosition, Position, VerticalPosition};