Commit graph

67 commits

Author SHA1 Message Date
Aliaksandr Kalenik
b2abd1dd05 LibWeb: Resolve box shadow data for paintable boxes during layout
Step towards making the paintable tree independent of the layout tree.
2023-12-19 21:08:51 +01:00
Aliaksandr Kalenik
d1d6da6ab6 LibWeb: Resolve border radius during layout and save it in paintables
This change fixes a problem that we should not call `to_px()` to
resolve any length or percentage values during paintables traversal
because that is supposed to happen while performing layout.

Also it improves performance because before we were resolving border
radii during each painting phase but now it happens only once during
layout.
2023-12-07 10:52:47 +01:00
MacDue
4c5d48f861 LibWeb: Support transforms, stroking, gradients, etc for SVG <text>
This makes use of the new Gfx::Path::text() to handle SVG text elements,
with this text is just a regular path, and can be manipulated like any
other graphics element.

This removes the SVGTextPaintable and makes both <text> and geometry
elements use a new (shared) SVGPathPaintable. This is identical to the
old SVGGeometryPaintable. This simplifies painting as once something is
resolved to a Gfx::Path, the painting logic is the same.
2023-11-05 02:46:46 +01:00
MacDue
c93d367d95 LibWeb: Layout SVG <text> elements during layout (not while painting)
Previously, all SVG <text> elements were zero-sized boxes, that were
only actually positioned and sized during painting. This led to a number
of problems, the most visible of which being that text could not be
scaled based on the viewBox.

Which this patch, <text> elements get a correctly sized layout box,
that can be hit-tested and respects the SVG viewBox.

To share code with SVGGeometryElement's the PathData (from the prior
commit) has been split into a computed path and computed transforms.
The computed path is specific to geometry elements, but the computed
transforms are shared between all SVG graphics elements.
2023-10-30 19:44:54 +01:00
MacDue
dc9cb449b1 LibWeb: Store computed SVG path data/transforms in LayoutState
This removes the awkward hack to recompute the layout transform at paint
time, and makes it possible for path sizes to be computed during layout.

