aboutsummaryrefslogtreecommitdiffstats
path: root/components/layout_2020/flow/root.rs
diff options
context:
space:
mode:
Diffstat (limited to 'components/layout_2020/flow/root.rs')
-rw-r--r--components/layout_2020/flow/root.rs192
1 files changed, 137 insertions, 55 deletions
diff --git a/components/layout_2020/flow/root.rs b/components/layout_2020/flow/root.rs
index dd647070d7a..454177c789e 100644
--- a/components/layout_2020/flow/root.rs
+++ b/components/layout_2020/flow/root.rs
@@ -10,7 +10,7 @@ use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
-use crate::geom::PhysicalRect;
+use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
use crate::positioned::PositioningContext;
use crate::replaced::ReplacedContent;
@@ -22,6 +22,7 @@ use euclid::default::{Point2D, Rect, Size2D};
use gfx_traits::print_tree::PrintTree;
use script_layout_interface::wrapper_traits::LayoutNode;
use servo_arc::Arc;
+use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::values::computed::Length;
use style_traits::CSSPixel;
@@ -35,8 +36,8 @@ pub struct FragmentTreeRoot {
/// The scrollable overflow of the root of the fragment tree.
scrollable_overflow: PhysicalRect<Length>,
- /// The axis-aligned bounding box of the border box of all child fragments
- bounding_box_of_border_boxes: PhysicalRect<Length>,
+ /// The containing block used in the layout of this fragment tree.
+ initial_containing_block: PhysicalRect<Length>,
}
impl BoxTreeRoot {
@@ -117,13 +118,18 @@ impl BoxTreeRoot {
viewport: euclid::Size2D<f32, CSSPixel>,
) -> FragmentTreeRoot {
let style = ComputedValues::initial_values();
+
+ // FIXME: use the document’s mode:
+ // https://drafts.csswg.org/css-writing-modes/#principal-flow
+ let physical_containing_block = PhysicalRect::new(
+ PhysicalPoint::zero(),
+ PhysicalSize::new(Length::new(viewport.width), Length::new(viewport.height)),
+ );
let initial_containing_block = DefiniteContainingBlock {
size: Vec2 {
- inline: Length::new(viewport.width),
- block: Length::new(viewport.height),
+ inline: physical_containing_block.size.width,
+ block: physical_containing_block.size.height,
},
- // FIXME: use the document’s mode:
- // https://drafts.csswg.org/css-writing-modes/#principal-flow
style,
};
@@ -142,8 +148,6 @@ impl BoxTreeRoot {
&mut 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
@@ -167,51 +171,18 @@ impl BoxTreeRoot {
acc.union(&child_overflow)
});
- let containing_block = PhysicalRect::zero();
- let bounding_box_of_border_boxes =
- independent_layout
- .fragments
- .iter()
- .fold(PhysicalRect::zero(), |acc, child| {
- acc.union(&match child {
- Fragment::Box(fragment) => fragment
- .border_rect()
- .to_physical(fragment.style.writing_mode, &containing_block),
- Fragment::Anonymous(fragment) => {
- fragment.rect.to_physical(fragment.mode, &containing_block)
- },
- Fragment::Text(fragment) => fragment
- .rect
- .to_physical(fragment.parent_style.writing_mode, &containing_block),
- Fragment::Image(fragment) => fragment
- .rect
- .to_physical(fragment.style.writing_mode, &containing_block),
- })
- });
-
FragmentTreeRoot {
children: independent_layout.fragments,
scrollable_overflow,
- bounding_box_of_border_boxes,
+ initial_containing_block: physical_containing_block,
}
}
}
impl FragmentTreeRoot {
- pub fn build_display_list(
- &self,
- builder: &mut crate::display_list::DisplayListBuilder,
- viewport_size: webrender_api::units::LayoutSize,
- ) {
- let containing_block = PhysicalRect::new(
- euclid::Point2D::zero(),
- euclid::Size2D::new(
- Length::new(viewport_size.width),
- Length::new(viewport_size.height),
- ),
- );
+ pub fn build_display_list(&self, builder: &mut crate::display_list::DisplayListBuilder) {
for fragment in &self.children {
- fragment.build_display_list(builder, &containing_block)
+ fragment.build_display_list(builder, &self.initial_containing_block)
}
}
@@ -229,15 +200,126 @@ impl FragmentTreeRoot {
))
}
- pub fn bounding_box_of_border_boxes(&self) -> Rect<Au> {
- let origin = Point2D::new(
- Au::from_f32_px(self.bounding_box_of_border_boxes.origin.x.px()),
- Au::from_f32_px(self.bounding_box_of_border_boxes.origin.y.px()),
- );
- let size = Size2D::new(
- Au::from_f32_px(self.bounding_box_of_border_boxes.size.width.px()),
- Au::from_f32_px(self.bounding_box_of_border_boxes.size.height.px()),
- );
- Rect::new(origin, size)
+ fn find<T>(
+ &self,
+ mut process_func: impl FnMut(&Fragment, &PhysicalRect<Length>) -> Option<T>,
+ ) -> Option<T> {
+ fn recur<T>(
+ fragments: &[Fragment],
+ containing_block: &PhysicalRect<Length>,
+ process_func: &mut impl FnMut(&Fragment, &PhysicalRect<Length>) -> Option<T>,
+ ) -> Option<T> {
+ for fragment in fragments {
+ if let Some(result) = process_func(fragment, containing_block) {
+ return Some(result);
+ }
+
+ match fragment {
+ Fragment::Box(fragment) => {
+ let new_containing_block = fragment
+ .content_rect
+ .to_physical(fragment.style.writing_mode, containing_block)
+ .translate(containing_block.origin.to_vector());
+ if let Some(result) =
+ recur(&fragment.children, &new_containing_block, process_func)
+ {
+ return Some(result);
+ }
+ },
+ Fragment::Anonymous(fragment) => {
+ let new_containing_block = fragment
+ .rect
+ .to_physical(fragment.mode, containing_block)
+ .translate(containing_block.origin.to_vector());
+ if let Some(result) =
+ recur(&fragment.children, &new_containing_block, process_func)
+ {
+ return Some(result);
+ }
+ },
+ _ => {},
+ }
+ }
+ None
+ }
+ recur(
+ &self.children,
+ &self.initial_containing_block,
+ &mut process_func,
+ )
+ }
+
+ pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
+ let mut bounding_box = PhysicalRect::zero();
+ self.find(|fragment, containing_block| {
+ let fragment_relative_rect = match fragment {
+ Fragment::Box(fragment) if fragment.tag == requested_node => fragment
+ .border_rect()
+ .to_physical(fragment.style.writing_mode, &containing_block),
+ Fragment::Text(fragment) if fragment.tag == requested_node => fragment
+ .rect
+ .to_physical(fragment.parent_style.writing_mode, &containing_block),
+ Fragment::Box(_) |
+ Fragment::Text(_) |
+ Fragment::Image(_) |
+ Fragment::Anonymous(_) => return None,
+ };
+
+ bounding_box = fragment_relative_rect
+ .translate(containing_block.origin.to_vector())
+ .union(&bounding_box);
+ None::<()>
+ });
+
+ Rect::new(
+ Point2D::new(
+ Au::from_f32_px(bounding_box.origin.x.px()),
+ Au::from_f32_px(bounding_box.origin.y.px()),
+ ),
+ Size2D::new(
+ Au::from_f32_px(bounding_box.size.width.px()),
+ Au::from_f32_px(bounding_box.size.height.px()),
+ ),
+ )
+ }
+
+ pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
+ self.find(|fragment, containing_block| {
+ let (style, padding_rect) = match fragment {
+ Fragment::Box(fragment) if fragment.tag == requested_node => {
+ (&fragment.style, fragment.padding_rect())
+ },
+ Fragment::Box(_) |
+ Fragment::Text(_) |
+ Fragment::Image(_) |
+ Fragment::Anonymous(_) => return None,
+ };
+
+ // https://drafts.csswg.org/cssom-view/#dom-element-clienttop
+ // " If the element has no associated CSS layout box or if the
+ // CSS layout box is inline, return zero." For this check we
+ // also explicitly ignore the list item portion of the display
+ // style.
+ let display = &style.get_box().display;
+ if display.inside() == style::values::specified::box_::DisplayInside::Flow &&
+ display.outside() == style::values::specified::box_::DisplayOutside::Inline
+ {
+ return Some(Rect::zero());
+ }
+
+ let padding_rect = padding_rect.to_physical(style.writing_mode, &containing_block);
+ let border = style.get_border();
+ Some(Rect::new(
+ Point2D::new(
+ border.border_left_width.px() as i32,
+ border.border_top_width.px() as i32,
+ ),
+ Size2D::new(
+ padding_rect.size.width.px() as i32,
+ padding_rect.size.height.px() as i32,
+ ),
+ ))
+ })
+ .unwrap_or_else(Rect::zero)
}
}