Commit graph

207 commits

Author SHA1 Message Date
Andreas Kling
bfcb4d88cf LibWeb: Treat percentage heights as "auto" if unresolvable
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.
2022-09-09 15:20:10 +02:00
Andreas Kling
3f960781fd LibWeb: Don't collapse vertical margins between floats
Just stack floats at their vertical margin edge instead of letting their
border boxes rub up against each other.
2022-09-09 15:20:10 +02:00
Andreas Kling
7ba6eb37fc LibWeb: Rename confusing parameter to layout_block_level_box()
It wasn't the content height, but rather the the bottom edge of the
lowest margin box.
2022-09-08 15:03:55 +02:00
Andreas Kling
af73a5d921 LibWeb: Use correct box edge when looking for space between floats 2022-09-08 15:03:55 +02:00
Andreas Kling
514fa83708 LibWeb: Improve float: right behavior
- 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.
2022-09-07 17:47:33 +02:00
martinfalisse
65e7126c48 LibWeb: Factor out compute_y_position
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.
2022-08-14 11:22:52 +02:00
MacDue
6a6475673f LibWeb: Convert images to common AbstractImageStyleValue base
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.
2022-08-08 22:39:06 +02:00
MacDue
a6505f6e6d LibWeb: Allow % height of a % height parent in block-formatted elements
With this you can start to see Francine's face in the CSS oil painting
(https://diana-adrianne.com/purecss-francine/)
2022-08-07 22:52:22 +02:00
Andreas Kling
3ede8dbffb LibWeb: Rename IntrinsicSizeDetermination to IntrinsicSizing
This matches the exact terminology used in CSS-SIZING-3:
https://drafts.csswg.org/css-sizing-3/#intrinsic-sizing
2022-07-26 01:53:41 +02:00
Andreas Kling
71a707480c LibWeb: Move "has-definite-width/height" flags to UsedValues
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.
2022-07-26 01:53:41 +02:00
Andreas Kling
ed8930fff5 LibWeb: Add accessors for UsedValues::computed_{width,height}
This is preparation for doing some more work when assigning to these
values.
2022-07-19 15:40:41 +02:00
Andreas Kling
52862c72d0 LibWeb: Rename FormattingState to LayoutState
This seems a bit more descriptive (and also a bit shorter).
2022-07-17 14:11:36 +02:00
Andreas Kling
61c27815e4 LibWeb: More specialization of intrinsic sizing layout
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.
2022-07-11 18:57:45 +02:00
Andreas Kling
9784a567d2 LibWeb: Factor out BFC "layout this block-level box" to a function 2022-07-11 18:57:45 +02:00
Andreas Kling
64959a8504 LibWeb: Express intrinsic size layout via size constraints
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
2022-07-11 18:57:45 +02:00
Andreas Kling
66d08d2417 LibWeb: Move IFC result measurement from IFC to BFC
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.
2022-07-11 18:57:45 +02:00
Andreas Kling
fd68be29ab LibWeb: Make BFC always drive IFC
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.
2022-07-11 18:57:45 +02:00
Andreas Kling
cefc931347 LibWeb: Make sure CSS::ComputedValues has initial size values
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.
2022-07-09 22:16:35 +02:00
MacDue
61a703816c LibWeb: Base marker size on font height rather than line height
This fixes the oversized markers on GitHub
2022-07-09 09:28:31 +01:00
Karol Kosek
a0bea0b86f LibWeb: Calculate floating elements width using min- and max-width
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.
2022-06-06 09:14:42 +01:00
Andreas Kling
fc8c4ea23f LibWeb: Let BFC compute width for block-level replaced elements
We never really hit this code path before, but now that IMG elements can
be block-level, we need to get them hooked up with box model metrics.
2022-04-11 01:04:09 +02:00
Andreas Kling
20c65e4298 LibWeb: Don't include children of overflow:hidden in scrollable overflow
This fixes an issue where Google Maps was getting page scrollbars
when it shouldn't have.
2022-04-10 20:02:53 +02:00
Enver Balalic
d8ec9a5501 LibWeb: Fix computing_width of a block when LayoutMode::MaxContent
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.
2022-04-03 12:58:08 +02:00
Idan Horowitz
086969277e Everywhere: Run clang-format 2022-04-01 21:24:45 +01:00
Andreas Kling
9711e1b303 LibWeb: Make floating boxes in IFC occupy horizontal margin box
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.
2022-03-29 12:35:31 +02:00
Simon Wanner
e5a779aecf LibWeb: Apply the layout_mode argument in BFC::compute_width 2022-03-28 15:25:25 +02:00
Andreas Kling
3ac9ea369d LibWeb: Don't choke on ICB with inline children
Let's relax our assumption about what kind of children the ICB has.
This is preparation for loading XHTML documents.
2022-03-27 23:38:27 +02:00
Andreas Kling
d77dfc6b48 LibWeb: Rename FormattingContext::compute_position() => compute_inset()
This function computes the used inset properties, not the position of a
box per se, so let's call it something more accurate.
2022-03-27 18:16:08 +02:00
Andreas Kling
c49c036c84 LibWeb: Stop allowing position:relative to affect layout
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. :^)
2022-03-27 18:16:08 +02:00
Andreas Kling
0d9c28add9 LibWeb: Don't collapse horizontal margins between floating boxes
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.
2022-03-26 22:12:21 +01:00
Andreas Kling
aefe1727fc LibWeb: Make text newlines in "pre" mode emit a ForcedBreak item
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.
2022-03-26 20:04:56 +01:00
Andreas Kling
fe908e7db2 LibWeb: Rename "offset" in box model metrics to "inset"
The CSS Positioned Layout spec refers to the top/left/bottom/right
properties as "inset" properties, so let's use the same terminology.
2022-03-26 17:31:01 +01:00
Andreas Kling
c02e6f991a LibWeb: Improve vertical margin collapse between adjacent blocks
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.
2022-03-25 00:10:09 +01:00
Andreas Kling
de6f7f0029 LibWeb: Support CSS floats in inline flow
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.
2022-03-22 19:26:51 +01:00
Andreas Kling
c1f0d21bbe LibWeb: Rename the LayoutMode enum values and explain them
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.
2022-03-19 15:46:15 +01:00
Andreas Kling
a19b9b727d LibWeb: Place right-side floats relative to their containing block
We were incorrectly placing them relative to the BFC root, but CSS2
says they are relative to their own containing block.
2022-03-18 19:28:58 +01:00
Simon Wanner
a2331e8dd3 LibWeb: Implement CSS transforms on stacking contexts
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 :^)
2022-03-18 18:51:42 +01:00
Andreas Kling
39b7fbfeb9 LibWeb: Rewrite CSS float implementation to use offset-from-edge
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.)
2022-03-18 15:18:48 +01:00
Andreas Kling
ef8a72ff3f LibWeb: Move available_space_for_line() from IFC to BFC
This is preparation for allowing blocks with their own internal BFC to
flow around floating boxes in the parent BFC.