For example, it's possible to use relative units in SVG shapes (e.g.
<rect>), which can be resolved during layout, but would be hard to
resolve again during painting.
2023-10-30 19:44:54 +01:00
Tobias Christiansen
6602b1ddb1 LibWeb: Rename "position" enum to "positioning"
The postitioning enum values are used by the position CSS property.
Unfortunately, the prior naming clashes with the CSS Values-4 type
named position, which will be implemented in a later commit.
2023-10-30 10:40:30 +00:00
MacDue
0af8d81f48 LibWeb: Layout SVG <mask> elements (but don't paint them)
This allows SVG mask elements to have layout computed, but not connected
to the main paint tree. They should only be reachable if (and painted)
if referenced by the "mask" attribute of another element.

This is controlled by the forms_unconnected_subtree() function on the
paintable, which (if it returns true) prevents the paintable from being
added as a child to what would be its parent.
2023-09-19 10:46:05 +02:00
MacDue
c5b50ec2f4 LibWeb: Create paintables for nodes whose parents don't have paintables
A Paintable is not created for an SVG <defs> element (nor should it),
but it can contain SVG <mask> elements that need a paintable.

This change forces those paintables to be created (without a parent).
The masks are then only painted by being referenced from another
element.
2023-09-19 10:46:05 +02:00
Andreas Kling
1434721247 LibWeb: Relax restrictions on LayoutState::get() input type
Instead of only letting NodeWithStyleAndBoxModelMetrics (and subclasses)
have used values in the layout state, we now allow any NodeWithStyle.
2023-09-04 18:22:59 +02:00
Aliaksandr Kalenik
0fb571c1c2 LibWeb: Add Length::resolved() overload for CSSPixels
Since we always pass the px value as an argument to resolved(), we can
pass it directly as CSSPixels instead of wrapping it in Length. This
approach allows us to avoid converting to a double, resulting in fewer
precision issues.
2023-08-30 20:09:15 +02:00
Andreas Kling
6d7a2f5cc9 LibWeb: Prune old paintable pointers from layout tree after relayout
When text paintables shift around in the tree due to line wrapping,
we may end up in a situation where some text node does not generate
a paintable (due to being all whitespace, for example), even though
in the previous layout pass, it *did* generate a paintable.

To prevent holding on to old paintables in such cases, we now do a
pass in LayoutState::commit() where we explicitly detach all old
paintables from the layout tree.
2023-08-29 17:05:16 +02:00
Andreas Kling
ae3958f640 LibWeb: Remove incorrect hack in build_paint_tree()
If a paintable already has a parent when we're building a paint tree,
that's a bug we should catch, not something that needs a workaround.
2023-08-28 23:36:22 +02:00
MacDue
360c0eb509 LibWeb: Remove implicit conversion from float and double to CSSPixels
In general it is not safe to convert any arbitrary floating-point value
to CSSPixels. CSSPixels has a resolution of 0.015625, which for small
values (e.g. scale factors between 0 and 1), can produce bad results
if converted to CSSPixels then scaled back up. In the worst case values
can underflow to zero and produce incorrect results.
2023-08-26 23:53:45 +02:00
Andreas Kling
3d7c880a42 LibWeb: Give DOM::Node a direct pointer to its Paintable
Instead of going via the layout tree.
2023-08-20 05:02:59 +02:00
Andreas Kling
136ac1a6a5 LibWeb: Add virtuals to check if Paintable is PBox or PWithLines
Instead of inferring the type of paintables by looking at the type of
their origin in the layout tree, let's ask them directly.
2023-08-20 05:02:59 +02:00
Andreas Kling
e67ac16862 LibWeb: Give Paintable its own pointer to the corresponding DOM node
Instead of going through the layout node's DOM pointer.
2023-08-20 05:02:59 +02:00
Andreas Kling
216bd513fa LibWeb: Make the paint tree a proper standalone tree
Until now, paint trees have been piggybacking on the layout tree for
traversal, and paintables didn't actually have their own parent/child
pointers.

This patch changes that by making Paintable inherit from TreeNode, and
adding a new pass to LayoutState::commit() where we recursively build
the new paint tree.
2023-08-20 05:02:59 +02:00
Andreas Kling
25a3d0d643 LibWeb: Resolve relative offsets *once* after layout
Instead of applying relative offsets (like position:relative insets)
during painting and hit testing, we now do a pass at the end of layout
and assign the final resolved offsets to paintables.

This makes painting and hit testing easier since they don't have to
think about relative offsets, and it also fixes a bug where offsets were
not applied to text fragments inside inline-flow elements that were
themselves position:relative.
2023-08-15 16:37:11 +02:00
Aliaksandr Kalenik
9101c8d079 LibWeb: Use available space to resolve table container width
Using avilable space directly while resolving table container width
allows to avoid assigning it to table wrapper box content width which
sometimes involves infinite (saturated) values.

Also this allows to get rid of set_max_content_width() which is a hack
that allows to bypass set_content_width() to assign infinite
(saturated) width to a box.

Closes https://github.com/SerenityOS/serenity/issues/19521
2023-08-11 19:36:19 +02:00
Sam Atkins
5ee1b7db7c LibWeb: Convert BorderData::width to CSSPixels
The `clip_shrink` optimization in `paint_background()` now also
correctly uses DevicePixels, instead of reducing a DevicePixel rect by
a CSSPixels amount.
2023-07-30 22:18:26 +01:00
Aliaksandr Kalenik
e5dcfe3905 LibWeb: Verify that value is not saturated in set_content_width/height
Checking if CSSPixels contains a finite value is no longer makes sense
after converting to fixed-point arithmetics. Instead there should
assertion that used value is not saturated.
2023-07-29 17:23:27 +02:00
Andreas Kling
bf25568703 LibWeb: Bring measuring of scrollable overflow closer to spec
Importantly, we now only consider overflow from descendants with
explicltly visible overflow, and only from descendants that have the
measured box as their containing block.

Also, we now measure scrollable overflow for all boxes, not just scroll
containers. This will allow us to fix a long-standing paint problem in
the next commit.
2023-07-13 05:09:08 +02:00
Andreas Kling
f23baf0a2d LibWeb: Add LineBox::absolute_rect()
Let's just calculate this once, at the end of a layout, and then never
have to worry about it again during painting.
2023-07-13 05:09:08 +02:00
Andi Gallo
f6d2a21d27 LibWeb: Store table cell indices and spans in PaintableBox
The adjacency information is required to position borders correctly
between columns and rows.
2023-07-06 10:31:51 +02:00
Andi Gallo
b7d23162cc LibWeb: Set the definite width flag in set_max_content_width
It was setting the definite flag for height.
2023-07-06 08:54:28 +02:00
Aliaksandr Kalenik
473848be0e LibWeb: Do not treat size of abspos items as definite
This fixes the issue when size of abspos items is considered to be
resolvable without performing layout which is not correct in the
scenarious when top/right/bottom/left properties are not auto.
2023-06-22 18:18:04 +02:00
Aliaksandr Kalenik
147c3b3d97 LibWeb+WebContent: Forbid access to underlying type of CSSPixels
Although DistinctNumeric, which is supposed to abstract the underlying
type, was used to represent CSSPixels, we have a whole bunch of places
in the layout code that assume CSSPixels::value() returns a
floating-point type. This assumption makes it difficult to replace the
underlying type in CSSPixels with a non-floating type.

To make it easier to transition CSSPixels to fixed-point math, one step
we can take is to prevent access to the underlying type using value()
and instead use explicit conversions with the to_float(), to_double(),
and to_int() methods.
2023-06-13 06:08:27 +02:00
Andi Gallo
75e87c32f2 LibWeb: Fix table width algorithm when available space is a constraint
Handle available space more carefully when computing a table width, in
order to avoid creating a definite infinite width when available space
width is max-content, as it's the case in calculate_max_content_width.
The constraint is thus correctly propagated by the time we cache the
computed value, which was previously rejected by the hash function due
to being definite but infinite instead of max-content.
2023-06-12 17:51:00 +02:00
Andi Gallo
8090adf268 LibWeb: Add partial implementation of border conflict resolution
Fix handling of border style specified per column as well.
2023-06-10 11:17:21 +02:00
Andreas Kling
caa491b72a LibWeb: Measure the overflow for all scroll containers
Instead of just measuring the layout viewport, we now measure overflow
in every box that is a scroll container.

This has the side effect of no longer creating paintables for layout
boxes that didn't participate in layout. (For example, empty/anonymous
boxes that were ignored by flex itemization.)

