LibWeb: Skip out-of-flow boxes when wrapping inlines in anonymous block

Out-of-flow boxes (floating and absolutely-positioned elements) were
previously collected and put in the anonymous block wrapper as well, but
this actually made hit testing not able to find them, since they were
breaking expectations about tree structure that hit testing relies on.

After this change, we simply let out-of-flow boxes stay in their
original parent, preserving the author's intended box tree structure.
This commit is contained in:
Andreas Kling 2023-12-10 21:33:03 +01:00
parent 11354dbf9e
commit 6994ea5885
Notes: sideshowbarker 2024-07-17 08:34:29 +09:00
10 changed files with 86 additions and 40 deletions

View file

@ -3,17 +3,17 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline
TextNode <#text>
BlockContainer <body> at (8,8) content-size 784x34.9375 children: not-inline
BlockContainer <div.big-float> at (8,8) content-size 100x100 floating [BFC] children: not-inline
BlockContainer <div.xxx> at (108,8) content-size 29.109375x17.46875 floating [BFC] children: inline
line 0 width: 29.109375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 3, rect: [108,8 29.109375x17.46875]
"xxx"
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 784x17.46875 children: inline
line 0 width: 27.640625, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 1, length: 3, rect: [137,8 27.640625x17.46875]
"bar"
BlockContainer <div.big-float> at (8,8) content-size 100x100 floating [BFC] children: not-inline
TextNode <#text>
BlockContainer <div.xxx> at (108,8) content-size 29.109375x17.46875 floating [BFC] children: inline
line 0 width: 29.109375, height: 17.46875, bottom: 17.46875, baseline: 13.53125
frag 0 from TextNode start: 0, length: 3, rect: [108,8 29.109375x17.46875]
"xxx"
TextNode <#text>
TextNode <#text>
BlockContainer <div> at (8,25.46875) content-size 784x17.46875 children: inline
line 0 width: 27.203125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
@ -32,11 +32,11 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x108]
PaintableWithLines (BlockContainer(anonymous)) [0,0 800x0]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x34.9375]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x34.9375] overflow: [8,8 784x100]
PaintableWithLines (BlockContainer<DIV>.big-float) [8,8 100x100]
PaintableWithLines (BlockContainer<DIV>.xxx) [108,8 29.109375x17.46875]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x17.46875]
PaintableWithLines (BlockContainer<DIV>.big-float) [8,8 100x100]
PaintableWithLines (BlockContainer<DIV>.xxx) [108,8 29.109375x17.46875]
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<DIV>) [8,25.46875 784x17.46875]
PaintableWithLines (BlockContainer<DIV>.yyy) [108,25.46875 21.515625x17.46875]

View file

@ -2,9 +2,9 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x600 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x100 children: not-inline
BlockContainer <div> at (8,8) content-size 784x100 children: not-inline
BlockContainer <div.square.white> at (8,8) content-size 100x100 floating [BFC] children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
BlockContainer <div.square.white> at (8,8) content-size 100x100 floating [BFC] children: not-inline
TextNode <#text>
BlockContainer <div.clearfix> at (8,108) content-size 784x0 children: not-inline
BlockContainer <(anonymous)> at (8,108) content-size 784x0 children: inline
@ -18,8 +18,8 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x600]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x100]
PaintableWithLines (BlockContainer<DIV>) [8,8 784x100]
PaintableWithLines (BlockContainer<DIV>.square.white) [8,8 100x100]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableWithLines (BlockContainer<DIV>.square.white) [8,8 100x100]
PaintableWithLines (BlockContainer<DIV>.clearfix) [8,108 784x0]
PaintableWithLines (BlockContainer(anonymous)) [8,108 784x0]
PaintableWithLines (BlockContainer<DIV>.square.black) [8,108 49x49]

View file

