Commit graph

634 commits

Author SHA1 Message Date
Sam Atkins
bfd7ac1204 LibWeb+WebContent+UI: Support image cursors
The `cursor` property accepts a list of possible cursors, which behave
as a fallback: We use whichever cursor is the first available one. This
is a little complicated because initially, any remote images have not
loaded, so we need to use the fallback standard cursor, and then switch
to another when it loads.

So, ComputedValues stores a Vector of cursors, and then in EventHandler
we scan down that list until we find a cursor that's ready for use.

The spec defines cursors as being `<url>`, but allows for `<image>`
instead. That includes functions like `linear-gradient()`.

This commit implements image cursors in the Qt UI, but not AppKit.
2025-02-28 13:50:13 +01:00
Sam Atkins
d127d412c8 LibWeb/CSS: Implement CursorStyleValue
A cursor is an image, with an optional x,y hotspot.

We know that a CursorStyleValue's bitmap never needs to change size, so
we create the ShareableBitmap once and then cache it, so that we don't
have to repeatedly create an FD for it or do the work of painting.

To avoid repainting that bitmap, we cache the values that were used to
create it - what currentColor is and its length resolution context -
and only repaint when those change.
2025-02-28 13:50:13 +01:00
Sam Atkins
9cbd8a82c7 LibWeb: Only require NodeWithStyle for gradient size resolution
None of the code here actually needs a NodeWithStyleAndBoxModelMetrics,
and we'll need to be able to resolve images from inside
NodeWithStyle::apply_style().
2025-02-28 13:50:13 +01:00
Sam Atkins
a0cd6dd607 LibWeb/CSS: Support CalculatedOr::to_string() for integers and floats
IntegerOrCalculated and NumberOrCalculated's T types don't have a
to_string() method because they're i64 and double respectively, so use
String::number() for them instead.

Also rearrange this method to avoid checking the variant's contents
multiple times.
2025-02-28 13:50:13 +01:00
Sam Atkins
c77456a508 LibWeb/CSS: Clarify types of image-parsing methods
parse_image_value() always returns some kind of AbstractImageStyleValue.
2025-02-28 13:50:13 +01:00
Sam Atkins
09d2c5eb9b LibWeb/CSS: Remove unused includes from CSSStyleValue.h
A couple of these were needed transitively, so I've added them to the
relevant files.
2025-02-28 13:50:13 +01:00
Sam Atkins
6a4a60cbd5 LibWeb/CSS: Invalidate color-stop caches when source data changes
We previously only invalidated the cached color-stop data when the
painted area's size changed. However, multiple elements can use the
same gradient and be the same size, but have different parameters that
affect the gradient stop positions, for example if a stop has an em
position. This can also change for the same element over time.

The new cache instead uses these parameters as the cache key. So we
recompute the cache if lengths would resolve differently, or the area's
size is different.

The included test fails without this change.
2025-02-28 13:50:13 +01:00
Sam Atkins
5651701f31 LibWeb/CSS: Remove now-redundant CalculationNode::to_string()
The main users were the `dump()` functions, which now dump their
children instead, which is more correct anyway.

The others are for serializing numeric values, so
NumericCalculationNode's to_string() is renamed to value_to_string
() and used for those for convenience.
2025-02-27 21:42:43 +01:00
Sam Atkins
5cfb8163c6 LibWeb/CSS: Sort a calculation's children during serialization
This gets us 38 more passes in our in-tree tests, plus however many more
in the rest of WPT. :^)
2025-02-27 21:42:43 +01:00
Sam Atkins
a63879330f LibWeb/CSS: Implement calc-serialization spec algorithms
This gets us 37 new subtest passes in css/css-values, and 13 passes in
our other in-tree tests (and probably some random other ones!)

As noted in comments, a few parts of this algorithm have ad-hoc
behaviour to handle some issues in the spec.
2025-02-27 21:42:43 +01:00
Sam Atkins
f97ac33cb3 LibWeb/CSS: Use NumericCalculationNode for constants
Having multiple kinds of node that hold numeric values made things more
complicated than they needed to be, and we were already converting
ConstantCalculationNodes to NumericCalculationNodes in the first
simplification pass that happens at parse-time, so they didn't exist
after that.

As noted, the spec allows for other contexts to introduce their own
numeric keywords, which might be resolved later than parse-time. We'll
need a different mechanism to support those, but
ConstantCalculationNode could not have done so anyway.
2025-02-27 21:42:43 +01:00
Sam Atkins
718e874cc7 LibWeb/CSS: Allow whitespace inside fit-content() function 2025-02-27 13:30:36 +00:00
zoupingshi
b609d8481a LibURL+LibWeb+Tests: Remove redundant words 2025-02-27 10:35:39 +00:00
Andreas Kling
8ab61843be LibWeb: Parse CSS fit-content(<length-percentage>) values
Before this change, we only parsed fit-content as a standalone keyword,
but CSS-SIZING-3 added it as a function as well. I don't know of
anything else in CSS that is overloaded like this, so it ends up looking
a little awkward in the implementation.

