Commit Graph

113 Commits

Author SHA1 Message Date
Sam Atkins
d327f677c5 LibWeb/CSS: Store linear-gradient() angle as a StyleValue
This means we now support calc() there too.
2025-12-01 11:01:06 +00:00
Sam Atkins
73fbaaba77 LibWeb: Store GradientStyleValue color-stop positions as StyleValues
A few things fall out of this:
- We no longer need to templatize our color-stop list types.
- A bit more code is required to resolve gradient data.

This results in a slightly different rendering for a couple of the test
gradients, with a larger difference between macOS and Linux. I've
expanded the fuzziness factor to cover for it.
2025-12-01 11:01:06 +00:00
Psychpsyo
2db3796fd3 LibWeb: Implement CSS perspective-origin 2025-11-21 11:14:28 +00:00
Aliaksandr Kalenik
597fe8288c LibWeb: Apply own clip rect for background phase only when clip used
Fixes a bug where we would clip `box-shadow` when `overflow: hidden`
was set, which is not supposed to happen since `overflow` only affects
clipping of an element's content.
2025-11-19 18:17:42 +01:00
Jelle Raaijmakers
2811c75031 LibWeb: Use anti-aliasing to draw images and painting surfaces
Fixes the jagged edges on the transformed badge on
https://aaronfrancis.com/backstage.
2025-11-12 17:43:02 +01:00
Jelle Raaijmakers
489dea58ba LibWeb: Make all clip rects anti-aliased
This fixes aliased edges when e.g. applying rotation transforms to
certain shapes or SVGs. Although the clip rects themselves are
rectangular, a non-identity matrix transform can be active for the
canvas.

Fixes #5909.
2025-11-12 17:43:02 +01:00
Jelle Raaijmakers
3f6cbeb87e LibGfx+LibWeb: Use mipmaps for downscaling images
This changes Gfx::ScalingMode to reflect the three modes of scaling we
support using Skia, which makes it a bit easier to reason about the mode
to select. New is ::BilinearMipmap, which uses linear interpolation
between mipmap levels to produce higher quality downscaled images.

The cubic resampling options Mitchell and its sibling CatmullRom both
produced weird artifacts or resulted in a worse quality than
BilinearMipmap when downscaling. We might not have been using these
correctly, but the new ::BilinearMipmap method seems to mirror what
Chrome uses for downscaled images.
2025-11-12 15:59:01 +01:00
Jelle Raaijmakers
b4810f47a3 LibWeb: Hook up SVG component transfer filter to Skia 2025-11-09 01:22:48 +01:00
norbiros
aa5b3ff95a LibGfx: Pass font variation settings to HarfBuzz
Enhance `Font::harfbuzz_font()` to include font variation information
when creating HarfBuzz fonts. This required updating the `Font` struct
to store details about font variations.

I wasn’t aware of this, but it also fixed some visual artifacts with
variable fonts, so big thanks to @Lubrsi for the suggestion!
2025-11-04 21:44:32 +01:00
norbiros
3829a85fde LibWeb: Add basic variable font support
Integrates the new `FontVariationSettings` from LibGfx into LibWeb to
enable initial variable font functionality. Currently, only the `wght`
(weight) axis is fully supported and tested. This update also introduces
support for the CSS `font-variation-settings` property.
2025-11-04 21:44:32 +01:00
Jelle Raaijmakers
4dbae64dce LibWeb: Unify objectBoundingBox and userSpaceOnUse coord transformations
There's a fairly complicated interaction between an SVG gradient's paint
transformation and the gradient coordinate transformation required to
correctly draw gradient fills. This was especially noticeable when
scaling down an SVG, resulting in broken gradient coordinates and
graphical glitches.

This changes the objectBoundingBox units to immediately map to the
bounding box's coordinate system, so we can unify the gradient paint
transformation logic and make it a lot simpler. We only need to undo the
bounding box offset and apply the paint transformation to fix a lot of
gradient fill bugs.
2025-10-27 16:42:27 -07:00
Tim Ledbetter
e1ff1e2095 LibWeb: Implement CanvasPattern.setTransform()
This method applies the given transformation matrix to a pattern.
2025-10-27 16:41:02 -07:00
Jelle Raaijmakers
62ae4e878f LibWeb: Implement support for drawing with CanvasPattern
We already had the API, but drawing to the canvas was not affected by
any created CanvasPattern. This moves CanvasPatternPaintStyle to LibGfx
so we don't have to reach into LibWeb, and implements the plumbing to
let Skia use images as a fill pattern.
2025-10-23 13:20:03 +01:00
Jelle Raaijmakers
f8c4043460 LibWeb: Repeat shader for repeating linear gradient
We implemented repeating linear gradients by expanding a vector of color
stops until the entire range was covered. This is both a bit wasteful
and caused Skia to draw corrupted gradients to screen whenever the total
amount of color stops and positions exceeded 127.

