mirror of
https://github.com/servo/servo.git
synced 2025-07-22 23:03:42 +01:00
Add support for overflow:scroll and overflow:hidden to layout_2020
This adds clipping and interactive scrolling support, but scrolling from script is still not functional.
This commit is contained in:
parent
8e0d037ee8
commit
7a5a320d74
19 changed files with 129 additions and 63 deletions
|
@ -9,9 +9,11 @@ use crate::replaced::IntrinsicSizes;
|
|||
use embedder_traits::Cursor;
|
||||
use euclid::{Point2D, SideOffsets2D, Size2D};
|
||||
use gfx::text::glyph::GlyphStore;
|
||||
use gfx_traits::{combine_id_with_fragment_type, FragmentType};
|
||||
use mitochondria::OnceCell;
|
||||
use net_traits::image_cache::UsePlaceholder;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::overflow_x::T as ComputedOverflow;
|
||||
use style::dom::OpaqueNode;
|
||||
use style::properties::ComputedValues;
|
||||
use style::values::computed::{BorderStyle, Length, LengthPercentage};
|
||||
|
@ -63,8 +65,6 @@ impl<'a> DisplayListBuilder<'a> {
|
|||
wr::CommonItemProperties::new(clip_rect, self.current_space_and_clip)
|
||||
}
|
||||
|
||||
// FIXME: use this for the `overflow` property or anything else that clips an entire subtree.
|
||||
#[allow(unused)]
|
||||
fn clipping_and_scrolling_scope<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
|
||||
let previous = self.current_space_and_clip;
|
||||
let result = f(self);
|
||||
|
@ -256,14 +256,49 @@ impl<'a> BuilderForBoxFragment<'a> {
|
|||
|
||||
self.build_background(builder);
|
||||
self.build_border(builder);
|
||||
let content_rect = self
|
||||
.fragment
|
||||
.content_rect
|
||||
.to_physical(self.fragment.style.writing_mode, self.containing_block)
|
||||
.translate(self.containing_block.origin.to_vector());
|
||||
for child in &self.fragment.children {
|
||||
child.build_display_list(builder, &content_rect)
|
||||
}
|
||||
|
||||
builder.clipping_and_scrolling_scope(|builder| {
|
||||
let overflow_x = self.fragment.style.get_box().overflow_x;
|
||||
let overflow_y = self.fragment.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 {
|
||||
// TODO(mrobinson): We should use the correct fragment type, once we generate
|
||||
// fragments from ::before and ::after generated content selectors.
|
||||
let id = combine_id_with_fragment_type(
|
||||
self.fragment.tag.id() as usize,
|
||||
FragmentType::FragmentBody,
|
||||
) as u64;
|
||||
let external_id = wr::ExternalScrollId(id, builder.wr.pipeline_id);
|
||||
|
||||
let sensitivity = if ComputedOverflow::Hidden == overflow_x &&
|
||||
ComputedOverflow::Hidden == overflow_y
|
||||
{
|
||||
wr::ScrollSensitivity::Script
|
||||
} else {
|
||||
wr::ScrollSensitivity::ScriptAndInputEvents
|
||||
};
|
||||
|
||||
builder.current_space_and_clip = builder.wr.define_scroll_frame(
|
||||
&original_scroll_and_clip_info,
|
||||
Some(external_id),
|
||||
self.fragment.scrollable_overflow().to_webrender(),
|
||||
*self.padding_rect(),
|
||||
vec![], // complex_clips
|
||||
None, // image_mask
|
||||
sensitivity,
|
||||
wr::units::LayoutVector2D::zero(),
|
||||
);
|
||||
}
|
||||
|
||||
let content_rect = self
|
||||
.fragment
|
||||
.content_rect
|
||||
.to_physical(self.fragment.style.writing_mode, self.containing_block)
|
||||
.translate(self.containing_block.origin.to_vector());
|
||||
for child in &self.fragment.children {
|
||||
child.build_display_list(builder, &content_rect)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
fn build_background(&mut self, builder: &mut DisplayListBuilder) {
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
||||
|
||||
use crate::geom::flow_relative::{Rect, Sides, Vec2};
|
||||
use crate::geom::PhysicalRect;
|
||||
use crate::geom::{PhysicalPoint, PhysicalRect};
|
||||
use gfx::text::glyph::GlyphStore;
|
||||
use gfx_traits::print_tree::PrintTree;
|
||||
use servo_arc::Arc as ServoArc;
|
||||
use std::sync::Arc;
|
||||
use style::computed_values::overflow_x::T as ComputedOverflow;
|
||||
use style::dom::OpaqueNode;
|
||||
use style::logical_geometry::WritingMode;
|
||||
use style::properties::ComputedValues;
|
||||
|
@ -39,7 +40,7 @@ pub(crate) struct BoxFragment {
|
|||
pub block_margins_collapsed_with_children: CollapsedBlockMargins,
|
||||
|
||||
/// The scrollable overflow of this box fragment.
|
||||
pub scrollable_overflow: PhysicalRect<Length>,
|
||||
pub scrollable_overflow_from_children: PhysicalRect<Length>,
|
||||
}
|
||||
|
||||
pub(crate) struct CollapsedBlockMargins {
|
||||
|
@ -101,15 +102,16 @@ impl Fragment {
|
|||
pub fn scrollable_overflow(&self) -> PhysicalRect<Length> {
|
||||
// FIXME(mrobinson, bug 25564): We should be using the containing block
|
||||
// here to properly convert scrollable overflow to physical geometry.
|
||||
let containing_block = PhysicalRect::zero();
|
||||
match self {
|
||||
Fragment::Box(fragment) => fragment.scrollable_overflow.clone(),
|
||||
Fragment::Box(fragment) => fragment.scrollable_overflow_for_parent(&containing_block),
|
||||
Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(),
|
||||
Fragment::Text(fragment) => fragment
|
||||
.rect
|
||||
.to_physical(fragment.parent_style.writing_mode, &PhysicalRect::zero()),
|
||||
.to_physical(fragment.parent_style.writing_mode, &containing_block),
|
||||
Fragment::Image(fragment) => fragment
|
||||
.rect
|
||||
.to_physical(fragment.style.writing_mode, &PhysicalRect::zero()),
|
||||
.to_physical(fragment.style.writing_mode, &containing_block),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -125,10 +127,13 @@ impl AnonymousFragment {
|
|||
}
|
||||
|
||||
pub fn new(rect: Rect<Length>, children: Vec<Fragment>, mode: WritingMode) -> Self {
|
||||
// FIXME(mrobinson, bug 25564): We should be using the containing block
|
||||
// here to properly convert scrollable overflow to physical geometry.
|
||||
let content_origin = rect.start_corner.to_physical(mode);
|
||||
let scrollable_overflow = children.iter().fold(PhysicalRect::zero(), |acc, child| {
|
||||
acc.union(&child.scrollable_overflow())
|
||||
acc.union(
|
||||
&child
|
||||
.scrollable_overflow()
|
||||
.translate(content_origin.to_vector()),
|
||||
)
|
||||
});
|
||||
AnonymousFragment {
|
||||
rect,
|
||||
|
@ -141,8 +146,9 @@ impl AnonymousFragment {
|
|||
pub fn print(&self, tree: &mut PrintTree) {
|
||||
tree.new_level(format!(
|
||||
"Anonymous\
|
||||
\nrect={:?}",
|
||||
self.rect
|
||||
\nrect={:?}\
|
||||
\nscrollable_overflow={:?}",
|
||||
self.rect, self.scrollable_overflow
|
||||
));
|
||||
|
||||
for child in &self.children {
|
||||
|
@ -163,14 +169,10 @@ impl BoxFragment {
|
|||
margin: Sides<Length>,
|
||||
block_margins_collapsed_with_children: CollapsedBlockMargins,
|
||||
) -> BoxFragment {
|
||||
// FIXME(mrobinson, bug 25564): We should be using the containing block
|
||||
// here to properly convert scrollable overflow to physical geometry.
|
||||
let scrollable_overflow = children.iter().fold(
|
||||
content_rect
|
||||
.inflate(&border)
|
||||
.to_physical(style.writing_mode, &PhysicalRect::zero()),
|
||||
|acc, child| acc.union(&child.scrollable_overflow()),
|
||||
);
|
||||
let scrollable_overflow_from_children =
|
||||
children.iter().fold(PhysicalRect::zero(), |acc, child| {
|
||||
acc.union(&child.scrollable_overflow())
|
||||
});
|
||||
BoxFragment {
|
||||
tag,
|
||||
style,
|
||||
|
@ -180,10 +182,28 @@ impl BoxFragment {
|
|||
border,
|
||||
margin,
|
||||
block_margins_collapsed_with_children,
|
||||
scrollable_overflow,
|
||||
scrollable_overflow_from_children,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn scrollable_overflow(&self) -> PhysicalRect<Length> {
|
||||
// FIXME(mrobinson, bug 25564): We should be using the containing block
|
||||
// here to properly convert scrollable overflow to physical geometry.
|
||||
let physical_padding_rect = self
|
||||
.padding_rect()
|
||||
.to_physical(self.style.writing_mode, &PhysicalRect::zero());
|
||||
|
||||
let content_origin = self
|
||||
.content_rect
|
||||
.start_corner
|
||||
.to_physical(self.style.writing_mode);
|
||||
physical_padding_rect.union(
|
||||
&self
|
||||
.scrollable_overflow_from_children
|
||||
.translate(content_origin.to_vector()),
|
||||
)
|
||||
}
|
||||
|
||||
pub fn padding_rect(&self) -> Rect<Length> {
|
||||
self.content_rect.inflate(&self.padding)
|
||||
}
|
||||
|
@ -197,10 +217,17 @@ impl BoxFragment {
|
|||
"Box\
|
||||
\ncontent={:?}\
|
||||
\npadding rect={:?}\
|
||||
\nborder rect={:?}",
|
||||
\nborder rect={:?}\
|
||||
\nscrollable_overflow={:?}\
|
||||
\noverflow={:?} / {:?}\
|
||||
\nstyle={:p}",
|
||||
self.content_rect,
|
||||
self.padding_rect(),
|
||||
self.border_rect()
|
||||
self.border_rect(),
|
||||
self.scrollable_overflow(),
|
||||
self.style.get_box().overflow_x,
|
||||
self.style.get_box().overflow_y,
|
||||
self.style,
|
||||
));
|
||||
|
||||
for child in &self.children {
|
||||
|
@ -208,6 +235,41 @@ impl BoxFragment {
|
|||
}
|
||||
tree.end_level();
|
||||
}
|
||||
|
||||
pub fn scrollable_overflow_for_parent(
|
||||
&self,
|
||||
containing_block: &PhysicalRect<Length>,
|
||||
) -> PhysicalRect<Length> {
|
||||
let mut overflow = self
|
||||
.border_rect()
|
||||
.to_physical(self.style.writing_mode, containing_block);
|
||||
|
||||
if self.style.get_box().overflow_y != ComputedOverflow::Visible &&
|
||||
self.style.get_box().overflow_x != ComputedOverflow::Visible
|
||||
{
|
||||
return overflow;
|
||||
}
|
||||
|
||||
// https://www.w3.org/TR/css-overflow-3/#scrollable
|
||||
// Only include the scrollable overflow of a child box if it has overflow: visible.
|
||||
let scrollable_overflow = self.scrollable_overflow();
|
||||
let bottom_right = PhysicalPoint::new(
|
||||
overflow.max_x().max(scrollable_overflow.max_x()),
|
||||
overflow.max_y().max(scrollable_overflow.max_y()),
|
||||
);
|
||||
|
||||
if self.style.get_box().overflow_y == ComputedOverflow::Visible {
|
||||
overflow.origin.y = overflow.origin.y.min(scrollable_overflow.origin.y);
|
||||
overflow.size.height = bottom_right.y - overflow.origin.y;
|
||||
}
|
||||
|
||||
if self.style.get_box().overflow_x == ComputedOverflow::Visible {
|
||||
overflow.origin.x = overflow.origin.x.min(scrollable_overflow.origin.x);
|
||||
overflow.size.width = bottom_right.x - overflow.origin.x;
|
||||
}
|
||||
|
||||
overflow
|
||||
}
|
||||
}
|
||||
|
||||
impl TextFragment {
|
||||
|
|
|
@ -131,7 +131,6 @@ ${helpers.single_keyword(
|
|||
"Overflow",
|
||||
"computed::Overflow::Visible",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
servo_2020_pref="layout.2020.unimplemented",
|
||||
logical_group="overflow",
|
||||
logical=logical,
|
||||
animation_value_type="discrete",
|
||||
|
|
|
@ -9,7 +9,7 @@ ${helpers.two_properties_shorthand(
|
|||
"overflow-x",
|
||||
"overflow-y",
|
||||
"specified::Overflow::parse",
|
||||
engines="gecko servo-2013",
|
||||
engines="gecko servo-2013 servo-2020",
|
||||
flags="SHORTHAND_IN_GETCS",
|
||||
needs_context=False,
|
||||
spec="https://drafts.csswg.org/css-overflow/#propdef-overflow",
|
||||
|
|
|
@ -1,2 +0,0 @@
|
|||
[background-repeat-repeat-x.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[background-repeat-repeat-y.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[background-size-contain.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[background-size-cover.xht]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[acid2_ref.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[border_radius_clip_a.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[position-sticky-bottom.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[position-sticky-top.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[overflow_auto.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[overflow_position_abs_simple_a.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[overflow_scroll.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[overflow_simple_a.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[overflow_xy_a.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[text_overflow_ellipsis.html]
|
||||
expected: FAIL
|
|
@ -1,2 +0,0 @@
|
|||
[text_overflow_string.html]
|
||||
expected: FAIL
|
Loading…
Add table
Add a link
Reference in a new issue