Commit Graph

647 Commits

Author SHA1 Message Date
Aliaksandr Kalenik
a1d538ae58 LibGfx: Cache GPU textures for bitmap-backed ImmutableBitmaps
Previously, bitmap-backed images were stored as raster SkImages and
re-uploaded to the GPU every frame. This caused significant overhead
in createProxyFromBitmap, uploadToTexture, and memmove.

Now, ensure_sk_image() converts raster SkImages to GPU textures using
SkImages::TextureFromImage() on first use. The texture is cached and
reused for subsequent frames.

- Mipmaps disabled (kNo) to reduce upload time and memory
- Budgeted (kYes) to let Skia manage GPU memory and evict under pressure
- Falls back to raster rendering if no GPU context available
2026-01-24 21:21:28 +01:00
Aliaksandr Kalenik
44d90af3d6 LibGfx+LibWeb: Cache SkTextBlob in GlyphRun
Previously, SkTextBlob was built on every paint in
DisplayListPlayerSkia::draw_glyph_run(), which meant:
- Repeated work when the same display list is painted multiple times
- Glyph arrays were allocated and populated on each paint

Now the blob is built once during display list recording and cached in
GlyphRun.
2026-01-24 15:22:03 +01:00
Luke Wilde
1494599b82 LibGfx: Add missing SkiaBackendContext locks
This adds locking for:
- Creating a sk_image from ImmutableBitmap
- Destroying ImmutableBitmap's sk_image
- Read/writing PaintingSurface for Bitmaps
2026-01-23 17:15:23 +01:00
Aliaksandr Kalenik
cb8ecb3c11 LibGfx+LibWeb: Move SVG mask/clip composition from CPU to GPU
Previously, both mask and clip-path were rendered to separate mutable
Gfx::Bitmap objects which forced CPU rasterization. They were then
combined using a CPU pixel-by-pixel operation before being returned
as an ImmutableBitmap.

Instead of including mask in the final bitmap as already rasterized
images, we now use display lists which opens opportunity to utilize
GPU if available.

Bitmap::apply_mask() and ApplyMaskBitmap display list command are no
longer used and have been removed.
2026-01-23 16:23:06 +01:00
Zaggy1024
e6dbcccb99 LibGfx+LibMedia: Send video frames to Skia as subsampled YUV
This saves us from having our own color conversion code, which was
taking up a fair amount of time in VideoDataProvider. With this change,
we should be able to play high resolution videos without interruptions
on machines where the CPU can keep up with decoding.

In order to make this change, ImmutableBitmap is now able to be
constructed with YUV data instead of an RBG bitmap. It holds onto a
YUVData instance that stores the buffers of image data, since Skia
itself doesn't take ownership of them.

In order to support greater than 8 bits of color depth, we normalize
the 10- or 12-bit color values into a 16-bit range.
2026-01-22 19:44:36 +01:00
Andreas Kling
177809db6e LibGfx: Validate color space size and deserialization result on decode
A malicious IPC peer could claim an enormous color space size, causing
OOM when we try to allocate a buffer. Add a 1 MiB limit since color
space profiles shouldn't be anywhere near that large.

Also validate that SkColorSpace::Deserialize() actually succeeded
before using the result.
2026-01-22 17:38:15 +01:00
Andreas Kling
039fa00bfc LibGfx: Use checked arithmetic when encoding BitmapSequence
The total_buffer_size calculation could theoretically overflow if we
tried to encode a sequence of bitmaps with combined size > SIZE_MAX.

Use Checked<size_t> and VERIFY to catch this (unlikely) encoding bug.
2026-01-22 17:38:15 +01:00
Callum Law
c35ecc8b1c LibWeb: Respect font-width for variable fonts 2026-01-21 23:49:25 +01:00
Callum Law
3f97f1579f LibGfx: Remove default parameters for some font related functions
We always pass these values so there is no need for default parameters
2026-01-21 23:49:25 +01:00
Callum Law
89a360e643 LibGfx+LibWeb: Remove unused FontWeight.h 2026-01-21 23:49:25 +01:00
Tim Ledbetter
3e704e0fd6 LibGfx+LibWeb: Fall back to system fonts for missing glyphs
When rendering text, if none of the fonts in the cascade list contain a
glyph for a given code point, we now query Skia's font manager to find
a system font that can render it.
2026-01-21 14:01:35 +01:00
Aliaksandr Kalenik
a36fcdb9c5 LibGfx: Add to_svg_string() method to Path
This converts a Path to its SVG path data string representation using
Skia's SkParsePath::ToSVGString().
2026-01-19 04:01:37 +01:00
ayeteadoe
5279e0ce73 CMake: Remove ENABLE_WINDOWS_CI option and adjust presets to match Unix
ENABLE_WINDOWS_CI and the *_CI presets were initially added back when
the AK library and all the AK Test* executables were the only targets
that supported building and running in CI. Since then, almost all the
targets in the codebase are built on Windows besides the following:
    - LibLine
    - test-262-runner

