Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
Add initial support for scrollable overflow in layout_2020
This still isn't totally correct and non-root scrolling is not handled
at all, but the root frame now scrolls.
  • Loading branch information
mrobinson committed Jan 21, 2020
1 parent 74d1f02 commit 8825d58
Show file tree
Hide file tree
Showing 7 changed files with 212 additions and 56 deletions.
65 changes: 34 additions & 31 deletions components/layout_2020/flow/inline.rs
Expand Up @@ -339,11 +339,12 @@ impl Lines {
block: line_block_size,
};
self.next_line_block_position += size.block;
self.fragments.push(Fragment::Anonymous(AnonymousFragment {
children: line_contents,
rect: Rect { start_corner, size },
mode: containing_block.style.writing_mode,
}))
self.fragments
.push(Fragment::Anonymous(AnonymousFragment::new(
Rect { start_corner, size },
line_contents,
containing_block.style.writing_mode,
)))
}
}

Expand Down Expand Up @@ -402,22 +403,24 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
inline_position: &mut Length,
at_line_break: bool,
) {
let mut fragment = BoxFragment {
tag: self.tag,
style: self.style.clone(),
children: std::mem::take(&mut nesting_level.fragments_so_far),
content_rect: Rect {
size: Vec2 {
inline: *inline_position - self.start_corner.inline,
block: nesting_level.max_block_size_of_fragments_so_far,
},
start_corner: self.start_corner.clone(),
let content_rect = Rect {
size: Vec2 {
inline: *inline_position - self.start_corner.inline,
block: nesting_level.max_block_size_of_fragments_so_far,
},
padding: self.padding.clone(),
border: self.border.clone(),
margin: self.margin.clone(),
block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
start_corner: self.start_corner.clone(),
};

let mut fragment = BoxFragment::new(
self.tag,
self.style.clone(),
std::mem::take(&mut nesting_level.fragments_so_far),
content_rect,
self.padding.clone(),
self.border.clone(),
self.margin.clone(),
CollapsedBlockMargins::zero(),
);
let last_fragment = self.last_box_tree_fragment && !at_line_break;
if last_fragment {
*inline_position += fragment.padding.inline_end +
Expand Down Expand Up @@ -470,16 +473,16 @@ fn layout_atomic<'box_tree>(
let size = replaced.used_size_as_if_inline_element(ifc.containing_block, &atomic.style);
let fragments = replaced.make_fragments(&atomic.style, size.clone());
let content_rect = Rect { start_corner, size };
BoxFragment {
tag: atomic.tag,
style: atomic.style.clone(),
children: fragments,
BoxFragment::new(
atomic.tag,
atomic.style.clone(),
fragments,
content_rect,
padding,
border,
margin,
block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
}
CollapsedBlockMargins::zero(),
)
},
Err(non_replaced) => {
let box_size = atomic.style.box_size();
Expand Down Expand Up @@ -545,16 +548,16 @@ fn layout_atomic<'box_tree>(
inline: inline_size,
},
};
BoxFragment {
tag: atomic.tag,
style: atomic.style.clone(),
children: independent_layout.fragments,
BoxFragment::new(
atomic.tag,
atomic.style.clone(),
independent_layout.fragments,
content_rect,
padding,
border,
margin,
block_margins_collapsed_with_children: CollapsedBlockMargins::zero(),
}
CollapsedBlockMargins::zero(),
)
},
};

Expand Down
19 changes: 10 additions & 9 deletions components/layout_2020/flow/mod.rs
Expand Up @@ -495,16 +495,16 @@ fn layout_in_flow_non_replaced_block_level<'a>(
inline: inline_size,
},
};
BoxFragment {
BoxFragment::new(
tag,
style: style.clone(),
children: fragments,
style.clone(),
fragments,
content_rect,
padding,
border,
margin,
block_margins_collapsed_with_children,
}
)
}

