Detect body elements during layout

During layout it is often useful, for various specification reasons, to
know if an element is the `<body>` element of an `<html>` element root. There
are a couple places where a brittle heuristic is used to detect `<body>`
elements. This information is going to be even more important to
properly handle `<html>` elements that inherit their overflow property from
their `<body>` children.

Implementing this properly requires updating the DOM wrapper interface.
This check does reach up to the parent of thread-safe nodes, but this is
essentially the same kind of operation that `parent_style()` does, so is
ostensibly safe.

This change should not change any behavior and is just a preparation
step for properly handle `<body>` overflow.
This commit is contained in:
Martin Robinson 2023-04-30 20:21:58 +02:00
parent 77a184a0e7
commit 72302e2dae
26 changed files with 487 additions and 277 deletions

View file

@ -12,7 +12,6 @@ use crate::flow::float::FloatBox;
use crate::flow::inline::{InlineBox, InlineFormattingContext, InlineLevelBox, TextRun};
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::Tag;
use crate::positioned::AbsolutelyPositionedBox;
use crate::style_ext::{DisplayGeneratingBox, DisplayInside, DisplayOutside};
use rayon::iter::{IntoParallelIterator, ParallelIterator};
@ -384,7 +383,7 @@ where
if let Some(text) = new_text_run_contents {
inlines.push(ArcRefCell::new(InlineLevelBox::TextRun(TextRun {
tag: Tag::from_node_and_style_info(info),
base_fragment_info: info.into(),
parent_style: Arc::clone(&info.style),
text,
})))
@ -495,7 +494,7 @@ where
// Whatever happened before, all we need to do before recurring
// is to remember this ongoing inline level box.
self.ongoing_inline_boxes_stack.push(InlineBox {
tag: Tag::from_node_and_style_info(info),
base_fragment_info: info.into(),
style: info.style.clone(),
first_fragment: true,
last_fragment: false,
@ -556,7 +555,7 @@ where
.rev()
.map(|ongoing| {
let fragmented = InlineBox {
tag: ongoing.tag,
base_fragment_info: ongoing.base_fragment_info,
style: ongoing.style.clone(),
first_fragment: ongoing.first_fragment,
// The fragmented boxes before the block level element
@ -755,7 +754,7 @@ where
BlockLevelCreator::SameFormattingContextBlock(contents) => {
let (contents, contains_floats) = contents.finish(context, info);
let block_level_box = ArcRefCell::new(BlockLevelBox::SameFormattingContextBlock {
tag: Tag::from_node_and_style_info(info),
base_fragment_info: info.into(),
contents,
style: Arc::clone(&info.style),
});

View file

@ -7,9 +7,9 @@ use crate::context::LayoutContext;
use crate::flow::float::FloatBox;
use crate::flow::FlowLayout;
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragment_tree::BaseFragmentInfo;
use crate::fragments::{
AnonymousFragment, BoxFragment, CollapsedBlockMargins, DebugId, FontMetrics, Fragment, Tag,
TextFragment,
AnonymousFragment, BoxFragment, CollapsedBlockMargins, FontMetrics, Fragment, TextFragment,
};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{
@ -51,7 +51,7 @@ pub(crate) enum InlineLevelBox {
#[derive(Debug, Serialize)]
pub(crate) struct InlineBox {
pub tag: Tag,
pub base_fragment_info: BaseFragmentInfo,
#[serde(skip_serializing)]
pub style: Arc<ComputedValues>,
pub first_fragment: bool,
@ -62,7 +62,7 @@ pub(crate) struct InlineBox {
/// https://www.w3.org/TR/css-display-3/#css-text-run
#[derive(Debug, Serialize)]
pub(crate) struct TextRun {
pub tag: Tag,
pub base_fragment_info: BaseFragmentInfo,
#[serde(skip_serializing)]
pub parent_style: Arc<ComputedValues>,
pub text: String,
@ -82,7 +82,7 @@ struct InlineNestingLevelState<'box_tree> {
}
struct PartialInlineBoxFragment<'box_tree> {
tag: Tag,
base_fragment_info: BaseFragmentInfo,
style: Arc<ComputedValues>,
start_corner: Vec2<Length>,
padding: Sides<Length>,
@ -471,7 +471,7 @@ impl InlineBox {
let text_decoration_line =
ifc.current_nesting_level.text_decoration_line | style.clone_text_decoration_line();
PartialInlineBoxFragment {
tag: self.tag,
base_fragment_info: self.base_fragment_info,
style,
start_corner,
padding,
@ -512,7 +512,7 @@ impl<'box_tree> PartialInlineBoxFragment<'box_tree> {
};
let mut fragment = BoxFragment::new(
self.tag,
self.base_fragment_info,
self.style.clone(),
std::mem::take(&mut nesting_level.fragments_so_far),
content_rect,
@ -580,7 +580,7 @@ fn layout_atomic(
.make_fragments(&replaced.style, size.clone());
let content_rect = Rect { start_corner, size };
BoxFragment::new(
replaced.tag,
replaced.base_fragment_info,
replaced.style.clone(),
fragments,
content_rect,
@ -655,7 +655,7 @@ fn layout_atomic(
},
};
BoxFragment::new(
non_replaced.tag,
non_replaced.base_fragment_info,
non_replaced.style.clone(),
independent_layout.fragments,
content_rect,
@ -836,8 +836,7 @@ impl TextRun {
ifc.current_nesting_level
.fragments_so_far
.push(Fragment::Text(TextFragment {
tag: self.tag,
debug_id: DebugId::new(),
base: self.base_fragment_info.into(),
parent_style: self.parent_style.clone(),
rect,
font_metrics,

View file

@ -11,8 +11,9 @@ use crate::flow::inline::InlineFormattingContext;
use crate::formatting_contexts::{
IndependentFormattingContext, IndependentLayout, NonReplacedFormattingContext,
};
use crate::fragment_tree::BaseFragmentInfo;
use crate::fragments::{
AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment, Tag,
AnonymousFragment, BoxFragment, CollapsedBlockMargins, CollapsedMargin, Fragment,
};
use crate::geom::flow_relative::{Rect, Sides, Vec2};
use crate::positioned::{AbsolutelyPositionedBox, PositioningContext};
@ -50,7 +51,7 @@ pub(crate) enum BlockContainer {
#[derive(Debug, Serialize)]
pub(crate) enum BlockLevelBox {
SameFormattingContextBlock {
tag: Tag,
base_fragment_info: BaseFragmentInfo,
#[serde(skip_serializing)]
style: Arc<ComputedValues>,
contents: BlockContainer,
@ -306,7 +307,7 @@ impl BlockLevelBox {
) -> Fragment {
match self {
BlockLevelBox::SameFormattingContextBlock {
tag,
base_fragment_info: tag,
style,
contents,
} => Fragment::Box(positioning_context.layout_maybe_position_relative_fragment(
@ -335,7 +336,7 @@ impl BlockLevelBox {
|_positioning_context| {
layout_in_flow_replaced_block_level(
containing_block,
replaced.tag,
replaced.base_fragment_info,
&replaced.style,
&replaced.contents,
)
@ -352,7 +353,7 @@ impl BlockLevelBox {
layout_context,
positioning_context,
containing_block,
non_replaced.tag,
non_replaced.base_fragment_info,
&non_replaced.style,
NonReplacedContents::EstablishesAnIndependentFormattingContext(
non_replaced,
@ -420,7 +421,7 @@ fn layout_in_flow_non_replaced_block_level(
layout_context: &LayoutContext,
positioning_context: &mut PositioningContext,
containing_block: &ContainingBlock,
tag: Tag,
base_fragment_info: BaseFragmentInfo,
style: &Arc<ComputedValues>,
block_level_kind: NonReplacedContents,
tree_rank: usize,
@ -559,7 +560,7 @@ fn layout_in_flow_non_replaced_block_level(
},
};
BoxFragment::new(
tag,
base_fragment_info,
style.clone(),
fragments,
content_rect,
@ -575,7 +576,7 @@ fn layout_in_flow_non_replaced_block_level(
/// https://drafts.csswg.org/css2/visudet.html#inline-replaced-height
fn layout_in_flow_replaced_block_level<'a>(
containing_block: &ContainingBlock,
tag: Tag,
base_fragment_info: BaseFragmentInfo,
style: &Arc<ComputedValues>,
replaced: &ReplacedContent,
) -> BoxFragment {
@ -600,7 +601,7 @@ fn layout_in_flow_replaced_block_level<'a>(
};
let block_margins_collapsed_with_children = CollapsedBlockMargins::from_margin(&margin);
BoxFragment::new(
tag,
base_fragment_info,
style.clone(),
fragments,
content_rect,

View file

@ -15,7 +15,8 @@ use crate::flow::float::FloatBox;
use crate::flow::inline::InlineLevelBox;
use crate::flow::{BlockContainer, BlockFormattingContext, BlockLevelBox};
use crate::formatting_contexts::IndependentFormattingContext;
use crate::fragments::{Fragment, Tag};
use crate::fragment_tree::Tag;
use crate::fragments::Fragment;
use crate::geom::flow_relative::Vec2;
use crate::geom::{PhysicalPoint, PhysicalRect, PhysicalSize};
use crate::positioned::AbsolutelyPositionedBox;
@ -36,7 +37,6 @@ use servo_arc::Arc;
use style::animation::AnimationSetKey;
use style::dom::OpaqueNode;
use style::properties::ComputedValues;
use style::selector_parser::PseudoElement;
use style::values::computed::Length;
use style_traits::CSSPixel;
use webrender_api::{ClipId, SpaceAndClipInfo, SpatialId};
@ -466,19 +466,15 @@ impl FragmentTree {
pub fn remove_nodes_in_fragment_tree_from_set(&self, set: &mut FxHashSet<AnimationSetKey>) {
self.find(|fragment, _, _| {
let (node, pseudo) = match fragment.tag()? {
Tag::Node(node) => (node, None),
Tag::BeforePseudo(node) => (node, Some(PseudoElement::Before)),
Tag::AfterPseudo(node) => (node, Some(PseudoElement::After)),
};
set.remove(&AnimationSetKey::new(node, pseudo));
let tag = fragment.tag()?;
set.remove(&AnimationSetKey::new(tag.node, tag.pseudo));
None::<()>
});
}
pub fn get_content_box_for_node(&self, requested_node: OpaqueNode) -> Rect<Au> {
let mut bounding_box = PhysicalRect::zero();
let tag_to_find = Tag::Node(requested_node);
let tag_to_find = Tag::new(requested_node);
self.find(|fragment, _, containing_block| {
if fragment.tag() != Some(tag_to_find) {
return None::<()>;
@ -516,17 +512,15 @@ impl FragmentTree {
}
pub fn get_border_dimensions_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
let tag_to_find = Tag::new(requested_node);
self.find(|fragment, _, containing_block| {
if fragment.tag() != Some(tag_to_find) {
return None;
}
let (style, padding_rect) = match fragment {
Fragment::Box(fragment) if fragment.tag.node() == requested_node => {
(&fragment.style, fragment.padding_rect())
},
Fragment::AbsoluteOrFixedPositioned(_) |
Fragment::Box(_) |
Fragment::Text(_) |
Fragment::Image(_) |
Fragment::IFrame(_) |
Fragment::Anonymous(_) => return None,
Fragment::Box(fragment) => (&fragment.style, fragment.padding_rect()),
_ => return None,
};
// https://drafts.csswg.org/cssom-view/#dom-element-clienttop
@ -559,7 +553,7 @@ impl FragmentTree {
pub fn get_scroll_area_for_node(&self, requested_node: OpaqueNode) -> Rect<i32> {
let mut scroll_area: PhysicalRect<Length> = PhysicalRect::zero();
let tag_to_find = Tag::Node(requested_node);
let tag_to_find = Tag::new(requested_node);
self.find(|fragment, _, containing_block| {
if fragment.tag() != Some(tag_to_find) {
return None::<()>;