This patch changes the *computed* representation of the following CSS
properties to use CSS::Size:
- width, min-width, max-width
- height, min-height, max-height
A few things had to change in order for things to keep working,
but I tried to keep the diff to a minimum.
The main trouble was that `min-width` and `max-width` can't actually be
`auto`, but they *can* be `none`. We previously treated `auto` as a
valid value (and it behaved mostly like `none`).
This was used by FFC to estimate the height of flex items after
performing layout inside them.
Now that we have automatic_content_height(), we no longer need this
awkward API and we can fold it into BFC's own height calculation.
This function should return the automatic height of the formatting
context's root box.
Until now, we've been relying on some magical handshakes between parent
and child context, when negotiating the height of child context root
boxes. This is a step towards something more reasonable.
We were forgetting to convert to and from BFC root relative coordinates
when calculating how much clearance was needed to get past floats.
This fixes the last remaining issue on Acid1, which is now perfect. :^)
We already had a helper for this, but compute_height() wasn't using it.
Tweak it so that compute_height() can use it, and remove the duplicated
code that's now redundant.
This patch combines a number of techniques to make inline content flow
more correctly around floats:
- During inline layout, BFC now lets LineBuilder decide the Y coordinate
when inserting a new float. LineBuilder has more information about the
currently accumulated line, and can make better breaking decisions.
- When inserting a float on one side, and the top of the newly inserted
float is below the bottommost float on the opposite side, we now reset
the opposite side back to the start of that edge. This improves
breaking behavior between opposite-side floats.
- After inserting a float during inline layout, we now recalculate the
available space on the line, but don't adjust X offsets of already
existing fragments. This is handled by update_last_line() anyway,
so it was pointless busywork.
- When measuring whether a line can fit at a given Y coordinate, we now
consider both the top and bottom Y values of the line. This fixes an
issue where the bottom part of a line would bleed over other content
(since we had only checked that the top Y coordinate of that line
would fit.)
There are some pretty brain-dead algorithms in here that we need to make
smarter, but I didn't want to complicate this any further so I've left
FIXMEs about them instead.
This remained undetected for a long time as HeaderCheck is disabled by
default. This commit makes the following file compile again:
// file: compile_me.cpp
#include <LibWeb/CSS/GridTrackSize.h>
// That's it, this was enough to cause a compilation error.
By asking if the value *contains* a percentage rather than whether it
*is* one, we cover many more cases where e.g `width: calc(100% - 10px)`
should be "treated as auto" etc.
If the containing block has indefinite height, we can't resolve
percentage heights against it. Instead of treating it as 0 by accident,
let's treat it as "auto" on purpose.
This brings back the cheek borders on Acid2.
- Use the border box of the floated element when testing if something
needs to flow around it.
- Take the floated element's containing block size into account (instead
of the BFC root) when calculating available space on a line where a
right-side float intrudes.
Factor out the code that computes the vertical position of a Box with
respect to its siblings so that it can be used when computing the
absolutely positioned divs as well.
This commit moves both the ImageStyleValue and LinearGradientStyleValue
to a common base class of AbstractImageStyleValue. This abstracts
getting the natural_width/height, loading/resolving, and painting
the image.
Now for 'free' you get:
- Linear gradients working with the various background sizing/repeat
properties.
- Linear gradients working as list-markers :^) -- best feature ever!
P.s. This commit is a little large as it's tricky to make this change
incrementally without breaking things.
This state is less static than we originally assumed, and there are
special formatting context-specific rules that say certain sizes are
definite in special circumstances.
To be able to support this, we move the has-definite-size flags from
the layout node to the UsedValues struct instead.
This patch adds a separate entry point for this kind of layout.
We override it in BFC to set up initial width/height values for the
BFC root block.
Resulting dimensions are assigned as content_width and content_height
at the end of intrinsic sizing, for each axis, if it's either "auto"
or there's a min-content or max-content constraint in effect.
Previously, we had three layout modes:
- Normal:
- Everything uses the computed values from CSS.
- MinContent:
- Containing blocks act as if they have 0 width.
- All line breaking opportunities are taken.
- MaxContent:
- Containing blocks act as if they have infinite width.
- Only forced line breaks are accepted.
The above was based on a set of misunderstandings of CSS sizing.
A major problem with the above was that *all* containing blocks
behaved differently during intrinsic size layout, not just the
relevant one.
With this patch there are only two layout modes:
- Normal:
- Everything uses the computed values from CSS.
- IntrinsicSizeDetermination:
- One or more boxes have size constraints applied.
There are two size constraints per layout box, set here:
- FormattingState::NodeState::width_constraint
- FormattingState::NodeState::height_constraint
They are of type SizeConstraint and can be one of None, MinContent,
or MaxContent. The default is None.
When performing an IntrinsicSizeDetermination layout, we now assign
a size constraint to the box we're trying to determine the intrinsic
size of, which is then honored by using two new helpers to query
the dimensions of containing blocks:
- FormattingContext::containing_block_width_for(Box)
- FormattingContext::containing_block_height_for(Box)
If there's a relevant constraint in effect on the Box, the size of
its containing block is adjusted accordingly.
This is essentially an implementation of the "available space"
constraints from CSS-SIZING-3. I'm sure some things will break from
this, and we'll have to deal with that separately.
Spec: https://drafts.csswg.org/css-sizing-3/#available
Before this change, IFC would first generate all of its line boxes
and then measure them. It would then write some of the values into
the state of the IFC's containing block.
We now move that up to BFC::layout_inline_children() instead, which
is a much more natural place to decide metrics for the block.
Instead of allowing FormattingContext to instantiate an IFC for anything
that has inline children, move this logic to BFC.
This is fine, since only BFC deals with blocks having inline children
anyway.
Instead of using Optional<LengthPercentage>, we now use LengthPercentage
for these values. The initial values are all `auto`.
This avoids having to check `has_value()` in a ton of places.
Previously, floating elements computed the width by only using the
`width` property. Now, they will also use the `min-width` and
`max-width` properties. :^)
The new steps are from "10.4. Minimum and maximum widths: 'min-width'
and 'max-width'" in the CSS 2 spec.
Found it when looking at curl.se.
We had an issue with computing a width of a block in MaxContent
mode because we would set the width of the containing block to
infinity which would make everything in the try_compute_width
block infinity as well.
This adds a special case for width = 'auto' when
width_of_containing_block is infinity and removes the width of
containing block from the equation entirely.
Previously, we only allowed floats to take up its own border box's worth
of horizontal space when laid out inside an IFC.
We should instead consume the full margin box horizonally. This fixes an
issue where a floated box on Acid3 had {width:20px; margin-right:-20px;}
but still consumed 20px of the previously available space, despite being
moved out of the way by its own negative margin.
Relatively positioned boxes should not affect the *layout* of their
siblings. So instead of applying relative inset as a layout-time
translation on the box, we now perform the adjustment at the paintable
level instead.
This makes position:relative actually work as expected, and exposes some
new bugs we need to take care of for Acid2. :^)
CSS 2.2 says "Horizontal margins never collapse."
So instead of collapsing them, we now add them together, which makes
negative margins between floating boxes work beautifully.
Instead of emitting a Text item with the "should_force_break" flag set
to true, newlines in newline-preserving text content now timply turn
into ForcedBreak items. This makes the <pre> element work again.
Collect all the preceding block-level siblings whose vertical margins
are collapsible. Both margin-top and margin-bottom now (previously,
we only considered the margin-bottom of siblings.)
Use the right margin in part-negative and all-negative situations.
CSS floats are now emitted by the InlineLevelIterator. When this
happens, IFC coordinates with the parent BFC to float the box to the
side, using the current LineBuilder state for vertical placement.
This makes the "instructions" text on Acid3 render as a single
contiguous flow of inline content.
The old mode names, while mechanically accurate, didn't really reflect
their relationship to the CSS specifications.
This patch renames them as follows:
Default => Normal
AllPossibleLineBreaks => MinContent
OnlyRequiredLineBreaks => MaxContent
There's also now an explainer comment with the LayoutMode enum about the
specific implications of layout in each mode.
Since there is currently no easy way to handle rotations and skews
with LibGfx this only implements translation and scaling by first
constructing a general 4x4 transformation matrix like outlined in
the css-transforms-1 specification. This is then downgraded to a
Gfx::AffineTransform in order to transform the destination rectangle
used with draw_scaled_bitmap()
While rotation would be nice this already looks pretty good :^)
The previous implementation used relative X offsets for both left and
right-side floats. This made right-side floats super awkward, since we
could only determine their X position once the width of the BFC root was
known, and for BFC roots with automatic width, this was not even working
at all most of the time.
This patch changes the way we deal with floats so that BFC keeps track
of the offset-from-edge for each float. The offset is the distance from
the BFC root edge (left or right, depending on float direction) to the
"innermost" margin edge of the floating box.
Floating box are now laid out in two passes: while going through the
normal flow layout, we put floats in their *static* position (i.e the
position they would have occupied if they weren't floating) and then
update the Y position value to the final one.
The second pass occurs later on, when the BFC root has had its width
assigned by the parent context. Once we know the root width, we can
set the X position value of floating boxes. (Because the X position of
right-side floats is relative to the right edge of the BFC root.)