/// https://drafts.csswg.org/css2/visudet.html#block-replaced-width
Expand Down Expand Up @@ -545,16 +545,17 @@ fn layout_in_flow_replaced_block_level<'a>(
},
size,
};
BoxFragment {
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
BoxFragment::new(
tag,
style: style.clone(),
children: fragments,
style.clone(),
fragments,
content_rect,
padding,
border,
block_margins_collapsed_with_children: CollapsedBlockMargins::from_margin(&margin),
margin,
}
block_margins_collapsed_with_children,
)
}

fn solve_inline_margins_for_in_flow_block_level(
Expand Down
52 changes: 48 additions & 4 deletions components/layout_2020/flow/root.rs
Expand Up @@ -11,12 +11,14 @@ use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom;
use crate::geom::flow_relative::Vec2;
use crate::geom::physical;
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
use crate::sizing::ContentSizesRequest;
use crate::style_ext::{Display, DisplayGeneratingBox, DisplayInside};
use crate::DefiniteContainingBlock;
use euclid::Size2D;
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
Expand All @@ -26,7 +28,14 @@ use style::Zero;
use style_traits::CSSPixel;

pub struct BoxTreeRoot(BlockFormattingContext);
pub struct FragmentTreeRoot(Vec<Fragment>);

pub struct FragmentTreeRoot {
/// The children of the root of the fragment tree.
children: Vec<Fragment>,

/// The scrollable overflow of the root of the fragment tree.
scrollable_overflow: physical::Rect<Length>,
}

impl BoxTreeRoot {
pub fn construct<'dom, Node>(context: &LayoutContext, root_element: Node) -> Self
Expand Down Expand Up @@ -131,7 +140,35 @@ impl BoxTreeRoot {
&mut independent_layout.fragments,
);

FragmentTreeRoot(independent_layout.fragments)
// FIXME(mrobinson, bug 25564): We should be using the containing block
// here to properly convert scrollable overflow to physical geometry.
let scrollable_overflow =
independent_layout
.fragments
.iter()
.fold(physical::Rect::zero(), |acc, child| {
let child_overflow = child.scrollable_overflow();

// https://drafts.csswg.org/css-overflow/#scrolling-direction
// We want to clip scrollable overflow on box-start and inline-start
// sides of the scroll container.
//
// FIXME(mrobinson, bug 25564): This should take into account writing
// mode.
let child_overflow = physical::Rect {
top_left: physical::Vec2::zero(),
size: physical::Vec2 {
x: child_overflow.size.x + child_overflow.top_left.x,
y: child_overflow.size.y + child_overflow.top_left.y,
},
};
acc.axis_aligned_bounding_box(&child_overflow)
});

FragmentTreeRoot {
children: independent_layout.fragments,
scrollable_overflow,
}
}
}

Expand All @@ -151,15 +188,22 @@ impl FragmentTreeRoot {
y: Length::new(viewport_size.height),
},
};
for fragment in &self.0 {
for fragment in &self.children {
fragment.build_display_list(builder, &containing_block)
}
}

pub fn print(&self) {
let mut print_tree = PrintTree::new("Fragment Tree".to_string());
for fragment in &self.0 {
for fragment in &self.children {
fragment.print(&mut print_tree);
}
}

pub fn scrollable_overflow(&self) -> webrender_api::units::LayoutSize {
webrender_api::units::LayoutSize::from_untyped(Size2D::new(
self.scrollable_overflow.size.x.px(),
self.scrollable_overflow.size.y.px(),
))
}
}
68 changes: 68 additions & 0 deletions components/layout_2020/fragments.rs
Expand Up @@ -3,6 +3,7 @@
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */

use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::geom::physical;
use gfx::text::glyph::GlyphStore;
use gfx_traits::print_tree::PrintTree;
use servo_arc::Arc as ServoArc;
Expand Down Expand Up @@ -36,6 +37,9 @@ pub(crate) struct BoxFragment {
pub margin: Sides<Length>,

pub block_margins_collapsed_with_children: CollapsedBlockMargins,

/// The scrollable overflow of this box fragment.
pub scrollable_overflow: physical::Rect<Length>,
}