Since these targets above are not required to actually run or test the
browser on Windows in its current experimental state, fully disabling
them should be fine for now.

ENABLE_WINDOWS_CI was also used to exclude test-web from ctest. This
can be fully disabled on Windows for now until proper runtime support
is added.

The remaining locations were all using ENABLE_WINDOWS_CI as a proxy for
ENABLE_ADDRESS_SANITIZER, so we can just be explicit instead.

The new presets map much more directly to the unix Release, Debug, and
Sanitizer presets which should make setting up ladybird on Windows less
confusing.

We also make the new Windows_Experimental_Release preset the default in
ladybird.py to match Unix.
2026-01-16 11:15:16 -07:00
Jonathan Gamble
8f1cb4cbb0 LibWeb: Implement resizing for eligible elements and update scrollbars
Add ElementResizeAction to Page (maybe there's a better place). It's
just a mousemove delegate that updates styles on the target element.

Add ChromeMetrics for zoom-invariant chrome like scrollbar thumb
thickness, resize gripper size, paddings, etc. It's not user-stylable
but separates basic concerns in a way that a visually gifted
designer unlike myself can adjust to taste.

These values are pre-divided by zoom factor so that PaintableBox can
continue using device_pixels_per_css_pixel calls as normal.

The adjusted metrics are computed on demand from Page multiple times
per paint cycle, which is not ideal but avoids lifetime management and
atomics. Maybe someone with more surety about the painting flow control
can improve this, but it won't be a huge win. If profiling shows
this slowing paints, then Ladybird is in good shape.

Update PaintableBox to draw the resize gripper and deconflict
the scrollbars. Set apropriate cursors for scrollbars and gripper in
mousemove. We override EventHandler's cursor handling because nothing
should ever come between a man and his resize gripper.

Chrome metrics use the CSSPixels class. This is good because it's
broadly compatible but bad because they're actually different units
when zoom is not 1.0. If that's a problem, we could make a new type
or just use double.
2026-01-12 11:00:14 +00:00
Andreas Kling
98a1bff615 LibGfx: Avoid guessing HarfBuzz segment properties for ASCII text
For ASCII text, we know the script is Latin and direction is LTR.
Set these properties directly instead of calling
hb_buffer_guess_segment_properties(), which scans the text buffer
to detect script and direction.

For non-ASCII text, use the text_type parameter to set direction
when known (Ltr/Rtl), reducing guesswork to just script detection.
2026-01-11 11:10:19 +01:00
Rocco Corsi
bec3f04637 LibGfx: Make NVIDIA 10 series GPU work with Dedicated Memory Allocation 2026-01-06 17:28:43 +01:00
Luke Wilde
2058c05d50 LibGfx: Create Gfx::Bitmap for PaintingSurface in ImmutableBitmap 2026-01-05 15:56:15 +01:00
Undefine
7f42cf3a0e LibGfx: Switch Vulkan image sharing mode to VK_SHARING_MODE_EXCLUSIVE
The validation layers complain if it's set to concurrent and we have
only one queue.
2026-01-02 10:23:46 +01:00
Undefine
d71e5f676f LibGfx: Remove incorrect Vulkan queue family index from image creation
This does not seem to impact functionality and gets rid of a validation
layer warning.
2026-01-02 10:23:46 +01:00
Undefine
988f631cdf LibGfx: Request the VK_EXT_external_memory_dma_buf Vulkan extensions
Otherwise the validation layers complain that this is required when
using VK_EXTERNAL_MEMORY_HANDLE_TYPE_DMA_BUF_BIT_EXT as an image
handle.
2026-01-02 10:23:46 +01:00
Undefine
8601430f5b LibGfx: Request the VK_KHR_image_format_list Vulkan extensions
Otherwise the validation layers complain that it's required by
`VK_EXT_image_drm_format_modifier`.
2026-01-02 10:23:46 +01:00
ayeteadoe
ee3aa865af Meta+LibGfx+LibWeb: Update skia to 144 and remove overlay port
Skia deprecated some non-span versions of their API, but they provided
SK_SUPPORT_UNSPANNED_APIS to expose the legacy versions.

SkFontMgr_New_FontConfig now requires a font scanner to be passed in.

There were a few screenshot tests that visibily looked the same but skia
must've changed some rendering infrastructure as the PNGs were not
matching anymore so I rebaselined those and adjusted the fuzzy matching
config to allow them to pass on both macOS and Linux.

The empty-radial-gradient-crash Ref test started to fail as we were
setting the horizontal scale factor to inf in when the height = 0. It
looks like something changed to make doing that not valid anymore.

The overlay port is removed as the issues, mainly skcms symbol import
and export were resolved upstream in skia and utilized in the new port
version.
2025-12-17 12:00:33 +01:00
Andreas Kling
2577c5ce67 Revert "Meta+LibGfx+LibWeb: Update skia to 144 and remove overlay port"
This reverts commit ac9688ea1e.

Broke the build on arm64 Linux.
2025-12-15 14:12:34 -06:00
ayeteadoe
ac9688ea1e Meta+LibGfx+LibWeb: Update skia to 144 and remove overlay port
Skia deprecated some non-span versions of their API, but they provided
SK_SUPPORT_UNSPANNED_APIS to expose the legacy versions.

SkFontMgr_New_FontConfig now requires a font scanner to be passed in.

There were a few screenshot tests that visibily looked the same but skia
must've changed some rendering infrastructure as the PNGs were not
matching anymore so I rebaselined those and adjusted the fuzzy matching
config to allow them to pass on both macOS and Linux.

The empty-radial-gradient-crash Ref test started to fail as we were
setting the horizontal scale factor to inf in when the height = 0. It
looks like something changed to make doing that not valid anymore.

The overlay port is removed as the issues, mainly skcms symbol import
and export were resolved upstream in skia and utilized in the new port
version.
2025-12-15 10:56:27 +01:00
Timothy Flynn
612558144b LibGfx: Add a stringifier for StandardCursor 2025-12-03 12:23:56 +01:00
Timothy Flynn
dcf8463886 LibGfx: Remove unused StandardCursor::__Count 2025-12-03 12:23:56 +01:00
InvalidUsernameException
ce2c4a3417 LibGfx+LibWeb: Fix compile errors in clang-cl from recent header cleanup
The recent commits 28ba610f32 and
70c4ed261f adjusted some include
directives to avoid excessive recompilation when changing some header
files. This has broken compilation with clang-cl on Windows without
getting noticed before the PRs were merged.
2025-11-30 08:45:29 -05:00
InvalidUsernameException
1f8a42c367 LibGfx: Add a test for bitmap export
The verified pixel output in this test just reflects currently observed
behavior, I have not verified that all cases output the correct data wrt
what the spec expects.
2025-11-28 18:32:48 +01:00
InvalidUsernameException
a81e407c44 LibWeb: Do not crash when converting a bitmap to RGB888
This makes it so that we can visit satellite and hybrid view on
maps.apple.com. Previously this would crash from a bounds check due to
us asking Skia to write 32bpp RGBx8888 data into a buffer sized for
24bpp RGB888.
2025-11-28 18:32:48 +01:00
InvalidUsernameException
9e60dc57b4 LibGfx: Add FIXME about potentially incorrect alpha handling 2025-11-28 18:32:48 +01:00
InvalidUsernameException
6847185d9a LibGfx: Mask alpha values when setting pixels on non-alpha bitmaps
This is not technically necessary, presumably the bitmap type does not
offer any guarantees about what values are stored in the alpha component
for non-alpha pixel formats.

But the previous behavior meant that `set_pixel()` would produce
different values in the alpha component depending on whether the bitmap
format was RGBx or BGRx (i.e. `color.alpha()` vs. 0x00), which can be a
bit confusing.
2025-11-28 18:32:48 +01:00
InvalidUsernameException
88c4814de6 LibGfx+LibWeb: Extract bitmap-to-buffer conversion into LibGfx
This factors the conversion logic to be independent from WebGL code,
allowing us to write unit tests for it that can run in CI (since WebGL
can't run in CI).
2025-11-28 18:32:48 +01:00
InvalidUsernameException
fa181c2be8 LibGfx: Do not over-promise what type gets returned 2025-11-28 18:32:48 +01:00
InvalidUsernameException
7c315ef67f Everywhere: Unify naming of RGBA-like colors
The `Bitmap` type was referring to to its internal pixel format by a
name that represents the order of the color components as they are layed
out in memory. Contrary, the `Color` type was using a naming that where
the name represents the order of the components from most to least
significant byte when viewed as a unsigned 32bit integer. This is
confusing as you have to keep remembering which mental model to use
depending on which code you work with.

To unify the two, the naming of RGBA-like colors in the `Color` type has
been adjusted to match the one from the Bitmap type. This seems to be
generally in line with how web APIs think about these types:
* `ImageData.pixelFormat` can be `rgba-8unorm` backed by a
  `Uint8ClamedArray`, but there is no pixel format backed by a 32bit
  unsigned type.
* WebGL can use format `RGBA` with type `UNSIGNED_BYTE`, but there is no
  such format with type `UNSIGNED_INT`.

Additionally, it appears that other browsers and browser-adjacent
libraries also think similarly about these types:
* Firefox:
  https://github.com/mozilla-firefox/firefox/blob/main/gfx/2d/Types.h
* WebKit:
  https://github.com/WebKit/WebKit/blob/main/Source/WebCore/platform/graphics/PixelFormat.h
* Skia:
  https://chromium.googlesource.com/skia/+/refs/heads/main/include/core/SkColorType.h

This has the not so nice side effect that APIs that interact with these
types through 32bit unsigned integers now have the component order
inverted due to little-endian byte order. E.g. specifying a color as hex
constant needs to be done as `0xAABBGGRR` if it is to be treated as
RGBA8888.

We could alleviate this by providing endian-independent APIs to callers.
But I suspect long-term we might want to think differently about bitmap
data anyway, e.g. to better support HDR in the future. However, such
changes would be more involved than just unifying the naming as done
here. So I considered that out of scope for now.
2025-11-28 18:32:48 +01:00
InvalidUsernameException
07f61f2cec LibGfx: Remove redundant enum
With the templatized overload of set_pixel() gone, there is no reason to
have two separate enums anymore.
2025-11-28 18:32:48 +01:00
InvalidUsernameException
645052b87e LibGfx: Remove some unused function overloads 2025-11-28 18:32:48 +01:00
InvalidUsernameException
28ba610f32 Everywhere: Avoid large rebuilds when editing (Immutable)Bitmap headers
This reduces the number of recompiled files as follow:
- Bitmap.h: 1309 -> 101
- ImmutableBitmap.h: 1218 -> 75
2025-11-28 18:32:48 +01:00
InvalidUsernameException
40f089a043 LibGfx: Sort source files alphabetically 2025-11-28 18:32:48 +01:00
InvalidUsernameException
bc44203744 LibGfx+Tests: Load bmp files with unpremultiplied alpha
From what I can tell BMP files with an alpha channel always store
unpremultiplied alpha. So let's load them as such to avoid rendering
artifacts from using the wrong alpha type.
2025-11-28 17:00:29 +01:00
Jelle Raaijmakers
3b7eede694 LibGfx: Report premultiplied alpha type for opaque Skia surfaces
We don't discern between opaque and non-opaque alpha types in LibGfx,
which at some point we might need to do. But for now, assume all opaque
Skia surfaces have premultiplied alpha.

Fixes #6892.
2025-11-26 09:24:38 +01:00
ayeteadoe
59c963f98f Meta+LibGfx: Remove fontconfig dependency on Windows
Previously when launching a UI process and/or a WebContent process on
Windows, the following message would be output to the console:

Fontconfig error: Cannot load default config file: No such file: (null)

Apparently on Windows, you have to provide a font .conf file to
fontconfig explicitly. Since we are not doing that, the default fonts
that are backed off to are not ideal.

Similar to how we aren't using fontconfig on Android, Windows also has
native font infrastructure in terms of both a collection of System
installed fonts as well as skia support for font managers that use
native Windows APIs. With that, we can remove the usage of fontconfig
entirely and improve the fonts used on websites like ladybird.org or
google.com.
2025-11-22 07:51:55 -05:00
Tim Ledbetter
36c6079dbc LibWeb+LibGfx: Implement SVGFEMorphologyElement
This filter primitive is used to erode or dilate an image.
2025-11-15 16:08:53 +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
Andreas Kling
baa9b6cc34 LibWeb: Prefer non-emoji font when deciding width of space between words
This fixes an issue where having an emoji font first in the font-family
cascade list would cause us to get the space width from the emoji font
as well.

We now look at adjacent text chunks when deciding which font to use for
space widths, instead of just blindly obeying the font-family value.
2025-11-06 23:42:01 +01:00
Andreas Kling
0fc0c84856 LibGfx: Add Font API to determine if it's (probably) an emoji font
This uses some heuristics since I don't think there's a simple way to
determine if something is "an emoji font".
2025-11-06 23:42:01 +01:00
Tim Ledbetter
713191a078 LibGfx: Remove unused alpha premultiplication functions 2025-11-05 15:39:14 +01:00
Tim Ledbetter
d37eb3de32 LibGfx: Use Skia to speed up alpha conversions on Linux 2025-11-05 15:39:14 +01:00
Tim Ledbetter
706d075835 LibGfx: Don't attempt alpha conversion for opaque images 2025-11-05 15:39:14 +01:00
Aliaksandr Kalenik
ed921b66f5 LibGfx+LibWeb: Delete unused Line class and Rect methods 2025-11-04 23:16:02 +01:00