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

@ -5,7 +5,8 @@
use crate::context::LayoutContext;
use crate::display_list::conversions::ToWebRender;
use crate::display_list::stacking_context::StackingContextSection;
use crate::fragments::{BoxFragment, Fragment, Tag, TextFragment};
use crate::fragment_tree::Tag;
use crate::fragments::{BoxFragment, Fragment, TextFragment};
use crate::geom::{PhysicalPoint, PhysicalRect};
use crate::replaced::IntrinsicSizes;
use crate::style_ext::ComputedValuesExt;
@ -95,19 +96,24 @@ impl<'a> DisplayListBuilder<'a> {
}
}
fn hit_info(&mut self, style: &ComputedValues, tag: Tag, auto_cursor: Cursor) -> HitInfo {
fn hit_info(
&mut self,
style: &ComputedValues,
tag: Option<Tag>,
auto_cursor: Cursor,
) -> HitInfo {
use style::computed_values::pointer_events::T as PointerEvents;
let inherited_ui = style.get_inherited_ui();
if inherited_ui.pointer_events == PointerEvents::None {
None
} else {
let hit_test_index = self.compositor_info.add_hit_test_info(
tag.node().0 as u64,
Some(cursor(inherited_ui.cursor.keyword, auto_cursor)),
);
Some((hit_test_index as u64, 0u16))
return None;
}
let hit_test_index = self.compositor_info.add_hit_test_info(
tag?.node.0 as u64,
Some(cursor(inherited_ui.cursor.keyword, auto_cursor)),
);
Some((hit_test_index as u64, 0u16))
}
}
@ -210,7 +216,7 @@ impl Fragment {
}
let mut common = builder.common_properties(rect.to_webrender(), &fragment.parent_style);
common.hit_info = builder.hit_info(&fragment.parent_style, fragment.tag, Cursor::Text);
common.hit_info = builder.hit_info(&fragment.parent_style, fragment.base.tag, Cursor::Text);
let color = fragment.parent_style.clone_color();
let font_metrics = &fragment.font_metrics;
@ -431,7 +437,11 @@ impl<'a> BuilderForBoxFragment<'a> {
}
fn build_hit_test(&self, builder: &mut DisplayListBuilder) {
let hit_info = builder.hit_info(&self.fragment.style, self.fragment.tag, Cursor::Default);
let hit_info = builder.hit_info(
&self.fragment.style,
self.fragment.base.tag,
Cursor::Default,
);
if hit_info.is_some() {
let mut common = builder.common_properties(self.border_rect, &self.fragment.style);
common.hit_info = hit_info;
@ -443,7 +453,11 @@ impl<'a> BuilderForBoxFragment<'a> {
}
fn build_background(&mut self, builder: &mut DisplayListBuilder) {
if self.fragment.tag.node() == builder.element_for_canvas_background {
if self
.fragment
.base
.is_for_node(builder.element_for_canvas_background)
{
// This background is already painted for the canvas, dont paint it again here.
return;
}
@ -494,26 +508,32 @@ impl<'a> BuilderForBoxFragment<'a> {
}
},
Image::Url(ref image_url) => {
// FIXME: images wont always have in intrinsic width or height
// when support for SVG is added.
// Or a WebRender `ImageKey`, for that matter.
let (width, height, key) = match image_url.url() {
Some(url) => {
match builder.context.get_webrender_image_for_url(
self.fragment.tag.node(),
url.clone(),
UsePlaceholder::No,
) {
Some(WebRenderImageInfo {
width,
height,
key: Some(key),
}) => (width, height, key),
_ => continue,
}
},
// FIXME: images wont always have in intrinsic width or
// height when support for SVG is added, or a WebRender
// `ImageKey`, for that matter.
//
// FIXME: It feels like this should take into account the pseudo
// element and not just the node.
let node = match self.fragment.base.tag {
Some(tag) => tag.node,
None => continue,
};
let image_url = match image_url.url() {
Some(url) => url.clone(),
None => continue,
};
let (width, height, key) = match builder.context.get_webrender_image_for_url(
node,
image_url,
UsePlaceholder::No,
) {
Some(WebRenderImageInfo {
width,
height,
key: Some(key),
}) => (width, height, key),
_ => continue,
};
// FIXME: https://drafts.csswg.org/css-images-4/#the-image-resolution
let dppx = 1.0;