Commit graph

53 commits

Author SHA1 Message Date
Andreas Kling
83afc1154c LibWeb: Fix IFC over-shrinking the available space for line boxes
After accounting for left-side floats, we have to subtract the offset of
the IFC's containing block again, to get the real starting X offset
for the current line.

This was done correctly in leftmost_x_offset_at() but incorrectly in
available_space_for_line(), causing IFC to break lines too early in
cases where the containing block had a non-zero X offset from the BFC
root block.
2022-03-19 12:42:10 +01:00
Andreas Kling
28b771560a LibWeb: Make SVG <svg> elements behave as CSS replaced elements
This makes SVG-in-HTML behave quite a bit better by following general
replaced layout rules. It also turns <svg> elements into inline-level
boxes instead of block-level boxes.
2022-03-19 12:42:10 +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
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
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
Lenny Maiorani
c37820b898 Libraries: Use default constructors/destructors in LibWeb
https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#cother-other-default-operation-rules

"The compiler is more likely to get the default semantics right and
you cannot implement these functions better than the compiler."
2022-03-17 17:23:49 +00:00
sin-ack
b801ddf73d LibWeb: Apply the current text-justify value when justifying
This implements at least some of the specification. inter-character is
not yet handled. However as our current algorithm only considers
whitespace as word breaks, inter-word could technically be considered to
be handled. :^)
2022-03-12 21:51:38 +01:00
sin-ack
7fe3f2d970 LibWeb: Refactor text justification code + only justify below threshold
All the justification-related code is now in
InlineFormattingContext::apply_justification_to_fragments and is
performed after all the line boxes have been added.

Text justification now only happens on the last line if the excess space
including whitespace is below a certain threshold. 10% seemed reasonable
since it prevents the "over-justification" of text. Note that fragments
in line boxes before the last one are always justified.
2022-03-12 21:51:38 +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
2dfb617c5b LibWeb: Make InlineLevelIterator emit absolutely positioned items
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.
2022-03-08 00:19:49 +01:00
Vrins
a8cfb34551 LibWeb: Allow <input type="button/submit/reset"> to be styled
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.
2022-02-28 15:46:06 +00:00
Andreas Kling
797f51e122 LibWeb: Add border box top/bottom metrics to line box fragments
This will allow us to support more kinds of vertical alignment.
2022-02-26 09:24:40 +01:00
Andreas Kling
c9f4759329 LibWeb: Use CSS font-size when computing text fragment content height 2022-02-26 01:10:43 +01:00
Andreas Kling
7ed6549c8b LibWeb: Fix off-by-one in calculation of available space for line boxes
The rightmost edge of the available space ends exactly at the leftmost
right-side floating box, not one pixel away from it.
2022-02-25 19:38:31 +01:00
Andreas Kling
bb1f26c149 LibWeb: Use correct coordinate space when measuring space between floats
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.
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
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
Sam Atkins
356d8bcfe8 LibWeb: Remove Length::Type::Undefined! :^) 2022-02-18 19:04:37 +01:00
Sam Atkins
b715943035 LibWeb: Remove redundant Length::resolved() calls
Now that calc() is also resolved in to_px(), code in the form
`foo.resolved(bar).to_px(bar)` can be simplified to `foo.to_px(bar)`.
2022-02-18 19:04:37 +01:00
Sam Atkins
67066c5140 LibWeb: Remove fallback value from Length::resolved()
Nobody makes undefined Lengths now, (although actually removing
Undefined will come in a later commit) so we can remove this parameter,
and `resolved_or_auto()`/`resolved_or_zero()`.
2022-02-18 19:04:37 +01:00
Sam Atkins
5b2482a939 LibWeb: Use Optional instead of undefined-lengths for widths/heights 2022-02-18 19:04:37 +01:00
Andreas Kling
dcc2568439 LibWeb: Make IFC register absolutely positioned descendants with BFC
This allows BFC to position all absolutely positioned descendants in the
same pass.
2022-02-15 02:05:53 +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
7d2a49eeb8 LibWeb: Always assign box model metrics in IFC::dimension_box_on_line()
Replaced elements have box model metrics, too. We shouldn't only assign
them to inline-block elements.
2022-02-14 18:00:21 +01:00
Andreas Kling
0532d7d255 LibWeb: Stop sizing the context root box in formatting contexts
Until now, some formatting contexts (BFC in particular) have been
assigning size to the root box. This is really the responsibility of the
parent formatting context, so let's stop doing it.

To keep position:absolute working, parent formatting contexts now notify
child contexts when the child's root box has been sized. (Note that the
important thing here is for the child root to have its final used height
before it's able to place bottom-relative boxes.)

This breaks flexbox layout in some ways, but we'll have to address those
by improving the spec compliance of FFC.)
2022-02-12 22:30:50 +01:00
Andreas Kling
0608de8c12 LibWeb: Rename Layout::Box::size() to content_size()
This property represents the CSS content size, so let's reduce ambiguity
by using the spec terminology.

We also bring a bunch of related functions along for the ride.
2022-02-06 01:07:47 +01:00
Sam Atkins
ce0de4b2b4 LibWeb: Allow LengthPercentage to hold a calculated value
Most of the time, we cannot resolve a `calc()` expression until we go to
use it. Since any `<length-percentage>` can legally be a `calc
()`, let's store it in `LengthPercentage` rather than make every single
user care about this distinction.
2022-02-04 13:52:02 +01:00
Andreas Kling
9201f626c1 LibWeb: Use BFC root relative coordinates when flowing around floats
While IFC flows text into a block container, floating objects are
anchored at the BFC root, not necessarily the local block container.