Instead of doing that, use the original color stops for the shader and
repeat it instead of clamping it. We need to do a bit of math to project
positions correctly, but after that the shader repeats itself nicely.

While we're here, calculate the gradient's length and the center point
as floats instead of ints, yielding a slight but noticeable improvement
in gradient rendering (see the diff on the zig zag pattern in
css-gradients.html for an example of this).
2025-10-22 10:45:18 +02:00
Jelle Raaijmakers
8af6da64a6 Tests: Rework CSS gradients test layout
Put the CSS gradients in a grid instead of a single long column. This
makes it much easier to detect changes / view diffs.
2025-10-22 10:45:18 +02:00
Psychpsyo
80b629578e LibWeb: Fix partially selecting non-text nodes
Steps 4 and 5 were swapped since marking all the nodes between the start
and end of the selection now also marks the end node as full, even if it
should be marked as End.
There could be extra logic to avoid marking it if it is a text node, but
this seems easier.

As a whole, this fixes partially selected non-text nodes. In such cases,
where the selection starts or ends inside a node with descendants, it is
impossible to just select from the start node to the end node since that
would select all descendants of the start node and none of the end node.
Previously, this was only half considered and only if the start node was
a descendant of the end node.
2025-10-21 10:23:10 +01:00
Tim Ledbetter
34857ba554 LibWeb: Apply dithering when painting gradients 2025-10-19 16:53:00 +02:00
Lorenz A
1e6ac54b75 LibGfx+LibWeb: Don't display Glyphs that are not on the path 2025-10-08 03:34:53 +01:00
Andreas Kling
d36e5098f8 LibWeb: Support percentage attributes on SVG rect element
This makes the IMDb logo have a yellow background as expected.
2025-09-28 19:25:18 +02:00
Andreas Kling
321809320b LibWeb+LibGfx: Remove Path::close_all_subpaths()
As it turns out, SkPath already behaves the way we need for SVG and HTML
canvas elements. Less work for us, yay! This removes a 5% item from the
profile when scrolling on https://imdb.com/

Note that there's a tiny screenshot test expectation change due to
minor antialiasing differences when we no longer do our redundant
subpath modifications.
2025-09-25 21:42:52 +02:00
Sam Atkins
d9ed784f92 Tests: Add the hidden-img hack to a couple of flaky tests
Editing a WPT import feels wrong because fixing the bug would be better,
but flaky CI helps nobody.
2025-09-25 10:35:28 +01:00
mikiubo
43978ba459 LibWeb: Enable anti-aliasing in DisplayListPlayerSkia::fill_rect
Set SkPaint anti-aliasing to true when filling rectangles
This improves rendering quality by smoothing jagged edges

update clip-path-transformed.html and ref image with anti-aliasing

Partially fixes #5909
2025-09-22 16:22:48 +02:00
Callum Law
1ac7b47764 LibWeb: Disallow spread distance value when parsing text-shadow
`text-shadow` does not support setting a value for spread distance
unlike `box-shadow`.
2025-09-18 15:21:22 +01:00
Callum Law
9aa2d1bd3e LibWeb: Make text-decoration lines entire width of fragment
This fixes an issue where text decorations (e.g. underlines) of text
split across multiple fragments would have unintended 1px gaps.

Gains us 2 WPT passes (imported)
2025-09-12 07:07:15 +01:00
Andreas Kling
67432e35f1 LibGfx: Match vImage premultiply/unpremultiply rounding behavior
Our Color::to_premultiplied() and Color::to_unpremultiplied() used
integer truncation.

Apple’s Accelerate framework (and many other libraries) use
round-to-nearest, which avoids bias and produces results that differ
by ±1 in many cases.

This commit switches both helpers to round-to-nearest and clamps the
results to [0,255]. For alpha==0 we now return fully transparent black
(0,0,0,0) to align with common conventions, instead of preserving RGB.
2025-08-23 14:09:17 +02:00
Jelle Raaijmakers
1a52fcd6ad LibWeb: Draw selected text with its own color
Other browsers such as Chrome and Firefox retain the text's color when
the text is part of a selection, so let's mimic them.
2025-08-20 14:30:16 +02:00
Jelle Raaijmakers
0cf6bd0324 LibWeb: Maintain rect positioning when rounding to device pixel rects
When rounding a CSSPixelRect to a DevicePixelRect, we simply pulled its
width and height through round() and called it a day. Unfortunately this
could negatively affect the rect's perceived positioning.