pub(crate) struct CollapsedBlockMargins {
Expand All @@ -55,6 +59,9 @@ pub(crate) struct AnonymousFragment {
pub rect: Rect<Length>,
pub children: Vec<Fragment>,
pub mode: WritingMode,

/// The scrollable overflow of this anonymous fragment's children.
pub scrollable_overflow: physical::Rect<Length>,
}

pub(crate) struct TextFragment {
Expand Down Expand Up @@ -90,6 +97,21 @@ impl Fragment {
Fragment::Image(fragment) => fragment.print(tree),
}
}

pub fn scrollable_overflow(&self) -> physical::Rect<Length> {
// FIXME(mrobinson, bug 25564): We should be using the containing block
// here to properly convert scrollable overflow to physical geometry.
match self {
Fragment::Box(fragment) => fragment.scrollable_overflow.clone(),
Fragment::Anonymous(fragment) => fragment.scrollable_overflow.clone(),
Fragment::Text(fragment) => fragment
.rect
.to_physical(fragment.parent_style.writing_mode, &physical::Rect::zero()),
Fragment::Image(fragment) => fragment
.rect
.to_physical(fragment.style.writing_mode, &physical::Rect::zero()),
}
}
}

impl AnonymousFragment {
Expand All @@ -98,6 +120,21 @@ impl AnonymousFragment {
children: vec![],
rect: Rect::zero(),
mode,
scrollable_overflow: physical::Rect::zero(),
}
}

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 scrollable_overflow = children.iter().fold(physical::Rect::zero(), |acc, child| {
acc.axis_aligned_bounding_box(&child.scrollable_overflow())
});
AnonymousFragment {
rect,
children,
mode,
scrollable_overflow,
}
}

Expand All @@ -116,6 +153,37 @@ impl AnonymousFragment {
}

impl BoxFragment {
pub fn new(
tag: OpaqueNode,
style: ServoArc<ComputedValues>,
children: Vec<Fragment>,
content_rect: Rect<Length>,
padding: Sides<Length>,
border: Sides<Length>,
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, &physical::Rect::zero()),
|acc, child| acc.axis_aligned_bounding_box(&child.scrollable_overflow()),
);
BoxFragment {
tag,
style,
children,
content_rect,
padding,
border,
margin,
block_margins_collapsed_with_children,
scrollable_overflow,
}
}

pub fn padding_rect(&self) -> Rect<Length> {
self.content_rect.inflate(&self.padding)
}
Expand Down
36 changes: 36 additions & 0 deletions components/layout_2020/geom.rs
Expand Up @@ -60,6 +60,15 @@ pub(crate) mod flow_relative {
}
}

impl<T: Zero> physical::Vec2<T> {
pub fn zero() -> Self {
Self {
x: T::zero(),
y: T::zero(),
}
}
}

impl<T: fmt::Debug> fmt::Debug for physical::Vec2<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// Not using f.debug_struct on purpose here, to keep {:?} output somewhat compact
Expand Down Expand Up @@ -387,6 +396,33 @@ impl<T> physical::Rect<T> {
}
}

impl physical::Rect<Length> {
pub fn axis_aligned_bounding_box(&self, other: &Self) -> Self {
let top_left = physical::Vec2 {
x: self.top_left.x.min(other.top_left.x),
y: self.top_left.y.min(other.top_left.y),
};

let bottom_corner_x = (self.top_left.x + self.size.x).max(other.top_left.x + other.size.x);
let bottom_corner_y = (self.top_left.y + self.size.y).max(other.top_left.y + other.size.y);
let size = physical::Vec2 {
x: bottom_corner_x - top_left.x,
y: bottom_corner_y - top_left.y,
};

Self { top_left, size }
}
}

impl<T: Zero> physical::Rect<T> {
pub fn zero() -> Self {
Self {
top_left: physical::Vec2::zero(),
size: physical::Vec2::zero(),
}
}
}

impl From<physical::Rect<Length>> for Rect<CSSPixel> {
fn from(r: physical::Rect<Length>) -> Self {
Rect {
Expand Down

0 comments on commit 8825d58

Please sign in to comment.