diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index fde7f3151990..bc3dd20d6cb1 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -22,6 +22,7 @@ use values::generics::grid::TrackSize; use values::generics::image::{CompatMode, Image as GenericImage, GradientItem}; use values::generics::rect::Rect; use values::specified::length::Percentage; +use values::specified::url::SpecifiedUrl; impl From for nsStyleCoord_CalcValue { fn from(other: CalcLengthOrPercentage) -> nsStyleCoord_CalcValue { @@ -364,6 +365,212 @@ impl nsStyleImage { Gecko_SetGradientImageValue(self, gecko_gradient); } } + + /// Converts into Image. + pub unsafe fn into_image(self: &nsStyleImage) -> Option { + use gecko_bindings::bindings::Gecko_GetImageElement; + use gecko_bindings::structs::nsStyleImageType; + use values::computed::{NumberOrPercentage, ImageRect}; + + match self.mType { + nsStyleImageType::eStyleImageType_Null => { + None + }, + nsStyleImageType::eStyleImageType_Image => { + let url = self.get_image_url(); + if self.mCropRect.mPtr.is_null() { + Some(GenericImage::Url(url)) + } else { + let ref rect = *self.mCropRect.mPtr; + match (NumberOrPercentage::from_gecko_style_coord(&rect.data_at(0)), + NumberOrPercentage::from_gecko_style_coord(&rect.data_at(1)), + NumberOrPercentage::from_gecko_style_coord(&rect.data_at(2)), + NumberOrPercentage::from_gecko_style_coord(&rect.data_at(3))) { + (Some(top), Some(right), Some(bottom), Some(left)) => + Some(GenericImage::Rect(ImageRect { url, top, right, bottom, left } )), + _ => { + debug_assert!(false, "mCropRect could not convert to NumberOrPercentage"); + None + } + } + } + }, + nsStyleImageType::eStyleImageType_Gradient => { + Some(GenericImage::Gradient(self.get_gradient())) + }, + nsStyleImageType::eStyleImageType_Element => { + use gecko_string_cache::Atom; + let atom = Gecko_GetImageElement(self); + Some(GenericImage::Element(Atom::from(atom))) + }, + x => panic!("Unexpected image type {:?}", x) + } + } + + unsafe fn get_image_url(self: &nsStyleImage) -> SpecifiedUrl { + use gecko_bindings::bindings::Gecko_GetURLValue; + let url_value = Gecko_GetURLValue(self); + let mut url = SpecifiedUrl::from_url_value_data(url_value.as_ref().unwrap()) + .expect("Could not convert to SpecifiedUrl"); + url.build_image_value(); + url + } + + unsafe fn get_gradient(self: &nsStyleImage) -> Gradient { + use gecko::values::convert_nscolor_to_rgba; + use gecko_bindings::bindings::Gecko_GetGradientImageValue; + use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_CIRCULAR, NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL}; + use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER}; + 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 values::computed::{Length, LengthOrPercentage}; + use values::computed::image::LineDirection; + use values::computed::position::Position; + use values::generics::image::{ColorStop, CompatMode, Circle, Ellipse, EndingShape, GradientKind, ShapeExtent}; + use values::specified::position::{X, Y}; + + let gecko_gradient = Gecko_GetGradientImageValue(self).as_ref().unwrap(); + let angle = Angle::from_gecko_style_coord(&gecko_gradient.mAngle); + let horizontal_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosX); + let vertical_style = LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mBgPosY); + + let kind = match gecko_gradient.mShape as u32 { + NS_STYLE_GRADIENT_SHAPE_LINEAR => { + let line_direction = match (angle, horizontal_style, vertical_style) { + (Some(a), None, None) => LineDirection::Angle(a), + (None, Some(horizontal), Some(vertical)) => { + let horizontal_as_corner = match horizontal { + LengthOrPercentage::Percentage(percentage) => { + if percentage.0 == 0.0 { + Some(X::Left) + } else if percentage.0 == 1.0 { + Some(X::Right) + } else { + None + } + }, + _ => None + }; + let vertical_as_corner = match vertical { + LengthOrPercentage::Percentage(percentage) => { + if percentage.0 == 0.0 { + Some(Y::Top) + } else if percentage.0 == 1.0 { + Some(Y::Bottom) + } else { + None + } + }, + _ => None + }; + + match (horizontal_as_corner, vertical_as_corner) { + (Some(hc), Some(vc)) => LineDirection::Corner(hc, vc), + _ => LineDirection::MozPosition( + Some(Position { horizontal, vertical }), None) + } + }, + (Some(_), Some(horizontal), Some(vertical)) => + LineDirection::MozPosition( + Some(Position { horizontal, vertical }), angle), + _ => { + debug_assert!(horizontal_style.is_none() && vertical_style.is_none(), + "Unexpected linear gradient direction"); + LineDirection::MozPosition(None, None) + } + }; + GradientKind::Linear(line_direction) + }, + _ => { + let gecko_size_to_keyword = |gecko_size| { + match gecko_size { + NS_STYLE_GRADIENT_SIZE_CLOSEST_SIDE => ShapeExtent::ClosestSide, + NS_STYLE_GRADIENT_SIZE_FARTHEST_SIDE => ShapeExtent::FarthestSide, + NS_STYLE_GRADIENT_SIZE_CLOSEST_CORNER => ShapeExtent::ClosestCorner, + NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER => ShapeExtent::FarthestCorner, + // FIXME: We should support ShapeExtent::Contain and ShapeExtent::Cover. + // But we can't choose those yet since Gecko does not support both values. + // https://bugzilla.mozilla.org/show_bug.cgi?id=1217664 + x => panic!("Found unexpected gecko_size: {:?}", x), + } + }; + + let shape = match gecko_gradient.mShape as u32 { + NS_STYLE_GRADIENT_SHAPE_CIRCULAR => { + let circle = match gecko_gradient.mSize as u32 { + NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => { + let radius = Length::from_gecko_style_coord(&gecko_gradient.mRadiusX) + .expect("mRadiusX could not convert to Length"); + debug_assert_eq!(radius, + Length::from_gecko_style_coord(&gecko_gradient.mRadiusY).unwrap()); + Circle::Radius(radius) + }, + size => Circle::Extent(gecko_size_to_keyword(size)) + }; + EndingShape::Circle(circle) + }, + NS_STYLE_GRADIENT_SHAPE_ELLIPTICAL => { + let length_percentage_keyword = match gecko_gradient.mSize as u32 { + NS_STYLE_GRADIENT_SIZE_EXPLICIT_SIZE => { + match (LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusX), + LengthOrPercentage::from_gecko_style_coord(&gecko_gradient.mRadiusY)) { + (Some(x), Some(y)) => Ellipse::Radii(x, y), + _ => { + debug_assert!(false, + "mRadiusX, mRadiusY could not convert to LengthOrPercentage"); + Ellipse::Radii(LengthOrPercentage::zero(), + LengthOrPercentage::zero()) + } + } + }, + size => Ellipse::Extent(gecko_size_to_keyword(size)) + }; + EndingShape::Ellipse(length_percentage_keyword) + }, + x => panic!("Found unexpected mShape: {:?}", x), + }; + + let position = match (horizontal_style, vertical_style) { + (Some(horizontal), Some(vertical)) => Position { horizontal, vertical }, + _ => { + debug_assert!(false, + "mRadiusX, mRadiusY could not convert to LengthOrPercentage"); + Position { + horizontal: LengthOrPercentage::zero(), + vertical: LengthOrPercentage::zero() + } + } + }; + + GradientKind::Radial(shape, position, angle) + } + }; + + let items = gecko_gradient.mStops.iter().map(|ref stop| { + if stop.mIsInterpolationHint { + GradientItem::InterpolationHint( + LengthOrPercentage::from_gecko_style_coord(&stop.mLocation) + .expect("mLocation could not convert to LengthOrPercentage") + ) + } else { + GradientItem::ColorStop(ColorStop { + color: convert_nscolor_to_rgba(stop.mColor), + position: LengthOrPercentage::from_gecko_style_coord(&stop.mLocation) + }) + } + }).collect(); + + let compat_mode = + if gecko_gradient.mMozLegacySyntax { + CompatMode::Moz + } else if gecko_gradient.mLegacySyntax { + CompatMode::WebKit + } else { + CompatMode::Modern + }; + + Gradient { items, repeating: gecko_gradient.mRepeating, kind, compat_mode } + } } pub mod basic_shape { diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index a196fec9f1f0..70169b8020bd 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1085,6 +1085,15 @@ fn static_assert() { } } + pub fn clone_border_image_source(&self) -> longhands::border_image_source::computed_value::T { + use values::None_; + + match unsafe { self.gecko.mBorderImageSource.into_image() } { + Some(image) => Either::Second(image), + None => Either::First(None_), + } + } + <% impl_style_sides("border_image_outset") %> <% @@ -3318,6 +3327,21 @@ fn static_assert() { } } + pub fn clone_${shorthand}_image(&self) -> longhands::${shorthand}_image::computed_value::T { + use values::None_; + + longhands::${shorthand}_image::computed_value::T( + self.gecko.${image_layers_field}.mLayers.iter() + .take(self.gecko.${image_layers_field}.mImageCount as usize) + .map(|ref layer| { + match unsafe { layer.mImage.into_image() } { + Some(image) => Either::Second(image), + None => Either::First(None_), + } + }).collect() + ) + } + <% fill_fields = "mRepeat mClip mOrigin mPositionX mPositionY mImage mSize" if shorthand == "background": diff --git a/components/style/properties/helpers/animated_properties.mako.rs b/components/style/properties/helpers/animated_properties.mako.rs index 26e56a89c521..03a51eb0a399 100644 --- a/components/style/properties/helpers/animated_properties.mako.rs +++ b/components/style/properties/helpers/animated_properties.mako.rs @@ -414,7 +414,12 @@ impl AnimatedProperty { let value: longhands::${prop.ident}::computed_value::T = ToAnimatedValue::from_animated_value(value); % endif - style.mutate_${prop.style_struct.ident.strip("_")}().set_${prop.ident}(value); + <% method = "style.mutate_" + prop.style_struct.ident.strip("_") + "().set_" + prop.ident %> + % if prop.has_uncacheable_values is "True": + ${method}(value, &mut false); + % else: + ${method}(value); + % endif } % endif % endfor diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index 821e7c428e49..96d05bed6c49 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -19,7 +19,7 @@ ${helpers.predefined_type("background-image", "ImageLayer", initial_specified_value="Either::First(None_)", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector="True", - animation_value_type="none", + animation_value_type="discrete", has_uncacheable_values="True" if product == "gecko" else "False", ignored_when_colors_disabled="True")} diff --git a/components/style/properties/longhand/border.mako.rs b/components/style/properties/longhand/border.mako.rs index f3b3642382db..740f2d9fd250 100644 --- a/components/style/properties/longhand/border.mako.rs +++ b/components/style/properties/longhand/border.mako.rs @@ -200,7 +200,7 @@ ${helpers.predefined_type("border-image-source", "ImageLayer", initial_specified_value="Either::First(None_)", spec="https://drafts.csswg.org/css-backgrounds/#the-background-image", vector=False, - animation_value_type="none", + animation_value_type="discrete", has_uncacheable_values=False, boxed="True")} diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index b000a105427d..887cf057bb22 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -150,6 +150,6 @@ ${helpers.predefined_type("mask-image", "ImageLayer", vector=True, products="gecko", extra_prefixes="webkit", - animation_value_type="none", + animation_value_type="discrete", flags="CREATES_STACKING_CONTEXT", has_uncacheable_values="True" if product == "gecko" else "False")}