A rect at { 0.5, 0.0 } with size { 19.5 x 20.0 } should have its right
edge at position 20, but after rounding it would end up at { 1, 0 } with
size { 20 x 20 }, causing its right edge to be at position 21 instead.

Fix this by first rounding the right and bottom edges of the input rect,
and then determining the dimensions by subtracting its rounded position.

Fixes #245.
2025-08-19 21:53:46 +02:00
Sam Atkins
5f986b2c33 LibWeb/Painting: Paint ridge and groove border styles 2025-08-11 11:07:15 +01:00
Sam Atkins
5d4a4e44fe LibWeb/Painting: Paint border-style: double using two solid borders
Call paint_border() recursively, once for the outer line, and once for
the inner one. This is done in a lambda so that we can reuse it for a
couple of other line styles.

Border-radius behaviour doesn't match other browsers, and goes a bit
haywire in some cases. I've left some FIXMEs for someone who
understands the maths here better than I do. 😅

The LineStyle handling is moved to the start of the function, to avoid
unnecessary work.
2025-08-11 11:07:15 +01:00
Timothy Flynn
4a8c70b3a5 LibWeb: Parse CSS/image URLs using DOMURL::parse
DOMURL::parse handles blob URLs.
2025-08-08 17:47:51 +01:00
Jelle Raaijmakers
59a867d3e3 Tests: Enable all screenshot tests on all platforms
With the newly supported fuzzy matching in our test-web runner, we can
now define the expected maximum color channel and pixel count errors per
failing test and set a baseline they should not exceed.

The figures I added to these tests all come from my macOS M4 machine.
Most discrepancies seem to come from color calculations being slightly
off.
2025-07-17 12:59:11 +01:00
Jelle Raaijmakers
115e5f42af LibWeb: Improve graphical list item marker positioning
While 788d5368a7 took care of better text
marker positioning, this improves graphical marker positioning instead.

By looking at how Firefox and Chrome render markers, it's clear that
there are three parts to positioning a graphical marker:

  * The containing space that the marker resides in;
  * The marker dimensions;
  * The distance between the marker and the start of the list item.

The space that the marker can be contained in, is the area to the left
of the list item with a height of the marker's line-height. The marker
dimensions are relative to the marker's font's pixel size: most of them
are a square at 35% of the font size, but the disclosure markers are
sized at 50% instead. Finally, the marker distance is always gauged at
50% of the font size.

So for example, a list item with `list-style-type: disc` and `font-size:
20px`, has 10px between its start and the right side of the marker, and
the marker's dimensions are 7x7.

The percentages I've chosen closely resemble how Firefox lays out its
list item markers.
2025-07-17 09:35:09 +01:00
Jelle Raaijmakers
788d5368a7 LibWeb: Improve list item marker positioning and alpha/roman text
This commit is a three-parter that is hard to separate without breaking
marker rendering:

  1. Any marker style that results in a string, except for a literal
     string (e.g. `list-style-type: "@"`), should get the string ". "
     appended. We forgot to do this for the alpha and roman types.

  2. Instead of using the "pixel size rounded up" from a font and adding
     an arbitrary 1 to that, we now use the exact pixel size for as long
     as possible to improve our vertical positioning of markers.

  3. Instead of always adding a "default marker width" to the marker
     content width, we now only do this if we did not have text metrics
     available (i.e. the marker style is not a text type). This greatly
     improves horizontal positioning of text markers.
2025-07-15 19:05:36 +01:00
Aliaksandr Kalenik
910fd426a2 LibWeb: Allow <svg> to establish a stacking context
83b6bc4 went too far by forbidding SVGSVGElement from establishing a
stacking context. This element type does follow the behavior of CSS
boxes, unlike inner SVG elements like `<rect>`, `<circle>`, etc., which
are not supposed to be aware of concepts like stacking contexts,
overflow clipping, scroll offsets, etc.

This change allows us to delete overrides of `before_paint()` and
`after_paint()` in SVGPaintable and SVGSVGPaintable, because display
list recording code has been rearranged to take care of clipping and
scrolling before recursing into SVGSVGPaintable descendants.