Note that a lot of code had already been prepped for fit-content values
to have an argument, we just weren't parsing it.
2025-02-27 00:44:14 +01:00
Sam Atkins
05dc8f07b2 LibWeb/CSS: Remove string type from transition-property
This isn't in the spec.
2025-02-26 11:22:47 +00:00
Sam Atkins
ab4b46f990 LibWeb/CSS: Automate parsing view-transition-name 2025-02-26 11:22:47 +00:00
Sam Atkins
c729c3fcee LibWeb/CSS: Add custom-ident blacklists to Properties.json
These excluded values use a similar notation to the ranges for numeric
types: `![foo,bar,baz]` to exclude `foo`, `bar`, and `baz`.
2025-02-26 11:22:47 +00:00
Sam Atkins
c6c607884b LibWeb/CSS: Take custom-ident blacklist as a Span
Using std::initializer_list here was a bit of a hack, and makes it
awkward to pass those blacklists around.
2025-02-26 11:22:47 +00:00
Andreas Kling
b4e47f198a LibWeb: Implement time-traveling inheritance for CSS font-size
Some checks are pending
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
When setting `font-family: monospace;` in CSS, we have to interpret
the keyword font sizes (small, medium, large, etc) as slightly smaller
for historical reasons. Normally the medium font size is 16px, but
for monospace it's 13px.

The way this needs to behave is extremely strange:
When encountering `font-family: monospace`, we have to go back and
replay the CSS cascade as if the medium font size had been 13px all
along. Otherwise relative values like 2em/200%/etc could have gotten
lost in the inheritance chain.