Such boxes are now marked as "(not painted)" in the layout tree dumps,
as they have no paintable to dump geometry from.
2023-06-01 13:33:35 +02:00
Andreas Kling
c62c714764 LibWeb: Put debug spam about negative content sizes behind a flag
We already clamp these values to zero, so it's actually pretty harmless
when this happens. If someone wants to investigate these issues deeper
and see if they can be fixed earlier in the layout pipeline, they can
enable the spam locally.
2023-06-01 07:34:37 +02:00
Andreas Kling
42470d837e LibWeb: Move layout box rect helpers into FormattingContext
These are only used during layout, and always within formatting context
code, so we might as well put them in FormattingContext and avoid having
to pass the LayoutState around all the time.
2023-05-31 11:38:05 +02:00
Andreas Kling
655d9d1462 LibWeb: Make CSSPixels and Length use 64-bit (double) floating point
This fixes a plethora of rounding problems on many websites.
In the future, we may want to replace this with fixed-point arithmetic
(bug #18566) for performance (and consistency with other engines),
but in the meantime this makes the web look a bit better. :^)

There's a lot more things that could be converted to doubles, which
would reduce the amount of casting necessary in this patch.
We can do that incrementally, however.
2023-05-24 14:40:35 +02:00
Jelle Raaijmakers
c03152c5d2 LibWeb: Simplify margin & border box construction in LayoutState 2023-05-23 12:35:42 +02:00
Andreas Kling
e2c72922f6 LibWeb: Make LayoutState use HashMap instead of potentially huge Vector
Before this change, LayoutState essentially had a Vector<UsedValues*>
resized to the exact number of layout nodes in the current document.

When a nested layout is performed (to calculate the intrinsic size of
something), we make a new LayoutState with its own Vector. If an entry
is missing in a nested LayoutState, we check the parent chain all the
way up to the root.

Because each nested LayoutState had to allocate a new Vector with space
for all layout nodes, this could get really nasty on very large pages
(such as the ECMA262 specification).