`Screenshot/images/css-transform-box-ref.png` expectation is updated and
fixes a bug where a rectangle at the very bottom of the page was not
clipped correctly.
`Screenshot/images/svg-filters-lb-website-ref.png` has a more subtle
difference, but if you look closely, you’ll see it matches other
browsers more closely now.
2025-07-12 11:01:15 +02:00
Lucien Fiorini
4711c38aa1 Tests: Add screenshot test for the background SVG in the LB website 2025-07-09 18:07:12 +01:00
Psychpsyo
baf2063e31 LibWeb: Fix selection when start node is inside end node
Fixes a regression introduced in
bc8870d019 (in a performant way this
time)
2025-07-04 20:19:50 +02:00
Tim Ledbetter
212d748ded LibWeb: Apply clip rect before painting background and foreground items 2025-06-24 12:56:28 +01:00
Manuel Zahariev
51b4b4a270 LibWeb: Tests for recalculating ordinals after list manipulation
FIXME: Rendering modifications to a list is sometimes not pixel-perfect
       vs. reference (likely a bug). After this is fixed, screenshot
       tests from this commit will likely fail + can be moved to
       ref tests.
2025-06-16 12:44:58 +01:00
InvalidUsernameException
52ba40f161 Tests/LibWeb: Fix flaky css background test
This test was introduced in 70b52e0994 and
was flaky in CI and on my local machine.
2025-05-30 12:03:25 -04:00
Timothy Flynn
4c8b5ba9de Tests/LibWeb: Add a screenshot test for acid2
This test has flaked over the years, so let's add a screenshot test to
catch future regressions.

This copy of the test was taken from:
https://www.webstandards.org/files/acid2/test.html#top

Our CI infra does not support navigating to the "#top" anchor out of the
gate. So the intro section was removed from this copy so that we render
the happy face immediately.
2025-05-22 17:44:40 -04:00
Jelle Raaijmakers
70b52e0994 LibWeb: Use efficient background repeat path for either direction
We're able to efficiently draw repeated bitmaps through Skia, but for
backgrounds we only did so if the background was `repeat-x` _and_
`repeat-y`, and not if just one was set. This meant that for backgrounds
that were only repeating in one direction, we were taking the slow path.
Turns out that this slow path also produced graphical artifacts when
zooming in and out, so let's not do that :^)
2025-05-09 21:37:48 +02:00
Timothy Flynn
30e8f3f1ad LibWeb: Update the <details> layout tree when it is opened/closed
Otherwise, the arrow painted next to the <details> element does not
update.

Using a screenshot test here because apparently the direction of the
arrow has no effect on the layout or paint trees.
2025-05-09 21:37:14 +02:00
Psychpsyo
86f2d291ca Meta: Add HTML doctype to a screenshot test that should have it 2025-05-06 20:04:18 +02:00
Jelle Raaijmakers
71665fa504 LibWeb: Scale font size by 1.15 for line-height: normal
Browsers such as Chrome and Firefox apply an arbitrary scale to the
current font size if `normal` is used for `line-height`. Firefox uses
1.2 while Chrome uses 1.15. Let's go with the latter for now, it's
relatively easy to change if we ever want to go back on that decision.

This also requires updating the expectations for a lot of layout tests.
The upside of this is that it's a bit easier to compare our layout
results to other browsers', especially Chrome.
2025-05-05 13:15:56 +02:00
Psychpsyo
82387e2127 LibWeb: Avoid changing button border color on disable/hover 2025-04-30 20:13:14 +01:00
Aliaksandr Kalenik
1e7922fac8 LibGfx+LibWeb: Add Path::glyph_run() and use in canvas
Canvas text painting needs to support per-glyph font fallbacks, which
means we can't hand over responsibility for text shaping to Skia and
instead need to extract glyph paths from our own shaped GlyphRun.
2025-04-21 09:51:16 +02:00
Mehran Kamal
6ba60188b4 LibWeb+LibGfx: Paint dash array and offset for SVG and Canvas 2025-04-14 18:00:38 +01:00
Mehran Kamal
a64902ba25 LibWeb+LibGfx: Paint miter_limit for SVG and Canvas 2025-04-14 18:00:38 +01:00
Glenn Skrzypczak
da09608156 LibWeb/Painting: Fix blending with viewport background
The viewport is now drawn onto transparent black instead of the
background color of the viewport.
2025-04-01 13:38:00 +02:00
Aliaksandr Kalenik
552dd18696 Revert "LibWeb/CSS: Implement 'background-blend-mode'"
This reverts commit a73cd88f0c.

Emitting SaveLayer for each paintable made rasterization a lot slower
on every website because now Skia has to allocate enormous amounts of
temporary surfaces. Let's revert it for now and figure how to implement
it with less aggressive SaveLayer usage.
2025-03-28 16:48:03 +00:00