BlockContainer paint boxes are the only ones that have line boxes
associated, so let's not waste memory on line boxes in all the other
types of boxes.
This also adds Layout::Box::paint_box() and the more tightly typed
Layout::BlockContainer::paint_box() to get at the paint box from the
corresponding layout box.
The "paintable" state in Layout::Box was actually not safe to access
until after layout had been performed.
As a first step towards making this harder to mess up accidentally,
this patch moves painting information from Layout::Box to a new class:
Painting::Box. Every layout can have a corresponding paint box, and
it holds the final used metrics determined by layout.
The paint box is created and populated by FormattingState::commit().
I've also added DOM::Node::paint_box() as a convenient way to access
the paint box (if available) of a given DOM node.
Going forward, I believe this will allow us to better separate data
that belongs to layout vs painting, and also open up opportunities
for naturally invalidating caches in the paint box (since it's
reconstituted by every layout.)
Note that we don't put absolutely positioned items on a line! This is
just so that IFC can discover boxes and pass them along to BFC.
This fixes an issue where only direct children of the IFC containing
block were considered for absolute positioning. Now we pick up
absolutely positioned children of nested inline nodes as well.
This patch adds support for "crisp-edges", "high-quality" and "smooth"
for the CSS image-rendering property.
"crisp-edges" maps to nearest-neighbor scaling for <canvas> and <img>
elements, while "high-quality" and "smooth" both use bilinear blending.
Previously, the decoration was painted behind the text. This probably
wasn't noticed before, as we didn't compute `text-decoration-color`
values yet and the decoration had the same color anyway.
Previosly, we used only the text color as a line decoration color.
The FIXME comment has been directly copy-pasted from the border color
note a few lines below.
If the content wants to be pixelated, we should honor that and paint
with nearest-neighbor scaling. The fact that it's faster is a nice bonus
as well. :^)
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.