This patch replaces the Vector with a HashMap. There's now a small cost
to lookups, but what we get in return is the ability to handle huge
layout trees without spending eternity in page faults.
2023-05-23 09:24:08 +02:00
Andreas Kling
c9223528a0 LibWeb: Get rid of weird Length::resolved() usage in LayoutState
The second call to resolved() turns non-finite lengths into "auto".
This is a very strange ad-hoc behavior that we need to get rid of.
2023-05-06 21:14:38 +02:00
Andreas Kling
00e3e82bbd LibWeb: Account for box-sizing:border-box in layout-less definite sizes
When we determine that a size is definite because it can be resolved now
without performing layout, we also need to account for the box-sizing
property.

This lets us remove a hack from flex layout where box-sizing:border-box
was manually undone at one point in the layout algorithm.
2023-05-02 11:47:13 +02:00
Andreas Kling
deea7cbc11 LibWeb: Remove vestigial resolve_definite_width/height helper functions
These functions no longer do anything interesting and just forward to
content_width/content_height. Let's make the callers use those directly
instead and remove this indirection layer.
2023-05-02 11:47:13 +02:00
Linus Groh
a75915f055 LibWeb/Layout: Rename BlockContainer::paint{_box => able_with_lines}()
It returns a PaintableBox (a PaintableWithLines, to be specific), not a
'PaintBox'. paintable_box() without the cast is already available
through BlockContainer's Box base class, we don't need to shadow it.
2023-04-20 20:43:30 +02:00
Linus Groh
754e458d0a LibWeb/Layout: Rename Box::{paint => paintable}_box()
It returns a PaintableBox, not a 'PaintBox'.
2023-04-20 20:43:30 +02:00
Sam Atkins
53a4a31af2 LibWeb: Remove CalculatedStyleValue from Length 2023-03-30 21:29:50 +02:00
Andreas Kling
ca290b27ea LibWeb: Make box content sizes indefinite before intrinsic sizing
When calculating the intrinsic width of a box, we now make its content
width & height indefinite before entering the intrinsic sizing layout.
This ensures that any geometry assigned to the box by its parent
formatting context is ignored.

For intrinsic heights, we only make the content height indefinite.
This is because used content width is a valid (but optional) input
to intrinsic height calculation.
2023-03-27 23:28:07 +02:00
Cameron Youell
f17bee0cb5 LibWeb: Fix mistype in LayoutState 2023-03-26 13:28:07 +02:00
Andreas Kling
b3b9ac6201 LibWeb: Add FIXME whining to debug log if layout produces negative sizes
Negative width/height sizes are not allowed in CSS, so if our layout
algorithm resolves something to a negative size, we have boogs.

Instead of crashing or rendering something very wrong, we now clamp the
values to 0 and whine on the debug log so that someone can go and figure
out how we got the negative values in the first place. :^)
2023-03-25 19:41:31 +01:00
Mathis Wiehl
b96920a9d6 LibWeb: Consider margins of atomic inlines in layout
According to CSS Inline Layout Module Level 3 § 2.2 Step 1. atomic
inlines should be layed out in a line box based on their margin box.

However, up until this patch we were unconditionally considering only
the border box during line box height calculation. This made us
essentially drop all vertical margins for atomic inlines.
2023-03-14 14:45:40 +01:00
Andreas Kling
7e76a51cb0 LibWeb: Rename Layout::InitialContainingBlock to Layout::Viewport
The name "initial containing block" was wrong for this, as it doesn't
correspond to the HTML element, and that's specifically what it's
supposed to do! :^)
2023-02-28 12:21:56 +01:00
Sam Atkins
c70dcaefcd LibWeb: Convert LayoutState to new pixel units 2023-01-05 17:42:31 +01:00
Sam Atkins
76047d1932 LibWeb: Convert InlineLevelIterator/LineBox/LineBuilder to new px units 2023-01-05 17:42:31 +01:00
martinfalisse
20313ae8a8 LibWeb: Use TextTop and TextBottom property for VerticalAlign
If text-top or text-bottom are given as values for the vertical-align
property, actually use them and calculate the respective position of
the element.

The actual calculations done (using the font_size, descent, etc.) are
not exactly how I imagined them when reading the spec, but the results
seem acceptable when compared to other browsers.
2023-01-01 18:38:01 +01:00
Sam Atkins
ab49dbf137 LibWeb: Convert Paintable coordinates to new pixel units
This fixes a few sizing issues too. The page size is now correct in most
cases! \o/

We get to remove some of the `to_type<>()` shenanigans, though it
reappears in some other places.
2022-12-14 16:47:57 +00:00