We implement this in a fairly naive way by explicitly checking for
`font-family: monospace` (note: it has to be *exactly* like that,
it can't be `font-family: monospace, Courier` or similar.)
When encountered, we simply walk the element ancestors and re-run the
cascade for the font-size property. This is clumsy and inefficient,
but it does work for the common cases.

Other browsers do more elaborate things that we should eventually care
about as well, such as user-configurable font settings, per-language
behavior, etc. For now, this is just something that allows us to handle
more WPT tests where things fall apart due to unexpected font sizes.

To learn more about the wonders of font-size, see this blog post:
https://manishearth.github.io/blog/2017/08/10/font-size-an-unexpectedly-complex-css-property/
2025-02-25 23:55:36 +01:00
Andreas Kling
263e58bbe9 LibWeb: Only calculate parent size once in compute_font_for_style_values 2025-02-25 23:55:36 +01:00
InvalidUsernameException
f7276bfab3 LibWeb: Reduced number of recompiled files for CSS property headers
Some checks are pending
CI / Lagom (x86_64, Sanitizer_CI, false, ubuntu-24.04, Linux, GNU) (push) Waiting to run
CI / Lagom (arm64, Sanitizer_CI, false, macos-15, macOS, Clang) (push) Waiting to run
CI / Lagom (x86_64, Fuzzers_CI, false, ubuntu-24.04, Linux, Clang) (push) Waiting to run
CI / Lagom (x86_64, Sanitizer_CI, true, ubuntu-24.04, Linux, Clang) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (macos-14, macOS, macOS-universal2) (push) Waiting to run
Package the js repl as a binary artifact / build-and-package (ubuntu-24.04, Linux, Linux-x86_64) (push) Waiting to run
Run test262 and test-wasm / run_and_update_results (push) Waiting to run
Lint Code / lint (push) Waiting to run
Label PRs with merge conflicts / auto-labeler (push) Waiting to run
Push notes / build (push) Waiting to run
This reduces the number of `.cpp` files that need to be recompiled when
one of the below header files changes as follows:

CSS/ComputedProperties.h: 1113 -> 49
CSS/ComputedValues.h: 1120 -> 209
2025-02-23 10:14:39 -05:00
InvalidUsernameException
be47f95180 LibWeb: Reduce number of recompiled files for display list headers
This reduces the number of `.cpp` files that need to be recompiled when
one of the below header files changes as follows:

Painting/Command.h: 1030 -> 61
Painting/DisplayList.h: 1030 -> 60
Painting/DisplayListRecorder.h: 557 -> 59
2025-02-23 10:14:39 -05:00
Andreas Kling
a706d0ebf4 LibWeb: Let getComputedStyle() show *used* values for margin/padding
We were incorrectly showing *computed* instead of *used* values for
margin and padding when inspected via getComputedStyle().
2025-02-22 20:02:16 +01:00
Psychpsyo
c0eb072645 LibWeb: Add CSS view-transition-name 2025-02-22 14:52:13 +00:00
Psychpsyo
b833168b74 LibWeb: Add view transition UA styles 2025-02-22 14:52:13 +00:00
Aliaksandr Kalenik
0ab61a94d7 LibWeb: Bucket hover rules using RuleCache
Analysis of selectors on modern websites shows that the `:hover`
pseudo-class is mostly used in the subject position within relatively
simple selectors like `.a:hover`. This suggests that we could greatly
benefit from segregating them by id/class/tag name, this way reducing
number of selectors tested during hover style invalidation.

With this change, hover invalidation on Discord goes down from 70ms to
3ms on my machine. I also tested GMail and GitHub where this change
shows nice 2x-3x speedup.
2025-02-22 10:12:24 +01:00
Aliaksandr Kalenik
ff8826d582 LibWeb: Prepare RuleCache for being reusable to store hover rules
Moves code that allows to add and iterate over rules in cache into
methods defined for RuleCache.
2025-02-22 10:12:24 +01:00
Aliaksandr Kalenik
1843a54df7 LibWeb: Skip quick selector rejection using ancestor filter if possible
If selector does not have any descendant combinators then we know for
sure it won't be filtered out by ancestor filter, which means there is
no need to check for it.

This change makes hover style invalidation go faster on Discord where
with this change we spend 4-5% in `should_reject_with_ancestor_filter()`
instead of 20%.
2025-02-20 19:48:27 +01:00
Aliaksandr Kalenik
0f3665e64e LibWeb: Mark should_reject_with_ancestor_filter() as inline 2025-02-19 21:52:29 +01:00
Shannon Booth
d62cf0a807 Everywhere: Remove some use of the URL constructors
These make it too easy to construct an invalid URL, which makes it
difficult to remove the valid state of URL - which this API relies
on.
2025-02-19 08:01:35 -05:00
Andrew Kaster
8760825bb4 LibWeb: Don't store Page on ResourceLoader
We only need a Page for file:// urls. At some point we probably
needed it for other kinds of requests, but the current functionality
doesn't need to store the Page pointer on the ResourceLoader.
2025-02-18 11:26:34 -07:00
Gingeh
4966fa4aed LibWeb: Prevent crash with custom cursor
We don't support custom cursors, use the default instead of crashing.
Also clean up a bit of dead code from when Cursor was optional.
2025-02-17 12:24:49 +00:00
InvalidUsernameException
29d74632c7 LibWeb: Move z-index to table wrapper box
When drawing a table, some of the CSS properties must be moved from the
table grid box to an anonamyous table wrapper box. One of these
properties is `position`. `z-index` however is not. This leads to the
following behavior if a table has both `position` and `z-index`:
* The wrapper box has the `position`, but a `z-index` of `auto`.
* The grid box has the `z-index`, but `position: static`.

This effectively means that the `z-index property is ignored since it
has no effect on non-positioned elements. This behavior contradicts what
other browsers do and causes layout issues on websites.

To align Ladybird behavior with other browser this commit also moves the
`z-index` property to the wrapper box.
2025-02-16 21:05:59 +01:00
Luke Wilde
751b93959f LibWeb/CSS: Use fallback var() value if custom property is empty
If the expansion of a custom property in variable expansion returns
tokens, then the custom property is not the initial guaranteed-invalid
value.

If it didn't return any tokens, then it is the initial
guaranteed-invalid value, and thus we should move on to the fallback
value.

Makes Shopify checkout show the background colours, borders, skeletons,
etc.
2025-02-16 09:19:19 +01:00
Shannon Booth
53826995f6 LibURL+LibWeb: Port URL::complete_url to Optional
Removing one more source of the URL::is_valid API.
2025-02-15 17:05:55 +00:00
Andreas Kling
c9cd795257 LibWeb: Don't lose change events on MediaQueryList internal state change
MediaQueryList will now remember if a state change occurred when
evaluating its match state. This memory can then be used by the document
later on when it's updating all queries, to ensure that we don't forget
to fire at least one change event.

This also required plumbing the system visibility state to initial
about:blank documents, since otherwise they would be stuck in "hidden"
state indefinitely and never evaluate their media queries.
2025-02-13 20:52:31 +01:00
Andreas Kling
6fd24c2a68 LibWeb: Update layout when checking media queries inside iframes
This ensures that the containing iframe has up-to-date viewport metrics,
which is important since that may affect media query results.
2025-02-13 20:52:31 +01:00
Aliaksandr Kalenik
327dc8e82a LibWeb: Avoid full tree traversal for non-subject :has() invalidation
Instead of checking all elements in a document for containment in
`:has()` invalidation set, we could narrow this down to ancestors and
ancestor siblings, like we already do for subject `:has()` invalidation.

This change brings great improvement on GitHub that has selectors with
non-subject `:has()` and sibling combinators (e.g., `.a:has(.b) ~ .c`)
which prior to this change meant style invalidation for whole document.
2025-02-13 16:24:51 +01:00
Sam Atkins
75faea3221 LibWeb/CSS: Don't serialize font shorthand with invalid longhand values
Some values that are valid in font's longhands individually are not
allowed inside the font shorthand.
2025-02-12 16:00:42 +00:00
Sam Atkins
80eee82ea9 LibWeb/CSS: Inline CSSStyleValue::to_font_variant_foo() methods
Now that these are only called from ComputedProperties getters, we can
put the code there directly.
2025-02-12 16:00:42 +00:00
Sam Atkins
62c18d1dec LibWeb/CSS: Serialize font-variant property closer to spec
It also needs special handling when reading it from CSSStyleDeclaration.
2025-02-12 16:00:42 +00:00
Sam Atkins
8236022152 LibWeb/CSS: Parse font-variant properties closer to spec
The spec wants these keywords to appear in a particular order when
serialized, so let's just put them in that order during parsing.

This also fixes a bug where we didn't reject `font-variant-east-asian`
that contains `normal` alongside another value.

Also, rather than always parsing them as a StyleValueList, parse single
values on their own, and then support that in the to_font_variant_foo()
methods.
2025-02-12 16:00:42 +00:00
Sam Atkins
cda3fe7a4b LibWeb/CSS: Reject trailing unparseable tokens in property values
Without this, we'd happily parse `font-variant-caps: small-caps potato`
as just `small-caps` and ignore the fact that unused tokens were left
over.

This fix gets us some WPT subtest passes, and removes the need for a
bespoke parsing function for font-variant-caps.
2025-02-12 16:00:42 +00:00
Sam Atkins
412b758107 LibWeb/CSS: Support nested shorthands in CSSStyleDeclaration
Without this, getting a property's value from `element.style.foo` would
fail if `foo` is a shorthand property which has a longhand that is also
a shorthand. For example, `border` expands to `border-width` which
expands to `border-top-width`.

This is because we used `property()` to get a longhand's value, but this
returns nothing if the property is a shorthand.

This commit solves that by moving most of get_property_value() into a
separate method that returns a StyleProperty instead of a String, and
which calls itself recursively for shorthands. Also move the manual
shorthand construction out of ResolvedCSSStyleDeclaration so that all
CSSStyleDeclarations can use it.
2025-02-12 16:00:42 +00:00
Sam Atkins
006c8ba2d4 LibWeb/CSS: Serialize font property more correctly
Anything that's default shouldn't be included.
2025-02-12 16:00:42 +00:00
Sam Atkins
531b92d467 LibWeb/CSS: Make font implicitly reset some properties
This is a weird behaviour specific to `font` - it can reset some
properties that it never actually sets. As such, it didn't seem worth
adding this concept to the code generator, but just manually stuffing
the ShorthandStyleValue with them during parsing.
2025-02-12 16:00:42 +00:00
Sam Atkins
0fd0596dbf LibWeb: Support strings as list-style-types
We've long claimed to support this, but then silently ignored string
values, until 4cb2063577 which would
not-so-silently crash instead. (Oops)

So, actually pass the string value along and use it in the list marker.

As part of this, rename our `list-style-type` enum to
`counter-style-name-keyword`. This is an awkward name, attempting to be
spec-based. (The spec says `<counter-style>`, which is either a
`<counter-style-name>` or a function, and the `<counter-style-name>` is
a `<custom-ident>` that also has a few predefined values. So this is the
best I could come up with.)

Unfortunately only one WPT test for this passes - the others fail
because we produce a different layout when text is in `::before` than
when it's in `::marker`, and similar issues.
2025-02-11 10:39:27 +01:00
Sam Atkins
b987d53926 LibWeb: Migrate ListItemMarkerBox's text from ByteString to String 2025-02-11 10:39:27 +01:00
Aliaksandr Kalenik
875a7141a3 LibWeb: Skip pending :has() invalidations if there are no :has()
`invalidate_style()` already tries to avoid scheduling invalidation for
`:has()` by checking result of `may_have_has_selectors()`, but it might
still result in unnecessary work because `may_have_has_selectors()`
does not force building of rules cache. This change adds
`have_has_selectors()` that forces building of rules cache and is
invoked in `update_style()` to double-check whether we actually need to
process scheduled `:has()` invalidations.

This allows to skip ~100000 ancestor traversals on this WPT test:
https://wpt.live/html/select/options-length-too-large.html
2025-02-11 10:22:23 +01:00
Sam Atkins
dc58f6567f LibWeb: Support :open for file and color <input> elements 2025-02-10 13:57:36 +00:00