Note that IFC still has the available_space_for_line() API, which
returns space available within the IFC's own containing block, while the
BFC available_space_for_line() returns space available within its root.
2022-03-18 15:18:48 +01:00
Andreas Kling
6de10858b9 LibWeb: Only collapse vertical margin between BlockContainer siblings
If there's some non-block-level box (like an SVG element of some kind)
between to blocks, just skip over the non-block for purposes of margin
collapsing. This is basically a hack, and something we'll need to
improve as part of our general SVG support.
2022-03-13 00:04:51 +01:00
Andreas Kling
c2a66b77df LibWeb: Measure intrinsic block width *around* children's border edge
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.
2022-03-04 12:34:26 +01:00
Andreas Kling
56df05ae44 LibWeb: Always include floats when computing height:auto for blocks
I'm not sure why we had two modes for this, but floats should always be
included in the auto height AFAICT.
2022-03-01 19:01:19 +01:00
Andreas Kling
726edd2d3b LibWeb: Pass state to create_independent_formatting_context_if_needed()
Instead of using the current m_state implicitly, make this function take
a FormattingState&. This will allow us to use it for throwaway layouts.
2022-02-28 14:17:44 +01:00
Andreas Kling
8c2a4a2a3d LibWeb: Calculate edge of containing block correctly when floating right 2022-02-21 20:42:34 +01:00
Andreas Kling
f21a0bf437 LibWeb: Don't shift right-floated boxes too much to the left
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. :^)
2022-02-21 20:42:34 +01:00
Andreas Kling
db5bf6e64c LibWeb: Rename FormattingState::ensure() -> get_mutable()
This makes it much more obvious what the difference between get() and
get_mutable() is.
2022-02-21 18:35:12 +01:00
Andreas Kling
2615728d6b LibWeb: Store overflow data in the FormattingState 2022-02-21 18:35:12 +01:00
Andreas Kling
92266d2247 LibWeb: Create list-item markers during layout tree construction
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.
2022-02-21 18:35:12 +01:00
Andreas Kling
c9700e100e LibWeb: Start making our layout system "transactional"
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.
2022-02-21 18:35:12 +01:00
Andreas Kling
561612f219 LibWeb: Add Layout::FormattingState
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. :^)
2022-02-21 18:35:12 +01:00