From 76651171fb6f099d92257ab6725dc7ab88b45c34 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 6 Sep 2016 14:09:00 +0800 Subject: [PATCH 1/3] Bug 1300731 - stylo: Implement mask longhands (except mask-image), write glue for most; r?heycam --- components/style/properties/gecko.mako.rs | 118 ++++++++++++++---- .../style/properties/longhand/svg.mako.rs | 70 +++++++++++ 2 files changed, 166 insertions(+), 22 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 8c72f927503..2b1d605b781 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -501,6 +501,8 @@ impl Debug for ${style_struct.gecko_struct_name} { "column-count", # column ] + force_stub += ["mask-position", "mask-size"] + # Types used with predefined_type()-defined properties that we can auto-generate. predefined_types = { "LengthOrPercentage": impl_style_coord, @@ -968,26 +970,34 @@ fn static_assert() { -<%def name="simple_background_array_property(name, field_name)"> - pub fn copy_background_${name}_from(&mut self, other: &Self) { +<%def name="simple_image_array_property(name, shorthand, field_name)"> + <% + image_layers_field = "mImage" if shorthand == "background" else "mMask" + %> + pub fn copy_${shorthand}_${name}_from(&mut self, other: &Self) { unsafe { - Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, other.gecko.mImage.mLayers.len()); + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, + other.gecko.${image_layers_field}.mLayers.len()); } - for (layer, other) in self.gecko.mImage.mLayers.iter_mut() - .zip(other.gecko.mImage.mLayers.iter()) - .take(other.gecko.mImage.${field_name}Count as usize) { + for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() + .zip(other.gecko.${image_layers_field}.mLayers.iter()) + .take(other.gecko.${image_layers_field} + .${field_name}Count as usize) { layer.${field_name} = other.${field_name}; } - self.gecko.mImage.${field_name}Count = other.gecko.mImage.${field_name}Count; + self.gecko.${image_layers_field}.${field_name}Count = + other.gecko.${image_layers_field}.${field_name}Count; } - pub fn set_background_${name}(&mut self, v: longhands::background_${name}::computed_value::T) { + pub fn set_${shorthand}_${name}(&mut self, + v: longhands::${shorthand}_${name}::computed_value::T) { unsafe { - Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, v.0.len()); + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, v.0.len()); } - self.gecko.mImage.${field_name}Count = v.0.len() as u32; - for (servo, geckolayer) in v.0.into_iter().zip(self.gecko.mImage.mLayers.iter_mut()) { + self.gecko.${image_layers_field}.${field_name}Count = v.0.len() as u32; + for (servo, geckolayer) in v.0.into_iter() + .zip(self.gecko.${image_layers_field}.mLayers.iter_mut()) { geckolayer.${field_name} = { ${caller.body()} }; @@ -1007,7 +1017,7 @@ fn static_assert() { <% impl_color("background_color", "mBackgroundColor", need_clone=True) %> - <%self:simple_background_array_property name="repeat" field_name="mRepeat"> + <%self:simple_image_array_property name="repeat" shorthand="background" field_name="mRepeat"> use properties::longhands::background_repeat::single_value::computed_value::T; use gecko_bindings::structs::nsStyleImageLayers_Repeat; use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_REPEAT; @@ -1027,9 +1037,9 @@ fn static_assert() { mXRepeat: repeat_x as u8, mYRepeat: repeat_y as u8, } - + - <%self:simple_background_array_property name="clip" field_name="mClip"> + <%self:simple_image_array_property name="clip" shorthand="background" field_name="mClip"> use properties::longhands::background_clip::single_value::computed_value::T; match servo { @@ -1037,9 +1047,9 @@ fn static_assert() { T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING as u8, T::content_box => structs::NS_STYLE_IMAGELAYER_CLIP_CONTENT as u8, } - + - <%self:simple_background_array_property name="origin" field_name="mOrigin"> + <%self:simple_image_array_property name="origin" shorthand="background" field_name="mOrigin"> use properties::longhands::background_origin::single_value::computed_value::T; match servo { @@ -1047,9 +1057,9 @@ fn static_assert() { T::padding_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_PADDING as u8, T::content_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_CONTENT as u8, } - + - <%self:simple_background_array_property name="attachment" field_name="mAttachment"> + <%self:simple_image_array_property name="attachment" shorthand="background" field_name="mAttachment"> use properties::longhands::background_attachment::single_value::computed_value::T; match servo { @@ -1057,9 +1067,9 @@ fn static_assert() { T::fixed => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED as u8, T::local => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL as u8, } - + - <%self:simple_background_array_property name="size" field_name="mSize"> + <%self:simple_image_array_property name="size" shorthand="background" field_name="mSize"> use gecko_bindings::structs::nsStyleImageLayers_Size_Dimension; use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType; use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImageLayers_Size}; @@ -1095,7 +1105,7 @@ fn static_assert() { mWidthType: w_type as u8, mHeightType: h_type as u8, } - + pub fn clone_background_size(&self) -> longhands::background_size::computed_value::T { use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue; @@ -1523,8 +1533,14 @@ fn static_assert() { } +<% skip_svg_longhands = """ +flood-color lighting-color stop-color +mask-mode mask-repeat mask-clip mask-origin mask-composite +clip-path +""" +%> <%self:impl_trait style_struct_name="SVG" - skip_longhands="flood-color lighting-color stop-color clip-path" + skip_longhands="${skip_svg_longhands}" skip_additionals="*"> <% impl_color("flood_color", "mFloodColor") %> @@ -1533,6 +1549,64 @@ fn static_assert() { <% impl_color("stop_color", "mStopColor") %> + <%self:simple_image_array_property name="mode" shorthand="mask" field_name="mMaskMode"> + use properties::longhands::mask_mode::single_value::computed_value::T; + + match servo { + T::alpha => structs::NS_STYLE_MASK_MODE_ALPHA as u8, + T::luminance => structs::NS_STYLE_MASK_MODE_LUMINANCE as u8, + T::match_source => structs::NS_STYLE_MASK_MODE_MATCH_SOURCE as u8, + } + + <%self:simple_image_array_property name="repeat" shorthand="mask" field_name="mRepeat"> + use properties::longhands::mask_repeat::single_value::computed_value::T; + use gecko_bindings::structs::nsStyleImageLayers_Repeat; + use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT; + use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_REPEAT; + + let (repeat_x, repeat_y) = match servo { + T::repeat_x => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT, + NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT), + T::repeat_y => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT, + NS_STYLE_IMAGELAYER_REPEAT_REPEAT), + T::repeat => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT, + NS_STYLE_IMAGELAYER_REPEAT_REPEAT), + T::no_repeat => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT, + NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT), + }; + nsStyleImageLayers_Repeat { + mXRepeat: repeat_x as u8, + mYRepeat: repeat_y as u8, + } + + <%self:simple_image_array_property name="clip" shorthand="mask" field_name="mClip"> + use properties::longhands::mask_clip::single_value::computed_value::T; + + match servo { + T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8, + T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING as u8, + T::content_box => structs::NS_STYLE_IMAGELAYER_CLIP_CONTENT as u8, + } + + <%self:simple_image_array_property name="origin" shorthand="mask" field_name="mOrigin"> + use properties::longhands::mask_origin::single_value::computed_value::T; + + match servo { + T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8, + T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING as u8, + T::content_box => structs::NS_STYLE_IMAGELAYER_CLIP_CONTENT as u8, + } + + <%self:simple_image_array_property name="composite" shorthand="mask" field_name="mComposite"> + use properties::longhands::mask_composite::single_value::computed_value::T; + + match servo { + T::add => structs::NS_STYLE_MASK_COMPOSITE_ADD as u8, + T::subtract => structs::NS_STYLE_MASK_COMPOSITE_SUBTRACT as u8, + T::intersect => structs::NS_STYLE_MASK_COMPOSITE_INTERSECT as u8, + T::exclude => structs::NS_STYLE_MASK_COMPOSITE_EXCLUDE as u8, + } + pub fn set_clip_path(&mut self, v: longhands::clip_path::computed_value::T) { use gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyClipPath}; use gecko_bindings::structs::StyleClipPathGeometryBox; diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index 3d0c5cc48aa..fb13562170e 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -77,3 +77,73 @@ ${helpers.single_keyword("mask-type", "luminance alpha", impl NoViewportPercentage for SpecifiedValue {} + +${helpers.single_keyword("mask-mode", + "alpha luminance match-source", + vector=True, + products="gecko", + animatable=False)} + +// TODO implement all of repeat-style for background and mask +// https://drafts.csswg.org/css-backgrounds-3/#repeat-style +${helpers.single_keyword("mask-repeat", + "repeat repeat-x repeat-y no-repeat", + vector=True, + products="gecko", + animatable=False)} + +<%helpers:longhand name="mask-position" products="gecko" animatable="True"> + use properties::longhands::background_position; + pub mod computed_value { + pub type T = ::properties::longhands::background_position::computed_value::T; + } + pub type SpecifiedValue = background_position::SpecifiedValue; + + #[inline] + pub fn get_initial_value() -> computed_value::T { + background_position::get_initial_value() + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + background_position::parse(context, input) + } + + +// missing: margin-box fill-box stroke-box view-box no-clip +// (gecko doesn't implement these) +${helpers.single_keyword("mask-clip", + "content-box padding-box border-box", + vector=True, + products="gecko", + animatable=False)} + +// missing: margin-box fill-box stroke-box view-box +// (gecko doesn't implement these) +${helpers.single_keyword("mask-origin", + "content-box padding-box border-box", + vector=True, + products="gecko", + animatable=False)} + +<%helpers:longhand name="mask-size" products="gecko" animatable="True"> + use properties::longhands::background_size; + pub mod computed_value { + pub type T = ::properties::longhands::background_size::computed_value::T; + } + pub type SpecifiedValue = background_size::SpecifiedValue; + + #[inline] + pub fn get_initial_value() -> computed_value::T { + background_size::get_initial_value() + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + background_size::parse(context, input) + } + + +${helpers.single_keyword("mask-composite", + "add subtract intersect exclude", + vector=True, + products="gecko", + animatable=False)} From 075a430b99eddc52621d7fd33f769e4b3f8599a6 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 6 Sep 2016 14:51:54 +0800 Subject: [PATCH 2/3] Bug 1300731 - stylo: Glue for mask-position, reuse code between background and mask; r?heycam --- components/style/properties/gecko.mako.rs | 209 ++++++++++------------ 1 file changed, 90 insertions(+), 119 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 2b1d605b781..e47e0d9b30a 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -497,12 +497,9 @@ impl Debug for ${style_struct.gecko_struct_name} { "transition-duration", "transition-timing-function", "transition-property", "transition-delay", - "background-size", # background "column-count", # column ] - force_stub += ["mask-position", "mask-size"] - # Types used with predefined_type()-defined properties that we can auto-generate. predefined_types = { "LengthOrPercentage": impl_style_coord, @@ -1004,21 +1001,13 @@ fn static_assert() { } } -// TODO: Gecko accepts lists in most background-related properties. We just use -// the first element (which is the common case), but at some point we want to -// add support for parsing these lists in servo and pushing to nsTArray's. -<% skip_background_longhands = """background-color background-repeat - background-image background-clip - background-origin background-attachment - background-size background-position""" %> -<%self:impl_trait style_struct_name="Background" - skip_longhands="${skip_background_longhands}" - skip_additionals="*"> +<%def name="impl_common_image_layer_properties(shorthand)"> + <% + image_layers_field = "mImage" if shorthand == "background" else "mMask" + %> - <% impl_color("background_color", "mBackgroundColor", need_clone=True) %> - - <%self:simple_image_array_property name="repeat" shorthand="background" field_name="mRepeat"> - use properties::longhands::background_repeat::single_value::computed_value::T; + <%self:simple_image_array_property name="repeat" shorthand="${shorthand}" field_name="mRepeat"> + use properties::longhands::${shorthand}_repeat::single_value::computed_value::T; use gecko_bindings::structs::nsStyleImageLayers_Repeat; use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_REPEAT; use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT; @@ -1039,8 +1028,8 @@ fn static_assert() { } - <%self:simple_image_array_property name="clip" shorthand="background" field_name="mClip"> - use properties::longhands::background_clip::single_value::computed_value::T; + <%self:simple_image_array_property name="clip" shorthand="${shorthand}" field_name="mClip"> + use properties::longhands::${shorthand}_clip::single_value::computed_value::T; match servo { T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8, @@ -1049,8 +1038,8 @@ fn static_assert() { } - <%self:simple_image_array_property name="origin" shorthand="background" field_name="mOrigin"> - use properties::longhands::background_origin::single_value::computed_value::T; + <%self:simple_image_array_property name="origin" shorthand="${shorthand}" field_name="mOrigin"> + use properties::longhands::${shorthand}_origin::single_value::computed_value::T; match servo { T::border_box => structs::NS_STYLE_IMAGELAYER_ORIGIN_BORDER as u8, @@ -1059,17 +1048,66 @@ fn static_assert() { } - <%self:simple_image_array_property name="attachment" shorthand="background" field_name="mAttachment"> - use properties::longhands::background_attachment::single_value::computed_value::T; - - match servo { - T::scroll => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL as u8, - T::fixed => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED as u8, - T::local => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL as u8, + pub fn copy_${shorthand}_position_from(&mut self, other: &Self) { + self.gecko.${image_layers_field}.mPositionXCount + = cmp::min(1, other.gecko.${image_layers_field}.mPositionXCount); + self.gecko.${image_layers_field}.mPositionYCount + = cmp::min(1, other.gecko.${image_layers_field}.mPositionYCount); + self.gecko.${image_layers_field}.mLayers.mFirstElement.mPosition = + other.gecko.${image_layers_field}.mLayers.mFirstElement.mPosition; + unsafe { + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, + other.gecko.${image_layers_field}.mLayers.len()); } - + for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() + .zip(other.gecko.${image_layers_field}.mLayers.iter()) + .take(other.gecko.${image_layers_field}.mPositionXCount as usize) { + layer.mPosition.mXPosition + = other.mPosition.mXPosition; + } + for (layer, other) in self.gecko.${image_layers_field}.mLayers.iter_mut() + .zip(other.gecko.${image_layers_field}.mLayers.iter()) + .take(other.gecko.${image_layers_field}.mPositionYCount as usize) { + layer.mPosition.mYPosition + = other.mPosition.mYPosition; + } + self.gecko.${image_layers_field}.mPositionXCount + = other.gecko.${image_layers_field}.mPositionXCount; + self.gecko.${image_layers_field}.mPositionYCount + = other.gecko.${image_layers_field}.mPositionYCount; + } - <%self:simple_image_array_property name="size" shorthand="background" field_name="mSize"> + pub fn clone_${shorthand}_position(&self) + -> longhands::${shorthand}_position::computed_value::T { + use values::computed::position::Position; + longhands::background_position::computed_value::T( + self.gecko.${image_layers_field}.mLayers.iter() + .take(self.gecko.${image_layers_field}.mPositionXCount as usize) + .take(self.gecko.${image_layers_field}.mPositionYCount as usize) + .map(|position| Position { + horizontal: position.mPosition.mXPosition.into(), + vertical: position.mPosition.mYPosition.into(), + }) + .collect() + ) + } + + pub fn set_${shorthand}_position(&mut self, + v: longhands::${shorthand}_position::computed_value::T) { + unsafe { + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, v.0.len()); + } + + self.gecko.${image_layers_field}.mPositionXCount = v.0.len() as u32; + self.gecko.${image_layers_field}.mPositionYCount = v.0.len() as u32; + for (servo, geckolayer) in v.0.into_iter().zip(self.gecko.${image_layers_field} + .mLayers.iter_mut()) { + geckolayer.mPosition.mXPosition = servo.horizontal.into(); + geckolayer.mPosition.mYPosition = servo.vertical.into(); + } + } + + <%self:simple_image_array_property name="size" shorthand="${shorthand}" field_name="mSize"> use gecko_bindings::structs::nsStyleImageLayers_Size_Dimension; use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType; use gecko_bindings::structs::{nsStyleCoord_CalcValue, nsStyleImageLayers_Size}; @@ -1107,7 +1145,7 @@ fn static_assert() { } - pub fn clone_background_size(&self) -> longhands::background_size::computed_value::T { + pub fn clone_${shorthand}_size(&self) -> longhands::background_size::computed_value::T { use gecko_bindings::structs::nsStyleCoord_CalcValue as CalcValue; use gecko_bindings::structs::nsStyleImageLayers_Size_DimensionType as DimensionType; use properties::longhands::background_size::single_value::computed_value::{ExplicitSize, T}; @@ -1123,7 +1161,7 @@ fn static_assert() { } longhands::background_size::computed_value::T( - self.gecko.mImage.mLayers.iter().map(|ref layer| { + self.gecko.${image_layers_field}.mLayers.iter().map(|ref layer| { if DimensionType::eCover as u8 == layer.mSize.mWidthType { debug_assert!(layer.mSize.mHeightType == DimensionType::eCover as u8); return T::Cover @@ -1140,55 +1178,27 @@ fn static_assert() { }).collect() ) } + +<% skip_background_longhands = """background-color background-repeat + background-image background-clip + background-origin background-attachment + background-size background-position""" %> +<%self:impl_trait style_struct_name="Background" + skip_longhands="${skip_background_longhands}" + skip_additionals="*"> - pub fn copy_background_position_from(&mut self, other: &Self) { - self.gecko.mImage.mPositionXCount = cmp::min(1, other.gecko.mImage.mPositionXCount); - self.gecko.mImage.mPositionYCount = cmp::min(1, other.gecko.mImage.mPositionYCount); - self.gecko.mImage.mLayers.mFirstElement.mPosition = - other.gecko.mImage.mLayers.mFirstElement.mPosition; - unsafe { - Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, other.gecko.mImage.mLayers.len()); - } - for (layer, other) in self.gecko.mImage.mLayers.iter_mut() - .zip(other.gecko.mImage.mLayers.iter()) - .take(other.gecko.mImage.mPositionXCount as usize) { - layer.mPosition.mXPosition = other.mPosition.mXPosition; - } - for (layer, other) in self.gecko.mImage.mLayers.iter_mut() - .zip(other.gecko.mImage.mLayers.iter()) - .take(other.gecko.mImage.mPositionYCount as usize) { - layer.mPosition.mYPosition = other.mPosition.mYPosition; - } - self.gecko.mImage.mPositionXCount = other.gecko.mImage.mPositionXCount; - self.gecko.mImage.mPositionYCount = other.gecko.mImage.mPositionYCount; - } + <% impl_color("background_color", "mBackgroundColor", need_clone=True) %> - pub fn clone_background_position(&self) -> longhands::background_position::computed_value::T { - use values::computed::position::Position; - longhands::background_position::computed_value::T( - self.gecko.mImage.mLayers.iter() - .take(self.gecko.mImage.mPositionXCount as usize) - .take(self.gecko.mImage.mPositionYCount as usize) - .map(|position| Position { - horizontal: position.mPosition.mXPosition.into(), - vertical: position.mPosition.mYPosition.into(), - }) - .collect() - ) - } + <% impl_common_image_layer_properties("background") %> - pub fn set_background_position(&mut self, v: longhands::background_position::computed_value::T) { - unsafe { - Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, v.0.len()); + <%self:simple_image_array_property name="attachment" shorthand="background" field_name="mAttachment"> + use properties::longhands::background_attachment::single_value::computed_value::T; + match servo { + T::scroll => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_SCROLL as u8, + T::fixed => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_FIXED as u8, + T::local => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL as u8, } - - self.gecko.mImage.mPositionXCount = v.0.len() as u32; - self.gecko.mImage.mPositionYCount = v.0.len() as u32; - for (servo, geckolayer) in v.0.into_iter().zip(self.gecko.mImage.mLayers.iter_mut()) { - geckolayer.mPosition.mXPosition = servo.horizontal.into(); - geckolayer.mPosition.mYPosition = servo.vertical.into(); - } - } + pub fn copy_background_image_from(&mut self, other: &Self) { unsafe { @@ -1220,8 +1230,6 @@ fn static_assert() { self.gecko.mImage.mImageCount = cmp::max(self.gecko.mImage.mLayers.len() as u32, self.gecko.mImage.mImageCount); - // TODO: pre-grow the nsTArray to the right capacity - // otherwise the below code won't work for (image, geckoimage) in images.0.into_iter().zip(self.gecko.mImage.mLayers.iter_mut()) { if let Some(image) = image.0 { match image { @@ -1535,7 +1543,7 @@ fn static_assert() { <% skip_svg_longhands = """ flood-color lighting-color stop-color -mask-mode mask-repeat mask-clip mask-origin mask-composite +mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position mask-size clip-path """ %> @@ -1549,6 +1557,8 @@ clip-path <% impl_color("stop_color", "mStopColor") %> + <% impl_common_image_layer_properties("mask") %> + <%self:simple_image_array_property name="mode" shorthand="mask" field_name="mMaskMode"> use properties::longhands::mask_mode::single_value::computed_value::T; @@ -1558,45 +1568,6 @@ clip-path T::match_source => structs::NS_STYLE_MASK_MODE_MATCH_SOURCE as u8, } - <%self:simple_image_array_property name="repeat" shorthand="mask" field_name="mRepeat"> - use properties::longhands::mask_repeat::single_value::computed_value::T; - use gecko_bindings::structs::nsStyleImageLayers_Repeat; - use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT; - use gecko_bindings::structs::NS_STYLE_IMAGELAYER_REPEAT_REPEAT; - - let (repeat_x, repeat_y) = match servo { - T::repeat_x => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT, - NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT), - T::repeat_y => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT, - NS_STYLE_IMAGELAYER_REPEAT_REPEAT), - T::repeat => (NS_STYLE_IMAGELAYER_REPEAT_REPEAT, - NS_STYLE_IMAGELAYER_REPEAT_REPEAT), - T::no_repeat => (NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT, - NS_STYLE_IMAGELAYER_REPEAT_NO_REPEAT), - }; - nsStyleImageLayers_Repeat { - mXRepeat: repeat_x as u8, - mYRepeat: repeat_y as u8, - } - - <%self:simple_image_array_property name="clip" shorthand="mask" field_name="mClip"> - use properties::longhands::mask_clip::single_value::computed_value::T; - - match servo { - T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8, - T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING as u8, - T::content_box => structs::NS_STYLE_IMAGELAYER_CLIP_CONTENT as u8, - } - - <%self:simple_image_array_property name="origin" shorthand="mask" field_name="mOrigin"> - use properties::longhands::mask_origin::single_value::computed_value::T; - - match servo { - T::border_box => structs::NS_STYLE_IMAGELAYER_CLIP_BORDER as u8, - T::padding_box => structs::NS_STYLE_IMAGELAYER_CLIP_PADDING as u8, - T::content_box => structs::NS_STYLE_IMAGELAYER_CLIP_CONTENT as u8, - } - <%self:simple_image_array_property name="composite" shorthand="mask" field_name="mComposite"> use properties::longhands::mask_composite::single_value::computed_value::T; From 7138ad7d7e0aec781bd9ef3f3fdb692d9a7a5168 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Tue, 6 Sep 2016 18:20:30 +0800 Subject: [PATCH 3/3] Bug 1300731 - stylo: Implement mask-image; r?heycam --- components/style/properties/gecko.mako.rs | 315 ++++++++++-------- .../properties/longhand/background.mako.rs | 4 +- .../style/properties/longhand/svg.mako.rs | 93 ++++++ .../style/properties/properties.mako.rs | 1 + components/style/values/computed/mod.rs | 12 + ports/geckolib/gecko_bindings/bindings.rs | 2 + 6 files changed, 283 insertions(+), 144 deletions(-) diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index e47e0d9b30a..ee9f843ac33 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1178,7 +1178,180 @@ fn static_assert() { }).collect() ) } + + + pub fn copy_${shorthand}_image_from(&mut self, other: &Self) { + unsafe { + Gecko_CopyImageValueFrom(&mut self.gecko.${image_layers_field}.mLayers.mFirstElement.mImage, + &other.gecko.${image_layers_field}.mLayers.mFirstElement.mImage); + } + } + + pub fn set_${shorthand}_image(&mut self, + images: longhands::${shorthand}_image::computed_value::T) { + use gecko_bindings::structs::nsStyleImage; + use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; + use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER}; + use gecko_bindings::structs::nsStyleCoord; + use values::computed::{Image, LinearGradient}; + use values::specified::AngleOrCorner; + use values::specified::{HorizontalDirection, VerticalDirection}; + use cssparser::Color as CSSColor; + + fn set_linear_gradient(gradient: LinearGradient, geckoimage: &mut nsStyleImage) { + let stop_count = gradient.stops.len(); + if stop_count >= ::std::u32::MAX as usize { + warn!("stylo: Prevented overflow due to too many gradient stops"); + return; + } + + let gecko_gradient = unsafe { + Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8, + NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8, + /* repeating = */ false, + /* legacy_syntax = */ false, + stop_count as u32) + }; + + match gradient.angle_or_corner { + AngleOrCorner::Angle(angle) => { + unsafe { + (*gecko_gradient).mAngle.set(angle); + (*gecko_gradient).mBgPosX.set_value(CoordDataValue::None); + (*gecko_gradient).mBgPosY.set_value(CoordDataValue::None); + } + } + AngleOrCorner::Corner(horiz, vert) => { + let percent_x = match horiz { + HorizontalDirection::Left => 0.0, + HorizontalDirection::Right => 1.0, + }; + let percent_y = match vert { + VerticalDirection::Top => 0.0, + VerticalDirection::Bottom => 1.0, + }; + + unsafe { + (*gecko_gradient).mAngle.set_value(CoordDataValue::None); + (*gecko_gradient).mBgPosX + .set_value(CoordDataValue::Percent(percent_x)); + (*gecko_gradient).mBgPosY + .set_value(CoordDataValue::Percent(percent_y)); + } + } + } + + let mut coord: nsStyleCoord = nsStyleCoord::null(); + for (index, stop) in gradient.stops.iter().enumerate() { + // NB: stops are guaranteed to be none in the gecko side by + // default. + coord.set(stop.position); + let color = match stop.color { + CSSColor::CurrentColor => { + // TODO(emilio): gecko just stores an nscolor, + // and it doesn't seem to support currentColor + // as value in a gradient. + // + // Double-check it and either remove + // currentColor for servo or see how gecko + // handles this. + 0 + }, + CSSColor::RGBA(ref rgba) => convert_rgba_to_nscolor(rgba), + }; + + let mut stop = unsafe { + &mut (*gecko_gradient).mStops[index] + }; + + stop.mColor = color; + stop.mIsInterpolationHint = false; + stop.mLocation.copy_from(&coord); + } + + unsafe { + Gecko_SetGradientImageValue(geckoimage, gecko_gradient); + } + } + + unsafe { + // Prevent leaking of the last elements we did set + for image in &mut self.gecko.${image_layers_field}.mLayers { + Gecko_SetNullImageValue(&mut image.mImage) + } + // XXXManishearth clear mSourceURI for masks + Gecko_EnsureImageLayersLength(&mut self.gecko.${image_layers_field}, images.0.len()); + for image in &mut self.gecko.${image_layers_field}.mLayers { + Gecko_InitializeImageLayer(image, 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 { + match image { + Image::LinearGradient(gradient) => { + set_linear_gradient(gradient, &mut geckoimage.mImage) + }, + Image::Url(..) => { + // let utf8_bytes = url.as_bytes(); + // Gecko_SetUrlImageValue(&mut self.gecko.mImage.mLayers.mFirstElement, + // utf8_bytes.as_ptr() as *const _, + // utf8_bytes.len()); + warn!("stylo: imgRequestProxies are not threadsafe in gecko, \ + background-image: url() not yet implemented"); + } + } + } + % else: + use properties::longhands::mask_image::single_value::computed_value::T; + match image { + T::Image(image) => match image { + Image::LinearGradient(gradient) => { + set_linear_gradient(gradient, &mut geckoimage.mImage) + } + _ => () // we need to support image values + }, + _ => () // we need to support url valeus + } + % endif + + } + } + + <% + fill_fields = "mRepeat mClip mOrigin mPositionX mPositionY mImage" + if shorthand == "background": + fill_fields += " mAttachment" + else: + # mSourceURI uses mImageCount + fill_fields += " mMaskMode mComposite" + %> + pub fn fill_arrays(&mut self) { + use gecko_bindings::bindings::Gecko_FillAll${shorthand.title()}Lists; + use std::cmp; + let mut max_len = 1; + % for member in fill_fields.split(): + max_len = cmp::max(max_len, self.gecko.${image_layers_field}.${member}Count); + % endfor + + // XXXManishearth Gecko does an optimization here where it only + // fills things in if any of the properties have been set + + unsafe { + // While we could do this manually, we'd need to also manually + // run all the copy constructors, so we just delegate to gecko + Gecko_FillAll${shorthand.title()}Lists(&mut self.gecko.${image_layers_field}, max_len); + } + } + +// TODO: Gecko accepts lists in most background-related properties. We just use +// the first element (which is the common case), but at some point we want to +// add support for parsing these lists in servo and pushing to nsTArray's. <% skip_background_longhands = """background-color background-repeat background-image background-clip background-origin background-attachment @@ -1199,146 +1372,6 @@ fn static_assert() { T::local => structs::NS_STYLE_IMAGELAYER_ATTACHMENT_LOCAL as u8, } - - pub fn copy_background_image_from(&mut self, other: &Self) { - unsafe { - Gecko_CopyImageValueFrom(&mut self.gecko.mImage.mLayers.mFirstElement.mImage, - &other.gecko.mImage.mLayers.mFirstElement.mImage); - } - } - - pub fn set_background_image(&mut self, images: longhands::background_image::computed_value::T) { - use gecko_bindings::structs::nsStyleImageLayers_LayerType as LayerType; - use gecko_bindings::structs::{NS_STYLE_GRADIENT_SHAPE_LINEAR, NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER}; - use gecko_bindings::structs::nsStyleCoord; - use values::computed::Image; - use values::specified::AngleOrCorner; - use values::specified::{HorizontalDirection, VerticalDirection}; - use cssparser::Color as CSSColor; - - unsafe { - // Prevent leaking of the last element we did set - for image in &mut self.gecko.mImage.mLayers { - Gecko_SetNullImageValue(&mut image.mImage) - } - Gecko_EnsureImageLayersLength(&mut self.gecko.mImage, images.0.len()); - for image in &mut self.gecko.mImage.mLayers { - Gecko_InitializeImageLayer(image, LayerType::Background); - } - } - - self.gecko.mImage.mImageCount = cmp::max(self.gecko.mImage.mLayers.len() as u32, - self.gecko.mImage.mImageCount); - - for (image, geckoimage) in images.0.into_iter().zip(self.gecko.mImage.mLayers.iter_mut()) { - if let Some(image) = image.0 { - match image { - Image::LinearGradient(ref gradient) => { - let stop_count = gradient.stops.len(); - if stop_count >= ::std::u32::MAX as usize { - warn!("stylo: Prevented overflow due to too many gradient stops"); - return; - } - - let gecko_gradient = unsafe { - Gecko_CreateGradient(NS_STYLE_GRADIENT_SHAPE_LINEAR as u8, - NS_STYLE_GRADIENT_SIZE_FARTHEST_CORNER as u8, - /* repeating = */ false, - /* legacy_syntax = */ false, - stop_count as u32) - }; - - match gradient.angle_or_corner { - AngleOrCorner::Angle(angle) => { - unsafe { - (*gecko_gradient).mAngle.set(angle); - (*gecko_gradient).mBgPosX.set_value(CoordDataValue::None); - (*gecko_gradient).mBgPosY.set_value(CoordDataValue::None); - } - } - AngleOrCorner::Corner(horiz, vert) => { - let percent_x = match horiz { - HorizontalDirection::Left => 0.0, - HorizontalDirection::Right => 1.0, - }; - let percent_y = match vert { - VerticalDirection::Top => 0.0, - VerticalDirection::Bottom => 1.0, - }; - - unsafe { - (*gecko_gradient).mAngle.set_value(CoordDataValue::None); - (*gecko_gradient).mBgPosX - .set_value(CoordDataValue::Percent(percent_x)); - (*gecko_gradient).mBgPosY - .set_value(CoordDataValue::Percent(percent_y)); - } - } - } - - let mut coord: nsStyleCoord = nsStyleCoord::null(); - for (index, stop) in gradient.stops.iter().enumerate() { - // NB: stops are guaranteed to be none in the gecko side by - // default. - coord.set(stop.position); - let color = match stop.color { - CSSColor::CurrentColor => { - // TODO(emilio): gecko just stores an nscolor, - // and it doesn't seem to support currentColor - // as value in a gradient. - // - // Double-check it and either remove - // currentColor for servo or see how gecko - // handles this. - 0 - }, - CSSColor::RGBA(ref rgba) => convert_rgba_to_nscolor(rgba), - }; - - let mut stop = unsafe { - &mut (*gecko_gradient).mStops[index] - }; - - stop.mColor = color; - stop.mIsInterpolationHint = false; - stop.mLocation.copy_from(&coord); - } - - unsafe { - Gecko_SetGradientImageValue(&mut geckoimage.mImage, gecko_gradient); - } - }, - Image::Url(..) => { - // let utf8_bytes = url.as_bytes(); - // Gecko_SetUrlImageValue(&mut self.gecko.mImage.mLayers.mFirstElement, - // utf8_bytes.as_ptr() as *const _, - // utf8_bytes.len()); - warn!("stylo: imgRequestProxies are not threadsafe in gecko, \ - background-image: url() not yet implemented"); - } - } - } - - } - } - - pub fn fill_arrays(&mut self) { - use gecko_bindings::bindings::Gecko_FillAllBackgroundLists; - use std::cmp; - let mut max_len = 1; - % for member in "mRepeat mClip mOrigin mAttachment mPositionX mPositionY mImage".split(): - max_len = cmp::max(max_len, self.gecko.mImage.${member}Count); - % endfor - - // XXXManishearth Gecko does an optimization here where it only - // fills things in if any of the properties have been set - - unsafe { - // While we could do this manually, we'd need to also manually - // run all the copy constructors, so we just delegate to gecko - Gecko_FillAllBackgroundLists(&mut self.gecko.mImage, max_len); - } - } <%self:impl_trait style_struct_name="List" skip_longhands="list-style-type" skip_additionals="*"> @@ -1543,7 +1576,7 @@ fn static_assert() { <% skip_svg_longhands = """ flood-color lighting-color stop-color -mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position mask-size +mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position mask-size mask-image clip-path """ %> diff --git a/components/style/properties/longhand/background.mako.rs b/components/style/properties/longhand/background.mako.rs index 893a0985d4b..c2c6212a60f 100644 --- a/components/style/properties/longhand/background.mako.rs +++ b/components/style/properties/longhand/background.mako.rs @@ -28,9 +28,7 @@ ${helpers.predefined_type("background-color", "CSSColor", fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { match self.0 { None => dest.write_str("none"), - Some(computed::Image::Url(ref url, ref _extra_data)) => url.to_css(dest), - Some(computed::Image::LinearGradient(ref gradient)) => - gradient.to_css(dest) + Some(ref image) => image.to_css(dest), } } } diff --git a/components/style/properties/longhand/svg.mako.rs b/components/style/properties/longhand/svg.mako.rs index fb13562170e..b7f78cd0ebd 100644 --- a/components/style/properties/longhand/svg.mako.rs +++ b/components/style/properties/longhand/svg.mako.rs @@ -147,3 +147,96 @@ ${helpers.single_keyword("mask-composite", vector=True, products="gecko", animatable=False)} + +<%helpers:vector_longhand name="mask-image" products="gecko" animatable="False"> + use cssparser::ToCss; + use std::fmt; + use url::Url; + use values::specified::{Image, UrlExtraData}; + use values::LocalToCss; + use values::NoViewportPercentage; + + pub mod computed_value { + use cssparser::ToCss; + use std::fmt; + use url::Url; + use values::{computed, LocalToCss}; + #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub enum T { + Image(computed::Image), + Url(Url, computed::UrlExtraData), + None + } + + impl ToCss for T { + fn to_css(&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), + T::Url(ref url, _) => url.to_css(dest), + } + } + } + } + + impl NoViewportPercentage for SpecifiedValue {} + + #[derive(Debug, Clone, PartialEq)] + #[cfg_attr(feature = "servo", derive(HeapSizeOf))] + pub enum SpecifiedValue { + Image(Image), + Url(Url, UrlExtraData), + None + } + + impl ToCss for SpecifiedValue { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + match *self { + SpecifiedValue::Image(ref image) => image.to_css(dest), + SpecifiedValue::Url(ref url, _) => url.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 { + 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, data) => { + if url.fragment().is_some() { + Ok(SpecifiedValue::Url(url, data)) + } else { + Ok(SpecifiedValue::Image(Image::Url(url, data))) + } + } + 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)), + SpecifiedValue::Url(ref url, ref data) => + computed_value::T::Url(url.clone(), data.clone()), + } + } + } + diff --git a/components/style/properties/properties.mako.rs b/components/style/properties/properties.mako.rs index 6cbb487b309..f2f8fbd2b66 100644 --- a/components/style/properties/properties.mako.rs +++ b/components/style/properties/properties.mako.rs @@ -2060,6 +2060,7 @@ pub fn cascade(viewport_size: Size2D, % if product == "gecko": style.mutate_background().fill_arrays(); + style.mutate_svg().fill_arrays(); % endif // The initial value of outline width may be changed at computed value time. diff --git a/components/style/values/computed/mod.rs b/components/style/values/computed/mod.rs index 7abdf9fa1ac..ddaa0c66ee8 100644 --- a/components/style/values/computed/mod.rs +++ b/components/style/values/computed/mod.rs @@ -537,6 +537,18 @@ impl fmt::Debug for Image { } } +impl ::cssparser::ToCss for Image { + fn to_css(&self, dest: &mut W) -> fmt::Result where W: fmt::Write { + use values::LocalToCss; + match *self { + Image::Url(ref url, _) => { + url.to_css(dest) + } + Image::LinearGradient(ref gradient) => gradient.to_css(dest) + } + } +} + /// Computed values for a CSS linear gradient. #[derive(Clone, PartialEq)] #[cfg_attr(feature = "servo", derive(HeapSizeOf))] diff --git a/ports/geckolib/gecko_bindings/bindings.rs b/ports/geckolib/gecko_bindings/bindings.rs index 54fc98b6287..d9a863b7e89 100644 --- a/ports/geckolib/gecko_bindings/bindings.rs +++ b/ports/geckolib/gecko_bindings/bindings.rs @@ -388,6 +388,8 @@ extern "C" { -> *mut StyleBasicShape; pub fn Gecko_FillAllBackgroundLists(layers: *mut nsStyleImageLayers, max_len: u32); + pub fn Gecko_FillAllMaskLists(layers: *mut nsStyleImageLayers, + max_len: u32); pub fn Gecko_AddRefCalcArbitraryThread(aPtr: *mut Calc); pub fn Gecko_ReleaseCalcArbitraryThread(aPtr: *mut Calc); pub fn Gecko_NewCSSShadowArray(len: u32) -> *mut nsCSSShadowArray;