When calculating the intrinsic width of a block-level box, we were
previously measuring the content boxes of children. This meant that
shrink-to-fit sized blocks didn't gain enough width to contain children
with horizontal padding and/or border.
Until now, we've been treating the bottom of every line box fragment as
its baseline, and just aligning all the bottoms to the bottom of the
line box. That gave decent results in many cases, but was not correct.
This patch starts moving towards actual baseline calculations as
specified by CSS2.
Note that once layout is finished with a line box, we also store the
baseline of the line box in LineBox::m_baseline. This allows us to align
the real baseline of display:inline-block elements with other inline
content on the same line.
I was wrong in 56df05ae44, there are
situations where floating children should not affect the auto height of
their parent.
It turns out we were using the "height:auto for BFC roots" algorithm for
all height:auto blocks. This patch fixes that by splitting it into two
separate functions, and implementing most of the two different variants.
Note that we don't support vertical margin collapsing here yet.
Thanks to Tim for noticing the error! :^)
If an element with height:auto has any floating descendants whose bottom
margin edge is below the element's bottom content edge, then the height
is increased to include those edges.
Before this patch, we were stopping at the bottom *content* edge of
floating descendants.
This patch begins the support for the 'view-box' attribute that can be
attached to <svg>'s.
The FormattingContext determines the size of the Element according to
the specified 'width' and 'height' or if they are not given by the
'viewbox' or by the bounding box of the path if nothing is specified.
When we try to paint a SVG Path that belongs to a <svg> that has the
'view-box' and a specified 'height'/'width', all the parts of the path
get scaled/moved accordingly.
There probably are many edge cases and bugs still to be found, but this
is a nice start. :^)
Previously we used a native ui button to draw the buttons.
These buttons can however not be styled with css.
To allow these to be styled with css, we create a button with
the UA stylesheet that resembles the system ui button.
Instead of making a full copy of every NodeState when cloning a
FormattingState, we make NodeState ref-counted and implement a basic
copy-on-write mechanism.
FormattingState::get_mutable() now makes a deep copy of the NodeState
when first accessed *if* it is shared with other FormattingStates.
We now consider a layout box as having definite size in these cases:
- The size is a <length>.
- The size is a <percentage> and the containing block has definite size.
This is not complete, but a bit more accurate than what we had before.
Previously we were computing the bottom edge of a line box by finding
the bottommost fragment on the line.
That method didn't give correct results for line boxes with no fragments
(which is exactly what you get when inserting a bunch of <br> elements.)
To cover all situations, we now keep track of the bottommost edge in the
LineBox object itself.
Using WeakPtr to remember which LineBoxFragment owns which Box was
imposing some annoying constraints on the layout code. Importantly, it
was forcing us to heap-allocate fragments, which makes it much harder to
clone a FormattingState.
This patch replaces the WeakPtr with a coordinate system instead.
Fragments are referred to by their line box index + fragment index
within the line box.
Since we now honor the CSS font-size values when deciding line box
metrics, we sometimes find ourselves needing to paint text with a bitmap
font into a box that isn't large enough for the glyphs.
As it turns out, it looks a bit better if we just grow the paint rect to
fit the glyphs (instead of painting chopped-off glyphs.) So let's just
do that for now.
If vertical-align is a length value, we lift each line box fragment that
far from the baseline of the line box.
This is rather messy, and we'll have to improve factoring as we add
support for more alignment types.
The purpose of "entering" a box is to collect box model metrics that
apply to content fragments within the box. However, inline-blocks are
special, in that their inner content does not directly participate in
the inline formatting context outside it.
We were neglecting to pop nodes from the box model stack. The metrics
were already being zeroed out when used, but let's not grow the stack
needlessly.
Instead of just the outline, fill them with some semi-transparent color.
Also add tag name, ID, classes and coordinates to the little tooltip.
Finally, use the border box instead of the context box for metrics,
same as other browsers.
Instead of re-measuring the distance between the left and right edges of
a line box, we now simply adjust the final width based on how much the
rightmost fragment moved during the alignment process.
We were painting this in the Foreground phase by mistake. Also, the
`inspected_node() == dom_node()` check returns true for pseudo-elements
(both values are nullptr) so I've added an extra check there. As noted,
once pseudo-elements are inspectable we will need to revisit this.
This means we can instantiate them for pseudo-elements, which don't have
an associated Element. They all pass it to their parent as a
`Layout::Node*` and handle a lack of `layout_node()` already so this
won't affect any functionality.
When calculating how much space is available for inline content between
left and right floated elements, we have to use coordinates in the
containing block's coordinate space, since that's what floats use.
This fixes an issue where text would sometimes overlap floats.
We were subtracting the content width of right-floated boxes from their
X position for no reason. Removing this makes floats snuggle up to each
other on the right side. :^)
When encountering a box that claims to have block-level children, but
its CSS display type isn't actually "flow" inside, we would previously
crash due to a VERIFY() failure.
However, many sites choke on this due to freestanding table-related
boxes like those created by "table-row" and "table-row-group".
We're supposed to fix those up by wrapping them in a full set of table
boxes during layout tree construction, but that algorithm obviously
isn't working correctly in all cases. So let's work around the crashes
for now, allowing many more sites to load (even if visually incorrect.)
This is a rather monstrous hack, and we should get rid of it as soon as
it's not needed anymore.
"5em" means 5*font-size, but by forcing "em" to mean the presentation
size of the bitmap font actually used, we broke a bunch of layouts that
depended on a correct interpretation of "em".
This means that "em" units will no longer be relative to the exact
size of the bitmap font in use, but I think that's a compromise we'll
have to make, since accurate layouts are more important.
This yields a visual progression on both ACID2 and ACID3. :^)
Previously, these were added during layout. This didn't fit into the new
world where layout doesn't mutate the tree incrementally, so this patch
adds logic to Layout::TreeBuilder for adding a marker to each list-item
box after its children have been constructed.
This patch adds a map of Layout::Node to FormattingState::NodeState.
Instead of updating layout nodes incrementally as layout progresses
through the formatting contexts, all updates are now written to the
corresponding NodeState instead.
At the end of layout, FormattingState::commit() is called, which
transfers all the values from the NodeState objects to the Node.
This will soon allow us to perform completely non-destructive layouts
which don't affect the tree.
Note that there are many imperfections here, and still many places
where we assign to the NodeState, but later read directly from the Node
instead. I'm just committing at this stage to make subsequent diffs
easier to understand.
The purpose of this new object will be to keep track of various states
during an ongoing layout.
Until now, we've been updating layout tree nodes as we go during layout,
which adds an invisible layer of implicit serialization to the whole
layout system.
My idea with FormattingState is that running layout will produce a
result entirely contained within the FormattingState object. At the end
of layout, it can then be applied to the layout tree, or simply queried
for some metrics we were trying to determine.
When doing subtree layouts to determine intrinsic sizes, we will
eventually be able to clone the current FormattingState, and run the
subtree layout in isolation, opening up opportunities for parallelism.
This first patch doesn't go very far though, it merely adds the object
as a skeleton class, and makes sure the root BFC has one. :^)
Normally we don't layout position:absolute elements until after the
parent formatting context has assigned dimensions to the current
formatting context's root box.
However, some of our parent contexts (especially FFC) don't do this
reliably, which makes position:absolute children have 0x0 dimensions.
Hack this for now by making ~BFC() pretend that the parent assigned
dimensions if it hadn't done it already.
This returns a String with this format:
- LayoutNodeClassName<TAG_NAME>#id.class1.class2.class3
I've rewritten this function 10+ times at this point, so I'm just gonna
add it to the repository for future debugging needs. :^)