-
-
Notifications
You must be signed in to change notification settings - Fork 1.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
LibWeb: Correctly lay out block elements inside inline elements #3276
LibWeb: Correctly lay out block elements inside inline elements #3276
Conversation
92e2698
to
e3732e8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
have you considered solving the problem on paintable tree level? I suppose webkit has to use continuations on layout tree because they do not have paintable tree concept, while we do and support 1:N relationship between layout and paintable nodes.
49dd2f9
to
827da96
Compare
@kalenikaliaksandr @awesomekling I've rearranged some things:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could we add a test for hit-testing just so we can be sure it works as expected when it comes to continuations?
Absolutely, in fact, I'm also working on a bugfix for something depending on this that involves hit-testing. I'll tack on the commit to this PR. |
Ran into a simple case that doesn't work correctly: Well <span> hello <div>friends |
Well that's embarrassing! I'll take a look |
And here's a basic dynamic case that doesn't work -- looks like we don't propagate style changes to the split layout nodes. <!doctype html>
<style>
* { font-family: sans-serif; }
</style>
<script>
onload = function() {
document.body.offsetWidth; // force a layout
a.setAttribute("style", null);
}
</script>
</head>
<body>
<span id="a" style="font-weight: bold;">hello <div>inner</div></span>
</body> |
Your pull request has conflicts that need to be resolved before it can be reviewed and merged. Make sure to rebase your branch on top of the latest |
827da96
to
85d6717
Compare
78e1a95
to
7b87570
Compare
@kalenikaliaksandr @awesomekling some more updates:
W/ regard to that last point, it seems to be working correctly but similar to propagating styles to anonymous wrappers (see the |
7b87570
to
48c5a98
Compare
Hit-testing was improved with respect to continuation chains, where we now consider inline elements that are parents of block elements to be valid targets of a hit-test even if that block element has This fixes the |
This allows for easy child removal similar to `DOM::Node::remove()`.
The existing `::unite_horizontally()` and `::unite_vertically()` tests did not properly test the edge cases where left/top in the Rect were updated, so they get re-arranged a bit.
48c5a98
to
071b80a
Compare
Our layout tree requires that all containers either have inline or non-inline children. In order to support the layout of non-inline elements inside inline elements, we need to do a bit of tree restructuring. It effectively simulates temporarily closing all inline nodes, appending the block element, and resumes appending to the last open inline node. The acid1.txt expectation needed to be updated to reflect the fact that we now hoist its <p> elements out of the inline <form> they were in. Visually, the before and after situations for acid1.html are identical.
There are many simpler APIs that we can use here. No functional changes.
Instead of ignoring any paintable immediately when they're invisible to hit-testing, consider every candidate and while the most specific candidate is invisible to hit-testing, traverse up to its parent paintable. This more closely reflects the behavior expected when wrapping block elements inside inline elements, where although the block element might have `pointer-events: none`, it still becomes part of the hit-test body of the inline parent. This makes the following link work as expected: <a href="https://ladybird.org"> <div style="pointer-events: none">Ladybird</div> </a>
071b80a
to
38dab84
Compare
Fixes #959 (?) |
The contents of inline elements containing a block element were incorrectly ordered, e.g.
...did not render the
<div>
as being in between thefoo
andbaz
fragments.Excerpt from
Web::Layout::TreeBuilder
:Block nodes inside inline nodes are allowed, but to maintain the invariant that either all layout children are
inline or non-inline, we need to rearrange the tree a bit. All inline ancestors up to the node we've inserted are
wrapped in an anonymous block, which is inserted into the nearest non-inline ancestor. We then recreate the inline
ancestors in another anonymous block inserted after the node so we can continue adding children.
Effectively, we try to turn this:
Into this:
To be able to reconstruct their relation after restructuring, layout nodes keep track of their continuation. The
top-most inline node of the "after" wrapper points to the "middle" wrapper, which points to the top-most inline node
of the "before" wrapper. All other inline nodes in the "after" wrapper point to their counterparts in the "before"
wrapper, to make it easier to create the right paintables since a DOM::Node only has a single Layout::Node.
Appending then continues in the "after" tree. If a new block node is then inserted, we can reuse the "middle" wrapper
if no inline siblings exist for node or its ancestors, and leave the existing "after" wrapper alone. Otherwise, we
create new wrappers and extend the continuation chain.
Inspired by: https://webkit.org/blog/115/webcore-rendering-ii-blocks-and-inlines/