@ -3,9 +3,9 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline
TextNode <#text>
BlockContainer <body> at (8,8) content-size 784x17.46875 children: not-inline
BlockContainer <div#b> at (9,9) content-size 50x50 floating [BFC] children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
BlockContainer <div#b> at (9,9) content-size 50x50 floating [BFC] children: not-inline
TextNode <#text>
BlockContainer <div#a> at (8,8) content-size 784x17.46875 children: inline
line 0 width: 37.578125, height: 17.46875, bottom: 17.46875, baseline: 13.53125
@ -18,9 +18,9 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x60]
PaintableWithLines (BlockContainer(anonymous)) [0,0 800x0]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x17.46875]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x17.46875] overflow: [8,8 784x52]
PaintableWithLines (BlockContainer<DIV>#b) [8,8 52x52]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableWithLines (BlockContainer<DIV>#b) [8,8 52x52]
PaintableWithLines (BlockContainer<DIV>#a) [8,8 784x17.46875]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,25.46875 784x0]

View file

@ -3,19 +3,19 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline
TextNode <#text>
BlockContainer <body> at (8,8) content-size 784x600 children: not-inline
BlockContainer <div.blue.absolute> at (208,208) content-size 200x200 positioned [BFC] children: inline
TextNode <#text>
BlockContainer <div.red.absolute> at (308,308) content-size 100x100 positioned [BFC] children: not-inline
TextNode <#text>
BlockContainer <div.yellow.absolute> at (258,258) content-size 100x100 positioned [BFC] children: inline
TextNode <#text>
BlockContainer <div.black.absolute> at (308,308) content-size 50x50 positioned [BFC] children: not-inline
TextNode <#text>
TextNode <#text>
BlockContainer <div.green.absolute> at (508,508) content-size 100x100 positioned [BFC] children: not-inline
TextNode <#text>
BlockContainer <(anonymous)> at (8,8) content-size 784x0 children: inline
TextNode <#text>
BlockContainer <div.blue.absolute> at (208,208) content-size 200x200 positioned [BFC] children: inline
TextNode <#text>
BlockContainer <div.red.absolute> at (308,308) content-size 100x100 positioned [BFC] children: not-inline
TextNode <#text>
BlockContainer <div.yellow.absolute> at (258,258) content-size 100x100 positioned [BFC] children: inline
TextNode <#text>
BlockContainer <div.black.absolute> at (308,308) content-size 50x50 positioned [BFC] children: not-inline
TextNode <#text>
TextNode <#text>
BlockContainer <div.green.absolute> at (508,508) content-size 100x100 positioned [BFC] children: not-inline
TextNode <#text>
TextNode <#text>
BlockContainer <div.blue> at (8,8) content-size 200x200 children: not-inline
BlockContainer <(anonymous)> at (8,8) content-size 200x0 children: inline
@ -39,12 +39,12 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 800x616]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x616]
PaintableWithLines (BlockContainer(anonymous)) [0,0 800x0]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x600]
PaintableWithLines (BlockContainer<DIV>.blue.absolute) [208,208 200x200]
PaintableWithLines (BlockContainer<DIV>.red.absolute) [308,308 100x100]
PaintableWithLines (BlockContainer<DIV>.yellow.absolute) [258,258 100x100]
PaintableWithLines (BlockContainer<DIV>.black.absolute) [308,308 50x50]
PaintableWithLines (BlockContainer<DIV>.green.absolute) [508,508 100x100]
PaintableWithLines (BlockContainer(anonymous)) [8,8 784x0]
PaintableWithLines (BlockContainer<DIV>.blue.absolute) [208,208 200x200]
PaintableWithLines (BlockContainer<DIV>.red.absolute) [308,308 100x100]
PaintableWithLines (BlockContainer<DIV>.yellow.absolute) [258,258 100x100]
PaintableWithLines (BlockContainer<DIV>.black.absolute) [308,308 50x50]
PaintableWithLines (BlockContainer<DIV>.green.absolute) [508,508 100x100]
PaintableWithLines (BlockContainer<DIV>.blue) [8,8 200x200] overflow: [8,8 200x300]
PaintableWithLines (BlockContainer(anonymous)) [8,8 200x0]
PaintableWithLines (BlockContainer<DIV>.red) [8,8 100x100]

View file

