Commit graph

20 commits

Author SHA1 Message Date
Andreas Kling
5d4e9a0673 LibWeb: Basic support for CSS text-indent: <length-percentage>
Note that this simple form of text-indent only affects the first line
of formatted content in each block.

Percentages are resolved against the width of the block.
2023-05-15 19:31:09 +02:00
Sam Atkins
76047d1932 LibWeb: Convert InlineLevelIterator/LineBox/LineBuilder to new px units 2023-01-05 17:42:31 +01:00
Andreas Kling
412b2313f3 LibWeb: Improve inline flow around floating boxes
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.
2022-09-16 15:15:50 +02:00
Andreas Kling
71ca857b67 LibWeb: Break lines until we have enough space between floats
Before this change, we'd always insert one line box fragment, even when
a float was taking up too much space on the line, and the fragment
didn't actually fit.

We now perform line breaks until we have enough space between floats.
This fixes many page layouts where we'd previously see small fragments
of inline content outside the right edge of the containing block.
2022-09-13 17:03:31 +02:00
Andreas Kling
ab6af4c9a0 LibWeb: Remove unused member LineBuilder::m_layout_mode 2022-08-14 23:33:28 +02:00
Andreas Kling
9b46091f38 LibWeb: Rename LayoutState::NodeState => LayoutState::UsedValues
This object contains all the CSS "used values" as seen during the layout
process, so calling it "used values" seems appropriate. :^)
2022-07-17 14:11:37 +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
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
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
d32630e17b LibWeb: Don't append collapsible whitespace to start of new line
After performing a required line break, and the next text chunk is
all collapsible whitespace, simply discard the whitespace.
2022-03-26 20:04:56 +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
28642de6ed LibWeb: Make LineBuilder aware of the current LayoutMode
This will allow us to override the available space correctly when doing
intrinsic sizing.
2022-03-18 15:18:48 +01:00
Andreas Kling
45f717cfad LibWeb: Respect inline-axis margins between line box fragments :^)
This makes the buckets on ACID3 space out nicely.
2022-03-09 18:47:32 +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
f2a917229a LibWeb: Support inline-level padding and border properly
Here's roughly how this works:

- InlineLevelIterator keeps a nesting stack of inline-level nodes with
  box model metrics.
- When entering a node with box model metrics, we add them to the
  current "leading metrics".
- When exiting a node with box model metrics, we add them to the
  current "trailing metrics".
- Pending leading metrics are consumed by the first fragment added
  to the line.
- Pending trailing metrics are consumed by the last fragment added
  to the line.

Like before, the position of a line box fragment is the top left of its
content box. However, fragments are placed horizontally along the line
with space inserted for padding and border.

InlineNode::paint() now expands the content rect as appropriate when
painting background and borders.

Note that margins and margin collapsing is not yet implemented.

This makes the eyes on ACID2 horizontally centered. :^)
2022-02-14 18:00:21 +01:00
Andreas Kling
b60e19fd34 LibWeb: Make LineBuilder assign height to empty line boxes
This ensures that <br> produces empty line boxes with the line-height
property as their height.
2022-01-23 01:36:13 +01:00
Andreas Kling
70a56d21dc LibWeb: Don't do horizontal inline line layout twice for last line
After pruning empty last line boxes, we now avoid re-running the
horizontal fragment positioning step, since that would be wasted work.
2022-01-23 01:22:41 +01:00
Andreas Kling
251b2f49a2 LibWeb: Make LineBuilder respect LayoutMode::OnlyRequiredLineBreaks
In this layout mode, we should only break when forced (e.g by an
explicit <br> tag.) This is used when determining intrinsic sizes.)
2022-01-23 01:22:41 +01:00
Andreas Kling
d3adc94ce8 LibWeb: Dimension inline-block boxes before deciding about line breaks
We won't know if we need to break before the inline-block box until
after we've dimensioned it.
2022-01-23 01:22:41 +01:00
Andreas Kling
00bde9ca51 LibWeb: Add Layout::LineBuilder class for incremental line box layout
This class will be used to place items on lines incrementally instead of
the current two-phase approach.
2022-01-23 01:22:41 +01:00