Auto merge of #27388 - Manishearth:clip-2020, r=SimonSapin

Layout 2020: Implement `clip: rect`

This implements `clip: rect`

Unfortunately, none of the tests pass yet, they are all broken due to https://github.com/servo/servo/issues/27387

Additionally, currently `clip` does not seem to clip the element itself, only its children. I'm not quite sure what to do about that, I patterned this off of the code in the layout 2013 which handled clip immediately after scroll overflow.
This commit is contained in:
bors-servo 2020-07-28 11:44:38 -04:00 committed by GitHub
commit b41f5f97f2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
140 changed files with 5140 additions and 153 deletions

View file

@ -63,7 +63,7 @@ use style::properties::{style_structs, ComputedValues};
use style::servo::restyle_damage::ServoRestyleDamage;
use style::values::computed::effects::SimpleShadow;
use style::values::computed::image::Image;
use style::values::computed::{ClipRectOrAuto, Gradient, LengthOrAuto};
use style::values::computed::{ClipRectOrAuto, Gradient};
use style::values::generics::background::BackgroundSize;
use style::values::generics::image::PaintWorklet;
use style::values::specified::ui::CursorKind;
@ -2701,26 +2701,7 @@ impl BlockFlow {
_ => return,
}
fn extract_clip_component(p: &LengthOrAuto) -> Option<Au> {
match *p {
LengthOrAuto::Auto => None,
LengthOrAuto::LengthPercentage(ref length) => Some(Au::from(*length)),
}
}
let clip_origin = Point2D::new(
stacking_relative_border_box.origin.x +
extract_clip_component(&style_clip_rect.left).unwrap_or_default(),
stacking_relative_border_box.origin.y +
extract_clip_component(&style_clip_rect.top).unwrap_or_default(),
);
let right = extract_clip_component(&style_clip_rect.right)
.unwrap_or(stacking_relative_border_box.size.width);
let bottom = extract_clip_component(&style_clip_rect.bottom)
.unwrap_or(stacking_relative_border_box.size.height);
let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
let clip_rect = Rect::new(clip_origin, clip_size);
let clip_rect = style_clip_rect.for_border_rect(stacking_relative_border_box);
preserved_state.push_clip(state, clip_rect, self.positioning());
let new_index = state.add_clip_scroll_node(ClipScrollNode {

View file

@ -19,6 +19,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::ClipRectOrAuto;
use style::values::computed::Length;
use style::values::generics::box_::Perspective;
use style::values::generics::transform;
@ -660,6 +661,7 @@ impl BoxFragment {
containing_block_info: &ContainingBlockInfo,
stacking_context: &mut StackingContext,
) {
self.build_clip_frame_if_necessary(builder, containing_block_info);
stacking_context.fragments.push(StackingContextFragment {
space_and_clip: builder.current_space_and_clip,
section: self.get_stacking_context_section(),
@ -708,6 +710,32 @@ impl BoxFragment {
builder.current_space_and_clip.spatial_id = builder.nearest_reference_frame;
}
fn build_clip_frame_if_necessary(
&self,
builder: &mut StackingContextBuilder,
containing_block_info: &ContainingBlockInfo,
) {
let position = self.style.get_box().position;
// https://drafts.csswg.org/css2/#clipping
// The clip property applies only to absolutely positioned elements
if position == ComputedPosition::Absolute || position == ComputedPosition::Fixed {
let clip = self.style.get_effects().clip;
if let ClipRectOrAuto::Rect(r) = clip {
let border_rect = self
.border_rect()
.to_physical(self.style.writing_mode, &containing_block_info.rect);
let clip_rect = r
.for_border_rect(border_rect)
.translate(containing_block_info.rect.origin.to_vector())
.to_webrender();
let parent = builder.current_space_and_clip;
builder.current_space_and_clip.clip_id =
builder.wr.define_clip_rect(&parent, clip_rect);
}
}
}
fn build_scroll_frame_if_necessary<'a>(
&self,
builder: &mut StackingContextBuilder,
@ -715,6 +743,7 @@ impl BoxFragment {
) {
let overflow_x = self.style.get_box().overflow_x;
let overflow_y = self.style.get_box().overflow_y;
let original_scroll_and_clip_info = builder.current_space_and_clip;
if overflow_x != ComputedOverflow::Visible || overflow_y != ComputedOverflow::Visible {
let external_id = wr::ExternalScrollId(

View file

@ -38,7 +38,6 @@ ${helpers.predefined_type(
"ClipRectOrAuto",
"computed::ClipRectOrAuto::auto()",
engines="gecko servo-2013 servo-2020",
servo_2020_pref="layout.2020.unimplemented",
animation_value_type="ComputedValue",
boxed=True,
allow_quirks="Yes",

View file

@ -22,11 +22,12 @@ use crate::properties;
use crate::properties::{ComputedValues, LonghandId, StyleBuilder};
use crate::rule_cache::RuleCacheConditions;
use crate::{ArcSlice, Atom, One};
use euclid::default::Size2D;
use euclid::{default, Point2D, Rect, Size2D};
use servo_arc::Arc;
use std::cell::RefCell;
use std::cmp;
use std::f32;
use std::ops::{Add, Sub};
#[cfg(feature = "gecko")]
pub use self::align::{
@ -208,7 +209,7 @@ impl<'a> Context<'a> {
}
/// The current viewport size, used to resolve viewport units.
pub fn viewport_size_for_viewport_unit_resolution(&self) -> Size2D<Au> {
pub fn viewport_size_for_viewport_unit_resolution(&self) -> default::Size2D<Au> {
self.builder
.device
.au_viewport_size_for_viewport_unit_resolution()
@ -353,11 +354,11 @@ where
}
}
impl<T> ToComputedValue for Size2D<T>
impl<T> ToComputedValue for default::Size2D<T>
where
T: ToComputedValue,
{
type ComputedValue = Size2D<<T as ToComputedValue>::ComputedValue>;
type ComputedValue = default::Size2D<<T as ToComputedValue>::ComputedValue>;
#[inline]
fn to_computed_value(&self, context: &Context) -> Self::ComputedValue {
@ -814,3 +815,29 @@ pub type GridLine = GenericGridLine<Integer>;
/// `<grid-template-rows> | <grid-template-columns>`
pub type GridTemplateComponent = GenericGridTemplateComponent<LengthPercentage, Integer>;
impl ClipRect {
/// Given a border box, resolves the clip rect against the border box
/// in the same space the border box is in
pub fn for_border_rect<T: Copy + From<Length> + Add<Output = T> + Sub<Output = T>, U>(
&self,
border_box: Rect<T, U>,
) -> Rect<T, U> {
fn extract_clip_component<T: From<Length>>(p: &LengthOrAuto, or: T) -> T {
match *p {
LengthOrAuto::Auto => or,
LengthOrAuto::LengthPercentage(ref length) => T::from(*length),
}
}
let clip_origin = Point2D::new(
From::from(self.left.auto_is(|| Length::new(0.))),
From::from(self.top.auto_is(|| Length::new(0.))),
);
let right = extract_clip_component(&self.right, border_box.size.width);
let bottom = extract_clip_component(&self.bottom, border_box.size.height);
let clip_size = Size2D::new(right - clip_origin.x, bottom - clip_origin.y);
Rect::new(clip_origin, clip_size).translate(border_box.origin.to_vector())
}
}