mirror of
https://github.com/servo/servo.git
synced 2025-08-03 12:40:06 +01:00
Auto merge of #16384 - canaltinova:shape-outside, r=Manishearth
stylo: Implement shape-outside property shape-outside property implemented. r=Manishearth in bugzilla --- <!-- Thank you for contributing to Servo! Please replace each `[ ]` by `[X]` when the step is complete, and replace `__` with appropriate data: --> - [X] `./mach build -d` does not report any errors - [X] `./mach test-tidy` does not report any errors - [X] These changes fix #15958 and [Bug 1355003](https://bugzilla.mozilla.org/show_bug.cgi?id=1355003) <!-- Also, please make sure that "Allow edits from maintainers" checkbox is checked, so that we can help you if you get stuck somewhere along the way.--> <!-- Pull requests that do not address these steps are welcome, but they will require additional verification as part of the review process. --> <!-- Reviewable:start --> --- This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/16384) <!-- Reviewable:end -->
This commit is contained in:
commit
9d5dde2604
4 changed files with 162 additions and 118 deletions
|
@ -463,14 +463,23 @@ pub mod basic_shape {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<ShapeBox> 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<GeometryBox> 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,
|
||||
|
|
|
@ -892,18 +892,18 @@ extern "C" {
|
|||
calc: nsStyleCoord_CalcValue);
|
||||
}
|
||||
extern "C" {
|
||||
pub fn Gecko_CopyClipPathValueFrom(dst: *mut 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,
|
||||
pub fn Gecko_StyleShapeSource_SetURLValue(shape: *mut StyleShapeSource,
|
||||
uri: ServoBundledURI);
|
||||
}
|
||||
extern "C" {
|
||||
|
|
|
@ -1548,7 +1548,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
|
||||
|
@ -2142,6 +2143,8 @@ fn static_assert() {
|
|||
Gecko_CopyWillChangeFrom(&mut self.gecko, &other.gecko as *const _ as *mut _);
|
||||
}
|
||||
}
|
||||
|
||||
<% impl_shape_source("shape_outside", "mShapeOutside") %>
|
||||
</%self:impl_trait>
|
||||
|
||||
<%def name="simple_image_array_property(name, shorthand, field_name)">
|
||||
|
@ -3191,6 +3194,118 @@ fn static_assert() {
|
|||
}
|
||||
</%self:impl_trait>
|
||||
|
||||
<%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});
|
||||
}
|
||||
}
|
||||
</%def>
|
||||
|
||||
<% 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
|
||||
|
@ -3221,115 +3336,8 @@ clip-path
|
|||
T::exclude => structs::NS_STYLE_MASK_COMPOSITE_EXCLUDE as u8,
|
||||
}
|
||||
</%self:simple_image_array_property>
|
||||
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>
|
||||
|
||||
<%self:impl_trait style_struct_name="InheritedSVG"
|
||||
|
|
|
@ -2298,3 +2298,30 @@ ${helpers.single_keyword("-moz-orient",
|
|||
}
|
||||
}
|
||||
</%helpers:longhand>
|
||||
|
||||
<%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<ShapeBox>;
|
||||
}
|
||||
|
||||
pub type SpecifiedValue = ShapeSource<ShapeBox>;
|
||||
|
||||
#[inline]
|
||||
pub fn get_initial_value() -> computed_value::T {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
pub fn parse(context: &ParserContext, input: &mut Parser) -> Result<SpecifiedValue, ()> {
|
||||
ShapeSource::parse(context, input)
|
||||
}
|
||||
</%helpers:longhand>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue