From 494238ab2939d42f1ba0eaf862900a12105149e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Sat, 25 Mar 2017 02:08:02 +0300 Subject: [PATCH] Add support for -moz-image-rect --- components/layout/display_list_builder.rs | 6 ++ components/style/gecko/conversions.rs | 25 +++++++- components/style/gecko_bindings/bindings.rs | 3 + components/style/values/computed/image.rs | 70 ++++++++++++++++++++- components/style/values/computed/mod.rs | 2 +- components/style/values/specified/image.rs | 68 +++++++++++++++++++- components/style/values/specified/mod.rs | 4 +- 7 files changed, 169 insertions(+), 9 deletions(-) diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 7b1403b492c..bf0550b0363 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -611,6 +611,9 @@ impl FragmentDisplayListBuilding for Fragment { i); } } + Some(computed::Image::ImageRect(_)) => { + // TODO: Implement `-moz-image-rect` + } } } } @@ -1076,6 +1079,9 @@ impl FragmentDisplayListBuilding for Fragment { Some(computed::Image::Gradient(..)) => { // TODO(gw): Handle border-image with gradient. } + Some(computed::Image::ImageRect(..)) => { + // TODO: Handle border-image with `-moz-image-rect`. + } Some(computed::Image::Url(ref image_url)) => { if let Some(url) = image_url.url() { let webrender_image = state.layout_context diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 43c8ce3b3a3..15a58b65cca 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -9,8 +9,9 @@ #![allow(unsafe_code)] use app_units::Au; -use gecko::values::convert_rgba_to_nscolor; +use gecko::values::{convert_rgba_to_nscolor, GeckoStyleCoordConvertible}; use gecko_bindings::bindings::{Gecko_CreateGradient, Gecko_SetGradientImageValue, Gecko_SetUrlImageValue}; +use gecko_bindings::bindings::Gecko_InitializeImageCropRect; use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImage}; use gecko_bindings::structs::nsresult; use gecko_bindings::sugar::ns_style_coord::{CoordDataValue, CoordDataMut}; @@ -118,6 +119,28 @@ impl nsStyleImage { *cacheable = false; } }, + Image::ImageRect(ref image_rect) if with_url => { + unsafe { + Gecko_SetUrlImageValue(self, image_rect.url.for_ffi()); + Gecko_InitializeImageCropRect(self); + + // We unfortunately must make any url() value uncacheable, since + // the applicable declarations cache is not per document, but + // global, and the imgRequestProxy objects we store in the style + // structs don't like to be tracked by more than one document. + // + // FIXME(emilio): With the scoped TLS thing this is no longer + // true, remove this line in a follow-up! + *cacheable = false; + + // Set CropRect + let ref mut rect = *self.mCropRect.mPtr; + image_rect.top.to_gecko_style_coord(&mut rect.data_at_mut(0)); + image_rect.right.to_gecko_style_coord(&mut rect.data_at_mut(1)); + image_rect.bottom.to_gecko_style_coord(&mut rect.data_at_mut(2)); + image_rect.left.to_gecko_style_coord(&mut rect.data_at_mut(3)); + } + } _ => (), } } diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index 7efc2252a00..75af7928a7f 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -678,6 +678,9 @@ extern "C" { pub fn Gecko_CopyImageValueFrom(image: *mut nsStyleImage, other: *const nsStyleImage); } +extern "C" { + pub fn Gecko_InitializeImageCropRect(image: *mut nsStyleImage); +} extern "C" { pub fn Gecko_CreateGradient(shape: u8, size: u8, repeating: bool, legacy_syntax: bool, stops: u32) diff --git a/components/style/values/computed/image.rs b/components/style/values/computed/image.rs index 8441ab62c05..1227cb73094 100644 --- a/components/style/values/computed/image.rs +++ b/components/style/values/computed/image.rs @@ -11,7 +11,7 @@ use cssparser::Color as CSSColor; use std::f32::consts::PI; use std::fmt; use style_traits::ToCss; -use values::computed::{Angle, Context, Length, LengthOrPercentage, ToComputedValue}; +use values::computed::{Angle, Context, Length, LengthOrPercentage, NumberOrPercentage, ToComputedValue}; use values::computed::position::Position; use values::specified::{self, HorizontalDirection, SizeKeyword, VerticalDirection}; use values::specified::url::SpecifiedUrl; @@ -28,6 +28,9 @@ impl ToComputedValue for specified::Image { }, 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)) } } } @@ -42,7 +45,12 @@ impl ToComputedValue for specified::Image { specified::Image::Gradient( ToComputedValue::from_computed_value(linear_gradient) ) - } + }, + Image::ImageRect(ref image_rect) => { + specified::Image::ImageRect( + ToComputedValue::from_computed_value(image_rect) + ) + }, } } } @@ -55,6 +63,7 @@ impl ToComputedValue for specified::Image { pub enum Image { Url(SpecifiedUrl), Gradient(Gradient), + ImageRect(ImageRect), } impl fmt::Debug for Image { @@ -70,6 +79,7 @@ impl fmt::Debug for Image { GradientKind::Radial(_, _) => write!(f, "radial-gradient({:?})", grad), } }, + Image::ImageRect(ref image_rect) => write!(f, "{:?}", image_rect), } } } @@ -78,7 +88,8 @@ impl ToCss for Image { fn to_css(&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::Gradient(ref gradient) => gradient.to_css(dest), + Image::ImageRect(ref image_rect) => image_rect.to_css(dest), } } } @@ -336,6 +347,59 @@ impl ToComputedValue for specified::GradientEndingShape { } } +/// 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(&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))] diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 87eb9e972cc..9ed8f81ee13 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -15,7 +15,7 @@ use super::{CSSFloat, CSSInteger, RGBA, specified}; use super::specified::grid::{TrackBreadth as GenericTrackBreadth, TrackSize as GenericTrackSize}; pub use cssparser::Color as CSSColor; -pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image}; +pub use self::image::{AngleOrCorner, EndingShape as GradientShape, Gradient, GradientKind, Image, ImageRect}; pub use self::image::{LengthOrKeyword, LengthOrPercentageOrKeyword}; pub use super::{Auto, Either, None_}; #[cfg(feature = "gecko")] diff --git a/components/style/values/specified/image.rs b/components/style/values/specified/image.rs index ef1df93f9fa..affe73d542b 100644 --- a/components/style/values/specified/image.rs +++ b/components/style/values/specified/image.rs @@ -13,7 +13,7 @@ use parser::{Parse, ParserContext}; use servo_url::ServoUrl; use std::fmt; use style_traits::ToCss; -use values::specified::{Angle, CSSColor, Length, LengthOrPercentage}; +use values::specified::{Angle, CSSColor, Length, LengthOrPercentage, NumberOrPercentage}; use values::specified::position::Position; use values::specified::url::SpecifiedUrl; @@ -26,6 +26,8 @@ pub enum Image { Url(SpecifiedUrl), /// A `` image. Gradient(Gradient), + /// A `-moz-image-rect` image + ImageRect(ImageRect), } impl ToCss for Image { @@ -33,6 +35,7 @@ impl ToCss for Image { match *self { Image::Url(ref url_value) => url_value.to_css(dest), Image::Gradient(ref gradient) => gradient.to_css(dest), + Image::ImageRect(ref image_rect) => image_rect.to_css(dest), } } } @@ -43,8 +46,11 @@ impl Image { if let Ok(url) = input.try(|input| SpecifiedUrl::parse(context, input)) { return Ok(Image::Url(url)); } + if let Ok(gradient) = input.try(|input| Gradient::parse_function(context, input)) { + return Ok(Image::Gradient(gradient)); + } - Ok(Image::Gradient(try!(Gradient::parse_function(context, input)))) + Ok(Image::ImageRect(ImageRect::parse(context, input)?)) } /// Creates an already specified image value from an already resolved URL @@ -236,6 +242,64 @@ impl GradientKind { } } +/// Specified values for `moz-image-rect` +/// -moz-image-rect(, top, right, bottom, left); +#[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(&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 Parse for ImageRect { + fn parse(context: &ParserContext, input: &mut Parser) -> Result { + match_ignore_ascii_case! { &try!(input.expect_function()), + "-moz-image-rect" => { + input.parse_nested_block(|input| { + let url = SpecifiedUrl::parse(context, input)?; + input.expect_comma()?; + let top = NumberOrPercentage::parse(context, input)?; + input.expect_comma()?; + let right = NumberOrPercentage::parse(context, input)?; + input.expect_comma()?; + let bottom = NumberOrPercentage::parse(context, input)?; + input.expect_comma()?; + let left = NumberOrPercentage::parse(context, input)?; + + Ok(ImageRect { + url: url, + top: top, + right: right, + bottom: bottom, + left: left, + }) + }) + } + _ => Err(()) + } + } +} + fn parse_two_length(context: &ParserContext, input: &mut Parser) -> Result<(LengthOrPercentage, LengthOrPercentage), ()> { let first = try!(LengthOrPercentage::parse(context, input)); diff --git a/components/style/values/specified/mod.rs b/components/style/values/specified/mod.rs index a7c07de2bad..1a7fda7a673 100644 --- a/components/style/values/specified/mod.rs +++ b/components/style/values/specified/mod.rs @@ -26,8 +26,8 @@ pub use self::align::{AlignItems, AlignJustifyContent, AlignJustifySelf, Justify 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::{GradientKind, HorizontalDirection, Image, LengthOrKeyword, LengthOrPercentageOrKeyword}; -pub use self::image::{SizeKeyword, VerticalDirection}; +pub use self::image::{GradientKind, HorizontalDirection, Image, ImageRect, LengthOrKeyword}; +pub use self::image::{LengthOrPercentageOrKeyword, SizeKeyword, VerticalDirection}; 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};