layout: Add initial support for clip-path: [<basic-shape> || <shape-box>] (#33107)

* Turn on clip-path tests and add results

Signed-off-by: Martin Robinson <mrobinson@igalia.com>

* enhance: Add support for `clip-path: [<basic-shape> || <shape-box>]`

Signed-off-by: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com>

* Changes from review

Signed-off-by: Martin Robinson <mrobinson@igalia.com>

---------

Signed-off-by: Martin Robinson <mrobinson@igalia.com>
Signed-off-by: Chocolate Pie <106949016+chocolate-pie@users.noreply.github.com>
Co-authored-by: Martin Robinson <mrobinson@igalia.com>
This commit is contained in:
Chocolate Pie 2024-08-29 00:00:34 +09:00 committed by GitHub
parent f810983fd2
commit 590527176e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
56 changed files with 450 additions and 89 deletions

28
Cargo.lock generated
View file

@ -1283,7 +1283,7 @@ dependencies = [
[[package]]
name = "derive_common"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"darling",
"proc-macro2",
@ -1472,7 +1472,7 @@ dependencies = [
[[package]]
name = "dom"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"bitflags 2.6.0",
]
@ -4083,7 +4083,7 @@ dependencies = [
[[package]]
name = "malloc_size_of"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"accountable-refcell",
"app_units",
@ -5777,7 +5777,7 @@ checksum = "0495e4577c672de8254beb68d01a9b62d0e8a13c099edecdbedccce3223cd29f"
[[package]]
name = "selectors"
version = "0.24.0"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"bitflags 2.6.0",
"cssparser",
@ -6091,7 +6091,7 @@ dependencies = [
[[package]]
name = "servo_arc"
version = "0.2.0"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"serde",
"stable_deref_trait",
@ -6100,7 +6100,7 @@ dependencies = [
[[package]]
name = "servo_atoms"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"string_cache",
"string_cache_codegen",
@ -6304,7 +6304,7 @@ checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
[[package]]
name = "size_of_test"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"static_assertions",
]
@ -6445,7 +6445,7 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "static_prefs"
version = "0.1.0"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
[[package]]
name = "strck"
@ -6498,7 +6498,7 @@ dependencies = [
[[package]]
name = "style"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"app_units",
"arrayvec",
@ -6557,7 +6557,7 @@ dependencies = [
[[package]]
name = "style_config"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"lazy_static",
]
@ -6565,7 +6565,7 @@ dependencies = [
[[package]]
name = "style_derive"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"darling",
"derive_common",
@ -6596,7 +6596,7 @@ dependencies = [
[[package]]
name = "style_traits"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"app_units",
"bitflags 2.6.0",
@ -6945,7 +6945,7 @@ dependencies = [
[[package]]
name = "to_shmem"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"cssparser",
"servo_arc",
@ -6958,7 +6958,7 @@ dependencies = [
[[package]]
name = "to_shmem_derive"
version = "0.0.1"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#3359447b53f0d0bc4affe135313ca8d0e48cb876"
source = "git+https://github.com/servo/stylo?branch=2024-07-16#65f8d1316a0966401bcfb9fa7dd5e3659a1605b2"
dependencies = [
"darling",
"derive_common",

View file

@ -0,0 +1,242 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
use style::values::computed::basic_shape::{BasicShape, ClipPath};
use style::values::computed::length::Length;
use style::values::computed::length_percentage::{LengthPercentage, NonNegativeLengthPercentage};
use style::values::computed::position::Position;
use style::values::generics::basic_shape::{GenericShapeRadius, ShapeBox, ShapeGeometryBox};
use style::values::generics::position::GenericPositionOrAuto;
use webrender_api::units::{LayoutRect, LayoutSideOffsets, LayoutSize};
use webrender_api::ClipChainId;
use webrender_traits::display_list::ScrollTreeNodeId;
use super::{compute_margin_box_radius, normalize_radii, BuilderForBoxFragment, DisplayList};
pub(super) fn build_clip_path_clip_chain_if_necessary(
clip_path: ClipPath,
display_list: &mut DisplayList,
parent_scroll_node_id: &ScrollTreeNodeId,
parent_clip_chain_id: &ClipChainId,
fragment_builder: BuilderForBoxFragment,
) -> Option<ClipChainId> {
let geometry_box = match clip_path {
ClipPath::Shape(_, ShapeGeometryBox::ShapeBox(shape_box)) => shape_box,
ClipPath::Shape(_, ShapeGeometryBox::ElementDependent) => ShapeBox::BorderBox,
ClipPath::Box(ShapeGeometryBox::ShapeBox(shape_box)) => shape_box,
ClipPath::Box(ShapeGeometryBox::ElementDependent) => ShapeBox::BorderBox,
_ => return None,
};
let layout_rect = match geometry_box {
ShapeBox::BorderBox => fragment_builder.border_rect,
ShapeBox::ContentBox => *fragment_builder.content_rect(),
ShapeBox::PaddingBox => *fragment_builder.padding_rect(),
ShapeBox::MarginBox => *fragment_builder.margin_rect(),
};
if let ClipPath::Shape(shape, _) = clip_path {
match *shape {
BasicShape::Circle(_) | BasicShape::Ellipse(_) | BasicShape::Rect(_) => {
build_simple_shape(
*shape,
layout_rect,
parent_scroll_node_id,
parent_clip_chain_id,
display_list,
)
},
BasicShape::Polygon(_) | BasicShape::PathOrShape(_) => None,
}
} else {
Some(create_rect_clip_chain(
match geometry_box {
ShapeBox::MarginBox => compute_margin_box_radius(
fragment_builder.border_radius,
layout_rect.size(),
fragment_builder.fragment,
),
_ => fragment_builder.border_radius,
},
layout_rect,
parent_scroll_node_id,
parent_clip_chain_id,
display_list,
))
}
}
fn build_simple_shape(
shape: BasicShape,
layout_box: LayoutRect,
parent_scroll_node_id: &ScrollTreeNodeId,
parent_clip_chain_id: &ClipChainId,
display_list: &mut DisplayList,
) -> Option<ClipChainId> {
match shape {
BasicShape::Rect(rect) => {
let insets = LayoutSideOffsets::new(
rect.rect.0.resolve(Length::new(layout_box.height())).px(),
rect.rect.1.resolve(Length::new(layout_box.width())).px(),
rect.rect.2.resolve(Length::new(layout_box.height())).px(),
rect.rect.3.resolve(Length::new(layout_box.width())).px(),
);
// `inner_rect()` will cause an assertion failure if the insets are larger than the
// rectangle dimension.
let shape_rect = if insets.left + insets.right >= layout_box.width() ||
insets.top + insets.bottom > layout_box.height()
{
LayoutRect::from_origin_and_size(layout_box.min, LayoutSize::zero())
} else {
layout_box.to_rect().inner_rect(insets).to_box2d()
};
let resolve = |radius: &LengthPercentage, box_size: f32| {
radius.percentage_relative_to(Length::new(box_size)).px()
};
let corner = |corner: &style::values::computed::BorderCornerRadius| {
LayoutSize::new(
resolve(&corner.0.width.0, layout_box.size().width),
resolve(&corner.0.height.0, layout_box.size().height),
)
};
let mut radii = webrender_api::BorderRadius {
top_left: corner(&rect.round.top_left),
top_right: corner(&rect.round.top_right),
bottom_left: corner(&rect.round.bottom_left),
bottom_right: corner(&rect.round.bottom_right),
};
normalize_radii(&layout_box, &mut radii);
Some(create_rect_clip_chain(
radii,
shape_rect,
parent_scroll_node_id,
parent_clip_chain_id,
display_list,
))
},
BasicShape::Circle(circle) => {
let center = match circle.position {
GenericPositionOrAuto::Position(position) => position,
GenericPositionOrAuto::Auto => Position::center(),
};
let anchor_x = center.horizontal.resolve(Length::new(layout_box.width()));
let anchor_y = center.vertical.resolve(Length::new(layout_box.height()));
let center = layout_box
.min
.add_size(&LayoutSize::new(anchor_x.px(), anchor_y.px()));
let horizontal =
compute_shape_radius(center.x, &circle.radius, layout_box.min.x, layout_box.max.x);
let vertical =
compute_shape_radius(center.y, &circle.radius, layout_box.min.y, layout_box.max.y);
// If the value is `Length` then both values should be the same at this point.
let radius = match circle.radius {
GenericShapeRadius::FarthestSide => horizontal.max(vertical),
GenericShapeRadius::ClosestSide => horizontal.min(vertical),
GenericShapeRadius::Length(_) => horizontal,
};
let radius = LayoutSize::new(radius, radius);
let mut radii = webrender_api::BorderRadius {
top_left: radius,
top_right: radius,
bottom_left: radius,
bottom_right: radius,
};
let start = center.add_size(&-radius);
let rect = LayoutRect::from_origin_and_size(start, radius * 2.);
normalize_radii(&layout_box, &mut radii);
Some(create_rect_clip_chain(
radii,
rect,
parent_scroll_node_id,
parent_clip_chain_id,
display_list,
))
},
BasicShape::Ellipse(ellipse) => {
let center = match ellipse.position {
GenericPositionOrAuto::Position(position) => position,
GenericPositionOrAuto::Auto => Position::center(),
};
let anchor_x = center.horizontal.resolve(Length::new(layout_box.width()));
let anchor_y = center.vertical.resolve(Length::new(layout_box.height()));
let center = layout_box
.min
.add_size(&LayoutSize::new(anchor_x.px(), anchor_y.px()));
let width = compute_shape_radius(
center.x,
&ellipse.semiaxis_x,
layout_box.min.x,
layout_box.max.x,
);
let height = compute_shape_radius(
center.y,
&ellipse.semiaxis_y,
layout_box.min.y,
layout_box.max.y,
);
let mut radii = webrender_api::BorderRadius {
top_left: LayoutSize::new(width, height),
top_right: LayoutSize::new(width, height),
bottom_left: LayoutSize::new(width, height),
bottom_right: LayoutSize::new(width, height),
};
let size = LayoutSize::new(width, height);
let start = center.add_size(&-size);
let rect = LayoutRect::from_origin_and_size(start, size * 2.);
normalize_radii(&rect, &mut radii);
Some(create_rect_clip_chain(
radii,
rect,
parent_scroll_node_id,
parent_clip_chain_id,
display_list,
))
},
_ => None,
}
}
fn compute_shape_radius(
center: f32,
radius: &GenericShapeRadius<NonNegativeLengthPercentage>,
min_edge: f32,
max_edge: f32,
) -> f32 {
let distance_from_min_edge = (min_edge - center).abs();
let distance_from_max_edge = (max_edge - center).abs();
match radius {
GenericShapeRadius::FarthestSide => distance_from_min_edge.max(distance_from_max_edge),
GenericShapeRadius::ClosestSide => distance_from_min_edge.min(distance_from_max_edge),
GenericShapeRadius::Length(length) => {
length.0.resolve(Length::new(max_edge - min_edge)).px()
},
}
}
fn create_rect_clip_chain(
radii: webrender_api::BorderRadius,
rect: LayoutRect,
parent_scroll_node_id: &ScrollTreeNodeId,
parent_clip_chain_id: &ClipChainId,
display_list: &mut DisplayList,
) -> ClipChainId {
let new_clip_id = if radii.is_zero() {
display_list
.wr
.define_clip_rect(parent_scroll_node_id.spatial_id, rect)
} else {
display_list.wr.define_clip_rounded_rect(
parent_scroll_node_id.spatial_id,
webrender_api::ComplexClipRegion {
rect,
radii,
mode: webrender_api::ClipMode::Clip,
},
)
};
display_list.define_clip_chain(*parent_clip_chain_id, [new_clip_id])
}

View file

@ -25,14 +25,15 @@ use style::properties::ComputedValues;
use style::values::computed::image::Image;
use style::values::computed::{
BorderImageSideWidth, BorderImageWidth, BorderStyle, Color, Length, LengthPercentage,
NonNegativeLengthOrNumber, NumberOrPercentage, OutlineStyle,
LengthPercentageOrAuto, NonNegativeLengthOrNumber, NumberOrPercentage, OutlineStyle,
};
use style::values::generics::rect::Rect;
use style::values::generics::NonNegative;
use style::values::specified::text::TextDecorationLine;
use style::values::specified::ui::CursorKind;
use style::Zero;
use style_traits::{CSSPixel, DevicePixel};
use webrender_api::units::LayoutPixel;
use webrender_api::units::{LayoutPixel, LayoutSize};
use webrender_api::{
self as wr, units, BorderDetails, BoxShadowClipMode, ClipChainId, CommonItemProperties,
ImageRendering, NinePatchBorder, NinePatchBorderSource,
@ -53,6 +54,7 @@ use crate::replaced::IntrinsicSizes;
use crate::style_ext::ComputedValuesExt;
mod background;
mod clip_path;
mod conversions;
mod gradient;
mod stacking_context;
@ -482,6 +484,7 @@ struct BuilderForBoxFragment<'a> {
fragment: &'a BoxFragment,
containing_block: &'a PhysicalRect<Au>,
border_rect: units::LayoutRect,
margin_rect: OnceCell<units::LayoutRect>,
padding_rect: OnceCell<units::LayoutRect>,
content_rect: OnceCell<units::LayoutRect>,
border_radius: wr::BorderRadius,
@ -514,23 +517,7 @@ impl<'a> BuilderForBoxFragment<'a> {
bottom_right: corner(&b.border_bottom_right_radius),
bottom_left: corner(&b.border_bottom_left_radius),
};
// Normalize radii that add up to > 100%.
// https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
// > Let f = min(L_i/S_i), where i ∈ {top, right, bottom, left},
// > S_i is the sum of the two corresponding radii of the corners on side i,
// > and L_top = L_bottom = the width of the box,
// > and L_left = L_right = the height of the box.
// > If f < 1, then all corner radii are reduced by multiplying them by f.
let f = (border_rect.width() / (radius.top_left.width + radius.top_right.width))
.min(border_rect.width() / (radius.bottom_left.width + radius.bottom_right.width))
.min(border_rect.height() / (radius.top_left.height + radius.bottom_left.height))
.min(border_rect.height() / (radius.top_right.height + radius.bottom_right.height));
if f < 1.0 {
radius.top_left *= f;
radius.top_right *= f;
radius.bottom_right *= f;
radius.bottom_left *= f;
}
normalize_radii(&border_rect, &mut radius);
radius
};
@ -539,6 +526,7 @@ impl<'a> BuilderForBoxFragment<'a> {
containing_block,
border_rect,
border_radius,
margin_rect: OnceCell::new(),
padding_rect: OnceCell::new(),
content_rect: OnceCell::new(),
border_edge_clip_chain_id: RefCell::new(None),
@ -565,6 +553,15 @@ impl<'a> BuilderForBoxFragment<'a> {
})
}
fn margin_rect(&self) -> &units::LayoutRect {
self.margin_rect.get_or_init(|| {
self.fragment
.margin_rect()
.translate(self.containing_block.origin.to_vector())
.to_webrender()
})
}
fn border_edge_clip(
&self,
builder: &mut DisplayListBuilder,
@ -1300,3 +1297,84 @@ fn resolve_border_image_slice(
resolve_percentage(border_image_slice.3, size.width),
)
}
pub(super) fn normalize_radii(rect: &units::LayoutRect, radius: &mut wr::BorderRadius) {
// Normalize radii that add up to > 100%.
// https://www.w3.org/TR/css-backgrounds-3/#corner-overlap
// > Let f = min(L_i/S_i), where i ∈ {top, right, bottom, left},
// > S_i is the sum of the two corresponding radii of the corners on side i,
// > and L_top = L_bottom = the width of the box,
// > and L_left = L_right = the height of the box.
// > If f < 1, then all corner radii are reduced by multiplying them by f.
let f = (rect.width() / (radius.top_left.width + radius.top_right.width))
.min(rect.width() / (radius.bottom_left.width + radius.bottom_right.width))
.min(rect.height() / (radius.top_left.height + radius.bottom_left.height))
.min(rect.height() / (radius.top_right.height + radius.bottom_right.height));
if f < 1.0 {
radius.top_left *= f;
radius.top_right *= f;
radius.bottom_right *= f;
radius.bottom_left *= f;
}
}
/// <https://drafts.csswg.org/css-shapes-1/#valdef-shape-box-margin-box>
/// > The corner radii of this shape are determined by the corresponding
/// > border-radius and margin values. If the ratio of border-radius/margin is 1 or more,
/// > or margin is negative or zero, then the margin box corner radius is
/// > max(border-radius + margin, 0). If the ratio of border-radius/margin is less than 1,
/// > and margin is positive, then the margin box corner radius is
/// > border-radius + margin * (1 + (ratio-1)^3).
pub(super) fn compute_margin_box_radius(
radius: wr::BorderRadius,
layout_rect: LayoutSize,
fragment: &BoxFragment,
) -> wr::BorderRadius {
let margin = fragment.style.get_margin();
let adjust_radius = |radius: f32, margin: f32| -> f32 {
if margin <= 0. || (radius / margin) >= 1. {
(radius + margin).max(0.)
} else {
radius + (margin * (1. + (radius / margin - 1.).powf(3.)))
}
};
let compute_margin_radius = |radius: LayoutSize,
layout_rect: LayoutSize,
margin: Size2D<LengthPercentageOrAuto, UnknownUnit>|
-> LayoutSize {
let width = margin
.width
.auto_is(LengthPercentage::zero)
.resolve(Length::new(layout_rect.width));
let height = margin
.height
.auto_is(LengthPercentage::zero)
.resolve(Length::new(layout_rect.height));
LayoutSize::new(
adjust_radius(radius.width, width.px()),
adjust_radius(radius.height, height.px()),
)
};
wr::BorderRadius {
top_left: compute_margin_radius(
radius.top_left,
layout_rect,
Size2D::new(margin.margin_left.clone(), margin.margin_top.clone()),
),
top_right: compute_margin_radius(
radius.top_right,
layout_rect,
Size2D::new(margin.margin_right.clone(), margin.margin_top.clone()),
),
bottom_left: compute_margin_radius(
radius.bottom_left,
layout_rect,
Size2D::new(margin.margin_left.clone(), margin.margin_bottom.clone()),
),
bottom_right: compute_margin_radius(
radius.bottom_right,
layout_rect,
Size2D::new(margin.margin_right.clone(), margin.margin_bottom.clone()),
),
}
}

View file

@ -17,6 +17,7 @@ use style::computed_values::mix_blend_mode::T as ComputedMixBlendMode;
use style::computed_values::overflow_x::T as ComputedOverflow;
use style::computed_values::position::T as ComputedPosition;
use style::properties::ComputedValues;
use style::values::computed::basic_shape::ClipPath;
use style::values::computed::{ClipRectOrAuto, Length};
use style::values::generics::box_::Perspective;
use style::values::generics::transform;
@ -28,10 +29,11 @@ use webrender_traits::display_list::{ScrollSensitivity, ScrollTreeNodeId, Scroll
use wr::units::{LayoutPixel, LayoutSize};
use wr::{ClipChainId, SpatialTreeItemKey, StickyOffsetBounds};
use super::clip_path::build_clip_path_clip_chain_if_necessary;
use super::DisplayList;
use crate::cell::ArcRefCell;
use crate::display_list::conversions::{FilterToWebRender, ToWebRender};
use crate::display_list::DisplayListBuilder;
use crate::display_list::{BuilderForBoxFragment, DisplayListBuilder};
use crate::fragment_tree::{
BoxFragment, ContainingBlockManager, Fragment, FragmentFlags, FragmentTree, PositioningFragment,
};
@ -488,7 +490,8 @@ impl StackingContext {
if effects.filter.0.is_empty() &&
effects.opacity == 1.0 &&
effects.mix_blend_mode == ComputedMixBlendMode::Normal &&
!style.has_transform_or_perspective(FragmentFlags::empty())
!style.has_transform_or_perspective(FragmentFlags::empty()) &&
style.clone_clip_path() == ClipPath::None
{
return false;
}
@ -654,8 +657,7 @@ impl StackingContext {
}
}
let mut fragment_builder =
super::BuilderForBoxFragment::new(box_fragment, containing_block);
let mut fragment_builder = BuilderForBoxFragment::new(box_fragment, containing_block);
let painter = super::background::BackgroundPainter {
style,
painting_area_override: Some(painting_area),
@ -1059,9 +1061,21 @@ impl BoxFragment {
);
}
// `clip-path` needs to be applied before filters and creates a stacking context, so it can be
// applied directly to the stacking context itself.
// before
let stacking_context_clip_chain_id = build_clip_path_clip_chain_if_necessary(
self.style.clone_clip_path(),
display_list,
&containing_block.scroll_node_id,
&containing_block.clip_chain_id,
BuilderForBoxFragment::new(self, &containing_block.rect),
)
.unwrap_or(containing_block.clip_chain_id);
let mut child_stacking_context = parent_stacking_context.create_descendant(
containing_block.scroll_node_id.spatial_id,
containing_block.clip_chain_id,
stacking_context_clip_chain_id,
self.style.clone(),
self.base.flags,
context_type,
@ -1122,6 +1136,16 @@ impl BoxFragment {
new_clip_chain_id = clip_chain_id;
}
if let Some(clip_chain_id) = build_clip_path_clip_chain_if_necessary(
self.style.clone_clip_path(),
display_list,
&new_scroll_node_id,
&new_clip_chain_id,
BuilderForBoxFragment::new(self, &containing_block.rect),
) {
new_clip_chain_id = clip_chain_id;
}
let establishes_containing_block_for_all_descendants = self
.style
.establishes_containing_block_for_all_descendants(self.base.flags);

View file

@ -13,6 +13,7 @@ use style::properties::longhands::backface_visibility::computed_value::T as Back
use style::properties::longhands::box_sizing::computed_value::T as BoxSizing;
use style::properties::longhands::column_span::computed_value::T as ColumnSpan;
use style::properties::ComputedValues;
use style::values::computed::basic_shape::ClipPath;
use style::values::computed::image::Image as ComputedImageLayer;
use style::values::computed::{Length, LengthPercentage, NonNegativeLengthPercentage, Size};
use style::values::generics::box_::Perspective;
@ -608,6 +609,10 @@ impl ComputedValuesExt for ComputedValues {
return true;
}
if self.get_svg().clip_path != ClipPath::None {
return true;
}
// Statically positioned fragments don't establish stacking contexts if the previous
// conditions are not fulfilled. Furthermore, z-index doesn't apply to statically
// positioned fragments (except for flex items, see below).

View file

@ -61,6 +61,10 @@ skip: true
[css-masking]
[clip]
skip: false
[clip-path]
skip: false
[animations]
skip: true
[css-multicol]
skip: true
[css-nesting]

View file

@ -0,0 +1,2 @@
[clip-path-blending-offset.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-borderBox-1a.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-borderBox-1c.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-001.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-002.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-003.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-004.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-005.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-006.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-007.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-circle-008.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-circle-closest-corner.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-circle-farthest-corner.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-contentBox-1a.html]
expected: FAIL

View file

@ -1,2 +1,2 @@
[clip-path-descendant-text-mutated-001.html]
expected: FAIL
expected: TIMEOUT

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-001.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-002.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-003.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-004.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-005.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-006.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-007.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-ellipse-008.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-ellipse-closest-farthest-corner.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-fillBox-1a.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-filter-order.html]
expected: FAIL

View file

@ -1,2 +0,0 @@
[clip-path-fixed-nested.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-fixed-scroll.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-foreignobject-non-zero-xy.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-geometryBox-2.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-inline-007.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-mix-blend-mode-1.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-paddingBox-1a.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-paddingBox-1c.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-path-003.html]
expected: FAIL

View file

@ -0,0 +1,3 @@
[clip-path-path-with-zoom-hittest.html]
[clip-path: path() hit-test takes zoom into account]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-path-with-zoom.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-round-zero-size.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-scaled-video.html]
expected: FAIL

View file

@ -1,2 +1,2 @@
[clip-path-scroll.html]
expected: TIMEOUT
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-shape-005.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-shape-006.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-shape-foreignobject-non-zero-xy.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-strokeBox-1a.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-svg-text-font-loading.html]
expected: TIMEOUT

View file

@ -0,0 +1,2 @@
[clip-path-url-reference-svg-foreignobject-zoomed.html]
expected: FAIL

View file

@ -0,0 +1,2 @@
[clip-path-viewBox-1c.html]
expected: FAIL

View file

@ -1,10 +0,0 @@
[interpolation.html]
[Test circle with negative easing on clip-path]
expected: FAIL
[Test ellipse with negative easing on clip-path]
expected: FAIL
[Test inset with negative easing on clip-path]
expected: FAIL

View file

@ -0,0 +1,2 @@
[svg-clip-path-fixed-values.html]
expected: FAIL

View file

@ -2,9 +2,6 @@
[Property background-blend-mode does not support quirky length]
expected: FAIL
[Property clip-path does not support quirky length]
expected: FAIL
[Property column-span does not support quirky length]
expected: FAIL