@ -9,9 +9,9 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <(anonymous)> at (8,16) content-size 1280x0 children: inline
TextNode <#text>
BlockContainer <div> at (8,16) content-size 1280x400 children: not-inline
ImageBox <img> at (488,16) content-size 800x400 floating children: not-inline
BlockContainer <(anonymous)> at (8,16) content-size 1280x0 children: inline
TextNode <#text>
ImageBox <img> at (488,16) content-size 800x400 floating children: not-inline
TextNode <#text>
BlockContainer <p> at (8,16) content-size 1280x17.46875 children: inline
line 0 width: 37.21875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
@ -33,8 +33,8 @@ ViewportPaintable (Viewport<#document>) [0,0 800x600] overflow: [0,0 1288x824]
PaintableWithLines (BlockContainer<DIV>.foo) [8,16 1280x800]
PaintableWithLines (BlockContainer(anonymous)) [8,16 1280x0]
PaintableWithLines (BlockContainer<DIV>) [8,16 1280x400]
ImagePaintable (ImageBox<IMG>) [488,16 800x400]
PaintableWithLines (BlockContainer(anonymous)) [8,16 1280x0]
ImagePaintable (ImageBox<IMG>) [488,16 800x400]
PaintableWithLines (BlockContainer<P>) [8,16 1280x17.46875]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,49.46875 1280x0]

View file

@ -3,9 +3,9 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <(anonymous)> at (0,0) content-size 800x0 children: inline
TextNode <#text>
BlockContainer <body> at (8,16) content-size 784x17.46875 children: not-inline
ImageBox <img> at (8,16) content-size 200x100 floating children: not-inline
BlockContainer <(anonymous)> at (8,16) content-size 784x0 children: inline
TextNode <#text>
ImageBox <img> at (8,16) content-size 200x100 floating children: not-inline
TextNode <#text>
BlockContainer <p> at (8,16) content-size 784x17.46875 children: inline
line 0 width: 37.21875, height: 17.46875, bottom: 17.46875, baseline: 13.53125
@ -18,9 +18,9 @@ Viewport <#document> at (0,0) content-size 800x600 children: not-inline
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x116]
PaintableWithLines (BlockContainer(anonymous)) [0,0 800x0]
PaintableWithLines (BlockContainer<BODY>) [8,16 784x17.46875] overflow: [8,16 784x33.46875]
PaintableWithLines (BlockContainer<BODY>) [8,16 784x17.46875] overflow: [8,16 784x100]
ImagePaintable (ImageBox<IMG>) [8,16 200x100]
PaintableWithLines (BlockContainer(anonymous)) [8,16 784x0]
ImagePaintable (ImageBox<IMG>) [8,16 200x100]
PaintableWithLines (BlockContainer<P>) [8,16 784x17.46875]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,49.46875 784x0]

View file

@ -0,0 +1,38 @@
<!DOCTYPE html><style>
* {
outline: 1px solid black;
margin: 0;
padding: 0;
}
body {
position: relative;
}
#d_header {
background: pink;
width: 400px;
height: 30px;
}
#d_scene_btns {
float: left;
}
#button {
width: 50px;
height: 50px;
background: orange;
}
#button:hover {
background: red;
}
</style><body><div id="d_header"><div id="d_scene_btns"><div id="button"></div></div> <div class="clear"></div>
<div id="box"></div>
<script src="../include.js"></script>
<script>
test(() => {
println(internals.hitTest(5, 5).node === document.getElementById("button"));
});
</script>

View file

@ -121,9 +121,16 @@ static Layout::Node& insertion_parent_for_block_node(Layout::NodeWithStyle& layo
// Parent block has inline-level children (our siblings).
// First move these siblings into an anonymous wrapper block.
Vector<JS::Handle<Layout::Node>> children;
while (JS::GCPtr<Layout::Node> child = layout_parent.first_child()) {
layout_parent.remove_child(*child);
children.append(*child);
{
JS::GCPtr<Layout::Node> next;
for (JS::GCPtr<Layout::Node> child = layout_parent.first_child(); child; child = next) {
next = child->next_sibling();
// NOTE: We let out-of-flow children stay in the parent, to preserve tree structure.
if (child->is_floating() || child->is_absolutely_positioned())
continue;
layout_parent.remove_child(*child);
children.append(*child);
}
}
layout_parent.append_child(layout_parent.create_anonymous_wrapper());
layout_parent.set_children_are_inline(false);

View file

@ -805,7 +805,7 @@ Optional<HitTestResult> PaintableBox::hit_test(CSSPixelPoint position, HitTestTy
Optional<HitTestResult> PaintableWithLines::hit_test(CSSPixelPoint position, HitTestType type) const
{
if (!layout_box().children_are_inline())
if (!layout_box().children_are_inline() || m_line_boxes.is_empty())
return PaintableBox::hit_test(position, type);
Optional<HitTestResult> last_good_candidate;