From d0619a7c5c436fb39f298730edf1a3d933741b4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Naz=C4=B1m=20Can=20Alt=C4=B1nova?= Date: Wed, 12 Apr 2017 16:06:03 +0300 Subject: [PATCH] stylo: Implement shape-outside property --- components/style/gecko/conversions.rs | 17 +- components/style/gecko_bindings/bindings.rs | 10 +- components/style/properties/gecko.mako.rs | 226 +++++++++--------- .../style/properties/longhand/box.mako.rs | 27 +++ 4 files changed, 162 insertions(+), 118 deletions(-) diff --git a/components/style/gecko/conversions.rs b/components/style/gecko/conversions.rs index 573bb5e0070..3531f35b9b2 100644 --- a/components/style/gecko/conversions.rs +++ b/components/style/gecko/conversions.rs @@ -463,14 +463,23 @@ pub mod basic_shape { } } + impl From for StyleGeometryBox { + fn from(reference: ShapeBox) -> Self { + use gecko_bindings::structs::StyleGeometryBox::*; + match reference { + ShapeBox::ContentBox => ContentBox, + ShapeBox::PaddingBox => PaddingBox, + ShapeBox::BorderBox => BorderBox, + ShapeBox::MarginBox => MarginBox, + } + } + } + impl From for StyleGeometryBox { fn from(reference: GeometryBox) -> Self { use gecko_bindings::structs::StyleGeometryBox::*; match reference { - GeometryBox::ShapeBox(ShapeBox::ContentBox) => ContentBox, - GeometryBox::ShapeBox(ShapeBox::PaddingBox) => PaddingBox, - GeometryBox::ShapeBox(ShapeBox::BorderBox) => BorderBox, - GeometryBox::ShapeBox(ShapeBox::MarginBox) => MarginBox, + GeometryBox::ShapeBox(shape_box) => From::from(shape_box), GeometryBox::FillBox => FillBox, GeometryBox::StrokeBox => StrokeBox, GeometryBox::ViewBox => ViewBox, diff --git a/components/style/gecko_bindings/bindings.rs b/components/style/gecko_bindings/bindings.rs index cabc1ab4af6..4fb7b8c8686 100644 --- a/components/style/gecko_bindings/bindings.rs +++ b/components/style/gecko_bindings/bindings.rs @@ -890,19 +890,19 @@ extern "C" { calc: nsStyleCoord_CalcValue); } extern "C" { - pub fn Gecko_CopyClipPathValueFrom(dst: *mut StyleShapeSource, - src: *const StyleShapeSource); + pub fn Gecko_CopyShapeSourceFrom(dst: *mut StyleShapeSource, + src: *const StyleShapeSource); } extern "C" { - pub fn Gecko_DestroyClipPath(clip: *mut StyleShapeSource); + pub fn Gecko_DestroyShapeSource(shape: *mut StyleShapeSource); } extern "C" { pub fn Gecko_NewBasicShape(type_: StyleBasicShapeType) -> *mut StyleBasicShape; } extern "C" { - pub fn Gecko_StyleClipPath_SetURLValue(clip: *mut StyleShapeSource, - uri: ServoBundledURI); + pub fn Gecko_StyleShapeSource_SetURLValue(shape: *mut StyleShapeSource, + uri: ServoBundledURI); } extern "C" { pub fn Gecko_ResetFilters(effects: *mut nsStyleEffects, new_len: usize); diff --git a/components/style/properties/gecko.mako.rs b/components/style/properties/gecko.mako.rs index 63f4a5abbfa..3687fd56981 100644 --- a/components/style/properties/gecko.mako.rs +++ b/components/style/properties/gecko.mako.rs @@ -1529,7 +1529,8 @@ fn static_assert() { page-break-before page-break-after scroll-snap-points-x scroll-snap-points-y transform scroll-snap-type-y scroll-snap-coordinate - perspective-origin transform-origin -moz-binding will-change""" %> + perspective-origin transform-origin -moz-binding will-change + shape-outside""" %> <%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}"> // We manually-implement the |display| property until we get general @@ -2110,6 +2111,8 @@ fn static_assert() { Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko as *const _ as *mut _); } } + + <% impl_shape_source("shape_outside", "mShapeOutside") %> <%def name="simple_image_array_property(name, shorthand, field_name)"> @@ -3136,6 +3139,118 @@ fn static_assert() { } +<%def name="impl_shape_source(ident, gecko_ffi_name)"> + pub fn set_${ident}(&mut self, v: longhands::${ident}::computed_value::T) { + use gecko_bindings::bindings::{Gecko_NewBasicShape, Gecko_DestroyShapeSource}; + use gecko_bindings::structs::StyleGeometryBox; + use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType}; + use gecko_bindings::structs::{StyleFillRule, StyleShapeSource}; + use gecko::conversions::basic_shape::set_corners_from_radius; + use gecko::values::GeckoStyleCoordConvertible; + use values::computed::basic_shape::*; + let ref mut ${ident} = self.gecko.${gecko_ffi_name}; + // clean up existing struct + unsafe { Gecko_DestroyShapeSource(${ident}) }; + + ${ident}.mType = StyleShapeSourceType::None; + + match v { + ShapeSource::Url(ref url) => { + unsafe { + bindings::Gecko_StyleShapeSource_SetURLValue(${ident}, url.for_ffi()); + } + } + ShapeSource::None => {} // don't change the type + ShapeSource::Box(reference) => { + ${ident}.mReferenceBox = reference.into(); + ${ident}.mType = StyleShapeSourceType::Box; + } + ShapeSource::Shape(servo_shape, maybe_box) => { + ${ident}.mReferenceBox = maybe_box.map(Into::into) + .unwrap_or(StyleGeometryBox::NoBox); + ${ident}.mType = StyleShapeSourceType::Shape; + + fn init_shape(${ident}: &mut StyleShapeSource, ty: StyleBasicShapeType) -> &mut StyleBasicShape { + unsafe { + // We have to be very careful to avoid a copy here! + let ref mut union = ${ident}.__bindgen_anon_1; + let mut shape: &mut *mut StyleBasicShape = union.mBasicShape.as_mut(); + *shape = Gecko_NewBasicShape(ty); + &mut **shape + } + } + match servo_shape { + BasicShape::Inset(rect) => { + let mut shape = init_shape(${ident}, StyleBasicShapeType::Inset); + unsafe { shape.mCoordinates.set_len(4) }; + + // set_len() can't call constructors, so the coordinates + // can contain any value. set_value() attempts to free + // allocated coordinates, so we don't want to feed it + // garbage values which it may misinterpret. + // Instead, we use leaky_set_value to blindly overwrite + // the garbage data without + // attempting to clean up. + shape.mCoordinates[0].leaky_set_null(); + rect.top.to_gecko_style_coord(&mut shape.mCoordinates[0]); + shape.mCoordinates[1].leaky_set_null(); + rect.right.to_gecko_style_coord(&mut shape.mCoordinates[1]); + shape.mCoordinates[2].leaky_set_null(); + rect.bottom.to_gecko_style_coord(&mut shape.mCoordinates[2]); + shape.mCoordinates[3].leaky_set_null(); + rect.left.to_gecko_style_coord(&mut shape.mCoordinates[3]); + + set_corners_from_radius(rect.round, &mut shape.mRadius); + } + BasicShape::Circle(circ) => { + let mut shape = init_shape(${ident}, StyleBasicShapeType::Circle); + unsafe { shape.mCoordinates.set_len(1) }; + shape.mCoordinates[0].leaky_set_null(); + circ.radius.to_gecko_style_coord(&mut shape.mCoordinates[0]); + + shape.mPosition = circ.position.into(); + } + BasicShape::Ellipse(el) => { + let mut shape = init_shape(${ident}, StyleBasicShapeType::Ellipse); + unsafe { shape.mCoordinates.set_len(2) }; + shape.mCoordinates[0].leaky_set_null(); + el.semiaxis_x.to_gecko_style_coord(&mut shape.mCoordinates[0]); + shape.mCoordinates[1].leaky_set_null(); + el.semiaxis_y.to_gecko_style_coord(&mut shape.mCoordinates[1]); + + shape.mPosition = el.position.into(); + } + BasicShape::Polygon(poly) => { + let mut shape = init_shape(${ident}, StyleBasicShapeType::Polygon); + unsafe { + shape.mCoordinates.set_len(poly.coordinates.len() as u32 * 2); + } + for (i, coord) in poly.coordinates.iter().enumerate() { + shape.mCoordinates[2 * i].leaky_set_null(); + shape.mCoordinates[2 * i + 1].leaky_set_null(); + coord.0.to_gecko_style_coord(&mut shape.mCoordinates[2 * i]); + coord.1.to_gecko_style_coord(&mut shape.mCoordinates[2 * i + 1]); + } + shape.mFillRule = if poly.fill == FillRule::EvenOdd { + StyleFillRule::Evenodd + } else { + StyleFillRule::Nonzero + }; + } + } + } + } + + } + + pub fn copy_${ident}_from(&mut self, other: &Self) { + use gecko_bindings::bindings::Gecko_CopyShapeSourceFrom; + unsafe { + Gecko_CopyShapeSourceFrom(&mut self.gecko.${gecko_ffi_name}, &other.gecko.${gecko_ffi_name}); + } + } + + <% skip_svg_longhands = """ mask-mode mask-repeat mask-clip mask-origin mask-composite mask-position-x mask-position-y mask-size mask-image clip-path @@ -3166,115 +3281,8 @@ clip-path 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::StyleGeometryBox; - use gecko_bindings::structs::{StyleBasicShape, StyleBasicShapeType, StyleShapeSourceType}; - use gecko_bindings::structs::{StyleFillRule, StyleShapeSource}; - use gecko::conversions::basic_shape::set_corners_from_radius; - use gecko::values::GeckoStyleCoordConvertible; - use values::computed::basic_shape::*; - let ref mut clip_path = self.gecko.mClipPath; - // clean up existing struct - unsafe { Gecko_DestroyClipPath(clip_path) }; - clip_path.mType = StyleShapeSourceType::None; - - match v { - ShapeSource::Url(ref url) => { - unsafe { - bindings::Gecko_StyleClipPath_SetURLValue(clip_path, url.for_ffi()); - } - } - ShapeSource::None => {} // don't change the type - ShapeSource::Box(reference) => { - clip_path.mReferenceBox = reference.into(); - clip_path.mType = StyleShapeSourceType::Box; - } - ShapeSource::Shape(servo_shape, maybe_box) => { - clip_path.mReferenceBox = maybe_box.map(Into::into) - .unwrap_or(StyleGeometryBox::NoBox); - clip_path.mType = StyleShapeSourceType::Shape; - - fn init_shape(clip_path: &mut StyleShapeSource, ty: StyleBasicShapeType) -> &mut StyleBasicShape { - unsafe { - // We have to be very careful to avoid a copy here! - let ref mut union = clip_path.__bindgen_anon_1; - let mut shape: &mut *mut StyleBasicShape = union.mBasicShape.as_mut(); - *shape = Gecko_NewBasicShape(ty); - &mut **shape - } - } - match servo_shape { - BasicShape::Inset(rect) => { - let mut shape = init_shape(clip_path, StyleBasicShapeType::Inset); - unsafe { shape.mCoordinates.set_len(4) }; - - // set_len() can't call constructors, so the coordinates - // can contain any value. set_value() attempts to free - // allocated coordinates, so we don't want to feed it - // garbage values which it may misinterpret. - // Instead, we use leaky_set_value to blindly overwrite - // the garbage data without - // attempting to clean up. - shape.mCoordinates[0].leaky_set_null(); - rect.top.to_gecko_style_coord(&mut shape.mCoordinates[0]); - shape.mCoordinates[1].leaky_set_null(); - rect.right.to_gecko_style_coord(&mut shape.mCoordinates[1]); - shape.mCoordinates[2].leaky_set_null(); - rect.bottom.to_gecko_style_coord(&mut shape.mCoordinates[2]); - shape.mCoordinates[3].leaky_set_null(); - rect.left.to_gecko_style_coord(&mut shape.mCoordinates[3]); - - set_corners_from_radius(rect.round, &mut shape.mRadius); - } - BasicShape::Circle(circ) => { - let mut shape = init_shape(clip_path, StyleBasicShapeType::Circle); - unsafe { shape.mCoordinates.set_len(1) }; - shape.mCoordinates[0].leaky_set_null(); - circ.radius.to_gecko_style_coord(&mut shape.mCoordinates[0]); - - shape.mPosition = circ.position.into(); - } - BasicShape::Ellipse(el) => { - let mut shape = init_shape(clip_path, StyleBasicShapeType::Ellipse); - unsafe { shape.mCoordinates.set_len(2) }; - shape.mCoordinates[0].leaky_set_null(); - el.semiaxis_x.to_gecko_style_coord(&mut shape.mCoordinates[0]); - shape.mCoordinates[1].leaky_set_null(); - el.semiaxis_y.to_gecko_style_coord(&mut shape.mCoordinates[1]); - - shape.mPosition = el.position.into(); - } - BasicShape::Polygon(poly) => { - let mut shape = init_shape(clip_path, StyleBasicShapeType::Polygon); - unsafe { - shape.mCoordinates.set_len(poly.coordinates.len() as u32 * 2); - } - for (i, coord) in poly.coordinates.iter().enumerate() { - shape.mCoordinates[2 * i].leaky_set_null(); - shape.mCoordinates[2 * i + 1].leaky_set_null(); - coord.0.to_gecko_style_coord(&mut shape.mCoordinates[2 * i]); - coord.1.to_gecko_style_coord(&mut shape.mCoordinates[2 * i + 1]); - } - shape.mFillRule = if poly.fill == FillRule::EvenOdd { - StyleFillRule::Evenodd - } else { - StyleFillRule::Nonzero - }; - } - } - } - } - - } - - pub fn copy_clip_path_from(&mut self, other: &Self) { - use gecko_bindings::bindings::Gecko_CopyClipPathValueFrom; - unsafe { - Gecko_CopyClipPathValueFrom(&mut self.gecko.mClipPath, &other.gecko.mClipPath); - } - } + <% impl_shape_source("clip_path", "mClipPath") %> <%self:impl_trait style_struct_name="InheritedSVG" diff --git a/components/style/properties/longhand/box.mako.rs b/components/style/properties/longhand/box.mako.rs index ffa8c5ebddf..586658ebadc 100644 --- a/components/style/properties/longhand/box.mako.rs +++ b/components/style/properties/longhand/box.mako.rs @@ -2298,3 +2298,30 @@ ${helpers.single_keyword("-moz-orient", } } + +<%helpers:longhand name="shape-outside" products="gecko" animation_type="none" boxed="True" + spec="https://drafts.csswg.org/css-shapes/#shape-outside-property"> + use std::fmt; + use style_traits::ToCss; + use values::specified::basic_shape::{ShapeBox, ShapeSource}; + use values::HasViewportPercentage; + + no_viewport_percentage!(SpecifiedValue); + + pub mod computed_value { + use values::computed::basic_shape::{ShapeBox, ShapeSource}; + + pub type T = ShapeSource; + } + + pub type SpecifiedValue = ShapeSource; + + #[inline] + pub fn get_initial_value() -> computed_value::T { + Default::default() + } + + pub fn parse(context: &ParserContext, input: &mut Parser) -> Result { + ShapeSource::parse(context, input) + } +