Because of this, we have to use root-relative coordinates when checking
how much space is available in between left and right floated objects.
2022-01-24 02:16:13 +01:00
Andreas Kling
00bd17034d LibWeb: Make IFC aware that its parent is always a BFC
This simplifies some code and allows us to use tighter types for the
parent context everywhere.
2022-01-24 02:09:17 +01:00
Andreas Kling
29589378ff LibWeb: Remove unused InlineFormattingContext::available_width_at_line() 2022-01-24 02:09:17 +01:00
Andreas Kling
0ea438e45b LibWeb: Put BFC floating object state into a struct
This patch adds a BFC::FloatSideData struct so we can contain left and
right floating object layout state in a struct. This is preparation for
adding more per-side state.
2022-01-23 01:22:41 +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
9f39ad8929 LibWeb: Ignore some collapsible whitespace when building lines
When collapsing whitespace, we can skip over all-whitespace chunks at
the start of each line, and immediately following fragments that
themselves end in whitespace.
2022-01-23 01:22:41 +01:00
Andreas Kling
2b631cde45 LibWeb: Avoid creating an empty first line box in block containers 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
ce8043c6c2 LibWeb: Use LineBuilder in IFC to layout line boxes incrementally
This resolves a long-standing architectural problem in LibWeb that made
it unable to place CSS floating objects correctly due to not having
final vertical position information when computing the amount of
available horizontal space for each line.
2022-01-23 01:22:41 +01:00
Andreas Kling
39b2046c42 LibWeb: Move available_space_for_line() into InlineFormattingContext 2022-01-23 01:22:41 +01:00
Andreas Kling
1f603c54ff LibWeb: Add inline-level iterator that enumerates items for line layout
This patch adds a new mechanism that allows InlineFormattingContext to
build line boxes incrementally instead of all-in-one go.

Incremental build will eventually allow much better support for CSS
floating objects.
2022-01-23 01:22:41 +01:00
Sam Atkins
bfcbab0dcf LibWeb: Remove reference_for_percent parameter from Length::resolved()
Despite looking like it was still needed, it was only used for passing
to other calls to Length::resolved() recursively. This makes the
various `foo.resolved().resolved()` calls a lot less awkward.
(Though, still quite awkward.)

I think we'd need to separate calculated lengths out to properly tidy
these calls up, but one yak at a time. :^)
2022-01-20 00:04:10 +01:00
Sam Atkins
dc681913e8 LibWeb: Convert width/height and min-/max- versions to LengthPercentage
A lot of this is quite ugly, but it should only be so until I remove
Length::Type::Percentage entirely. (Which should happen later in this
PR, otherwise, yell at me!) For now, a lot of things have to be
resolved twice, first from a LengthPercentage to a Length, and then
from a Length to a pixel one.
2022-01-20 00:04:10 +01:00
Sam Atkins
7196570f9b LibWeb: Cast unused smart-pointer return values to void 2021-12-05 15:31:03 +01:00
Andreas Kling
7ec7729e1b LibWeb: Don't force line box fragments height to be at least line-height
I don't remember why we did things this way, but it's clearly not right
to stretch fragments vertically. Instead, we should just align their
bottom to the appropriate line (as we already do.)
2021-10-28 18:01:04 +02:00
Andreas Kling
f2d0e8d0ee LibWeb: Expose FormattingContext type
Instead of having a virtual is_block_formatting_context(), let's have a
type() that can tell you exactly which type of formatting context it is.
2021-10-17 22:18:59 +02:00
Andreas Kling
f73aa8e2bd LibWeb: Move line boxes from Layout::Box to BlockContainer
Per the spec, only a BlockContainer" can have line boxes, so let's not
clutter up every Layout::Box with line boxes.

This also allows us to establish an invariant that BFC and IFC always
operate on a Layout::BlockContainer.

Note that if BlockContainer has all block-level children, its line boxes
are not used for anything. They are only used in the all inline-level
children scenario.
2021-10-06 21:53:25 +02:00
Andreas Kling
c4826eae4f LibWeb: Rename Layout::BlockBox => BlockContainer
There's a subtle difference here. A "block box" in the spec is a
block-level box, while a "block container" is a box whose children are
either all inline-level boxes in an IFC, or all block-level boxes
participating in a BFC.

Notably, an "inline-block" box is a "block container" but not a "block
box" since it is itself inline-level.
2021-10-06 20:10:36 +02:00
Tobias Christiansen
0ccde5417b LibWeb: Don't assume the parent is BFC in the IFC 2021-09-23 17:48:11 +02:00
Andreas Kling
ee3a73ddbb AK: Rename downcast<T> => verify_cast<T>
This makes it much clearer what this cast actually does: it will
VERIFY that the thing we're casting is a T (using is<T>()).
2021-06-24 19:57:01 +02:00
Matthew Olsson
88cfaf7bf0 LibGfx: Unify Rect, Point, and Size
This commit unifies methods and method/param names between the above
classes, as well as adds [[nodiscard]] and ALWAYS_INLINE where
appropriate. It also renamed the various move_by methods to
translate_by, as that more closely matches the transformation
terminology.
2021-05-02 22:48:06 +02:00
Brian Gianforcaro
1682f0b760 Everything: Move to SPDX license identifiers in all files.
SPDX License Identifiers are a more compact / standardized
way of representing file license information.

See: https://spdx.dev/resources/use/#identifiers

This was done with the `ambr` search and replace tool.

 ambr --no-parent-ignore --key-from-file --rep-from-file key.txt rep.txt *
2021-04-22 11:22:27 +02:00