Commit Graph

110 Commits

Author SHA1 Message Date
Shannon Booth
6afe179e5a LibWeb: Generate canvas settings from IDL bindings 2026-05-09 10:49:49 +02:00
Shannon Booth
5adfd1c43a LibWeb/Bindings: Generate struct definitions from IDL dictionaries
Previously we were inconsistent by generating code for enum definitions
but not generating code for dictionaries. With future changes to the
IDL generator to expose helpers to convert to and from IDL values
this produced circular depdendencies. To solve this problem, also
generate the dictionary definitions in bindings headers.
2026-05-09 10:49:49 +02:00
Aliaksandr Kalenik
f8640d813a LibGfx+LibWeb: Make DecodedImageFrame a value type
DecodedImageFrame only wraps a ref-counted Bitmap and color-space
metadata. The frame object itself does not provide shared mutable
state or lifetime ownership beyond those members, so ref-counting it
adds an unnecessary layer of indirection.
2026-05-07 16:08:13 +02:00
Andreas Kling
a414136d7c LibWeb: Account text and image storage as external memory
Report DOM character data, decoded image frames, ImageBitmap pixel
buffers, and 2D canvas surfaces through the GC external memory hook.
This lets image and text-heavy pages participate in GC threshold
calculations through their retained backing storage.
2026-05-07 10:03:09 +02:00
Aliaksandr Kalenik
76c79ee522 LibGfx: Remove ImmutableBitmap
DecodedImageFrame now owns decoded bitmap pixels directly, so the
separate ImmutableBitmap wrapper no longer carries useful semantics.
Remove the class and pass decoded image frames or bitmaps at the
boundaries where pixels are actually required.

The Skia image cache now keys off DecodedImageFrame, matching the
display-list commands that paint decoded images. Video frames stay
owned by LibMedia, with the explicit YUV-to-bitmap conversion living
at HTMLVideoElement's decoded-frame entry point for canvas and WebGL
callers.
2026-05-05 14:39:17 -05:00
Aliaksandr Kalenik
40f2abb7fe LibGfx+LibWeb: Add DecodedImageFrame
Decoded image data should not continue to traffic in ImmutableBitmap now
that the bitmap wrapper is being retired. Introduce DecodedImageFrame as
the paintable decoded-image unit and store a Bitmap plus ColorSpace in
it directly.

Thread the new frame type through decoded image data, display-list
image commands, filters, canvas drawImage, patterns, WebGL texture
upload, and CSS/SVG image consumers. ImmutableBitmap remains only at
the legacy boundaries that still need it, such as HTML video snapshots
and callers that explicitly ask for a bitmap snapshot.

This keeps color-space ownership with the decoded frame while making
the expensive or legacy ImmutableBitmap path explicit at the few call
sites that still need it.
2026-05-05 14:39:17 -05:00
Aliaksandr Kalenik
3c25d080b1 LibGfx: Move painting surface snapshots to PaintingSurface
ImmutableBitmap still owned the helper that read pixels from a
PaintingSurface and wrapped the result as an ImmutableBitmap. That kept
a surface readback operation attached to the type we are trying to
remove, even though the snapshot is really a property of the painting
surface.

Add PaintingSurface::snapshot_bitmap() as the explicit readback path.
The remaining callers now wrap that bitmap in ImmutableBitmap only at
the places that still need the old abstraction. Canvas serialization
also uses the same helper, so the BGRA8888 premultiplied snapshot
policy has a single owner.
2026-05-05 14:39:17 -05:00
Aliaksandr Kalenik
b61fb627d7 LibGfx+LibWeb: Cache Skia images outside of ImmutableBitmap
ImmutableBitmap currently caches an SkImage tied to a specific Skia
backend context, which prevents using the same bitmap with more than one
context. Move that cache out into a per-painter
ImmutableBitmapSkiaImageCache so the cached image lives next to the
context that produced it.

Painters and the display-list player prune their caches each frame, and
canvas 2D contexts prune when presenting, so unused images do not
accumulate.
2026-05-04 20:12:21 +02:00
Aliaksandr Kalenik
4f54b16315 LibWeb: Preserve non-ASCII characters in canvas text preparation
The whitespace-normalization loop in prepare_text() called
StringBuilder::append() on each code point, which resolves to the
`char` overload and truncates non-ASCII characters. measureText("ó")
therefore returned a width of 0, despite fillText painting the glyph.

Use append_code_point() instead, and add a regression test for both
precomposed and decomposed accented text.
2026-04-25 14:54:18 +02:00
Shannon Booth
fd44da6829 LibWeb/Bindings: Emit one bindings header and cpp per IDL
Previously, the LibWeb bindings generator would output multiple per
interface files like Prototype/Constructor/Namespace/GlobalMixin
depending on the contents of that IDL file.

This complicates the build system as it means that it does not know
what files will be generated without knowledge of the contents of that
IDL file.

Instead, for each IDL file only generate a single Bindings/<IDLFile>.h
and Bindings/<IDLFile>.cpp.
2026-04-21 07:36:13 +02:00
Callum Law
7d15916754 LibWeb: Use correct LRC for absolutizing canvas font values
Canvases belonging to `OffscreenCanvas` and disconnected
`HTMLCanvasElement`s use a LRC based on the initial canvas context font
size of 10px.

This will be covered by WPT tests in a later commit once we expose the
absolutized value in the font getter
2026-04-08 14:31:43 +01:00
Callum Law
1fdcea2b7b LibWeb: Disallow random() in canvas context value setters
This introduces two new top-level `ValueParsingContext`s,
`OnScreenCanvasContextFontValue` and `CanvasContextGenericValue`, while
these are handled the same for now, there is a distinction is whether or
not they allow tree counting functions (which will come in a later
commit)
2026-04-08 14:31:43 +01:00
Tim Ledbetter
26389363ad LibGfx+LibWeb: Move Skia backend context to process level singleton
Previously, this was attached to the traversable navigable. Using a
singleton instead allows us to use the context for detached documents.
2026-03-19 13:35:16 +01:00
Jelle Raaijmakers
67d822cbbe LibGfx+LibWeb: Implement CanvasTextDrawingStyles.letterSpacing 2026-03-12 17:13:16 +01:00
Jelle Raaijmakers
2efd7cdf8c LibWeb: Apply correct text baseline in CRC2D::text_path()
Fixes the vertical alignment of text in buttons on
https://lazyslug.com/lifeview/plugin/viewer.html.
2026-03-10 11:33:35 +01:00
Aliaksandr Kalenik
5bfc4a3c41 LibWeb: Cache display list commands per paintable
Cache the display list commands produced by each PaintableBox's paint()
on a per-phase basis. On subsequent display list rebuilds, if a
paintable's cache is still valid, replay the recorded commands directly
— skipping paint() and all the property resolution it entails.

Besides saving time on property resolution, this also enables Skia to
reuse path tessellation results across frames — e.g. border paths are
preserved in the cache and don't need to be re-tessellated on every
repaint.
2026-03-04 19:35:45 +01:00
Aliaksandr Kalenik
eae94a8a46 LibWeb: Route repaint requests through paintables, not Document
Rename Document::set_needs_display() to set_needs_repaint() and make it
private. External callers must now go through Node/Paintable which
route the request to the document internally.

Fix one existing misuse in AnimationEffect that was calling
document-level set_needs_display() instead of routing through the
target element's paintable.

This is preparation for per-paintable display list command caching:
repaint requests must go through specific paintables so their cached
command lists can be invalidated.
2026-03-04 19:35:45 +01:00
Andreas Kling
a146225331 LibWeb: Use unsafe layout/paintable accessors where appropriate
Add unsafe_layout_node(), unsafe_paintable(), and unsafe_paintable_box()
accessors that skip layout-staleness verification. These are for use in
contexts where accessing layout/paintable data is legitimate despite
layout not being up to date: tree construction, style recalculation,
painting, animation interpolation, DOM mutation, and invalidation
propagation.

Also add wrapper APIs on Node to centralize common patterns:
- set_needs_display() wraps if (unsafe_paintable()) ...set_needs_display
- set_needs_paint_only_properties_update() wraps similar
- set_needs_layout_update() wraps if (unsafe_layout_node()) ...

And add Document::layout_is_up_to_date() which checks whether layout
tree update flags are all clear.
2026-02-26 21:09:08 +01:00
Andreas Kling
ca72156497 LibWeb: Don't require layout node when setting canvas 2D shadowColor
Use update_style_if_needed_for_element() and resolve colors via
computed properties instead of forcing a full layout update.
2026-02-22 12:43:01 +01:00
Andreas Kling
cbf8b70d42 LibWeb: Don't require layout node when setting canvas 2D filter
Setting the filter property on a CanvasRenderingContext2D would crash
with a null pointer dereference if the canvas element had no layout
node (e.g. a detached canvas not in the document).

Instead of forcing a full layout update and requiring a layout node,
we now only update style if needed and resolve lengths via the
element's computed properties when available, falling back to
document-level defaults otherwise. This matches the pattern used by
CanvasTextDrawingStyles.
2026-02-22 12:43:01 +01:00
Aliaksandr Kalenik
004e5f851e LibWeb: Use ExternalContentSource for canvas painting
present() now snapshots the PaintingSurface into an ImmutableBitmap
and publishes it to the ExternalContentSource, so the rendering thread
never touches the live GPU surface — eliminating the data race
described in the ExternalContentSource commit (problem 1).

Canvas elements are registered with Page and presented once per frame
from the event loop, rather than on every individual draw call in
CRC2D::did_draw(). A dirty flag on HTMLCanvasElement ensures the
snapshot is only taken when content has actually changed, and makes
the present() call in CanvasPaintable::paint() a no-op when the
surface has already been snapshotted for the current frame.
2026-02-20 18:41:33 +01:00
Callum Law
9f7f623455 LibWeb: Store FilterOperation::DropShadow sub-values as StyleValues
This simplifies handling and brings it into line with other `StyleValue`
types
2026-02-16 12:09:23 +00:00
Callum Law
98e62cf86a LibWeb: Store FilterOperation::Blur::radius as StyleValue
This simplifies handling and brings it into line with other `StyleValue`
types
2026-02-16 12:09:23 +00:00
Callum Law
c529614e67 LibWeb: Store FilterOperation::HueRotate::angle as StyleValue
This simplifies handling and brings it into line with other `StyleValue`
types
2026-02-16 12:09:23 +00:00
Callum Law
e410efcfb7 LibWeb: Absolutize parsed canvas filter value 2026-02-16 12:09:23 +00:00
Callum Law
cd799aa7e7 LibWeb: Forward declare CSS::FilterOperation structs
This means we don't need to include `FilterValueListStyleValue.h` in as
many places - reducing the rebuild from editing that file from 717 files
to 19.
2026-02-16 12:09:23 +00:00
Aliaksandr Kalenik
901cc28272 LibWeb: Reduce recompilation impact of DOM/Document.h
Remove 11 heavy includes from Document.h that were only needed for
pointer/reference types (already forward-declared in Forward.h), and
extract the nested ViewportClient interface to a standalone header.

This reduces Document.h's recompilation cascade from ~1228 files to
~717 files (42% reduction). Headers like BrowsingContext.h that were
previously transitively included see even larger improvements (from
~1228 down to ~73 dependents).
2026-02-11 20:02:28 +01:00
Tim Ledbetter
e16618bdd1 LibWeb: Apply textBaseline offset in Canvas measureText() 2026-01-15 10:31:23 +01:00
Tim Ledbetter
191e8218dc LibWeb: Use correct font metrics calculations in Canvas measureText() 2026-01-15 10:31:23 +01:00
Tim Ledbetter
584e0996c9 LibWeb: Store color as a StyleValue in FilterOperation::DropShadow 2026-01-06 12:13:13 +01:00
Andreas Kling
1640b7957c LibWeb: Don't use GC::Root for 2D canvas fill/stroke styles
Using GC::Roots here was causing a reference cycle and leaking the world
whenever gradients or patterns were used on a 2D canvas.
2025-12-24 10:19:28 +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
Callum Law
70c4ed261f LibWeb: Reduce the number of headers CSS Parser.h is included in
Reduces the rebuild required when editing this file
2025-11-28 16:15:49 +00: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
Adrian Kiezik
823deacc27 LibWeb: Implement CanvasRenderingContext2D direction property
When direction is 'rtl':
  - textAlign='start' now aligns text to the right
  - textAlign='end' now aligns text to the left

Fixes the FIXME at CanvasRenderingContext2D.cpp:283
2025-10-27 22:03:26 -07:00
Tim Ledbetter
9da723b5c6 LibWeb: Ensure layout is up to date before resolving canvas colors 2025-10-27 16:56:01 -07:00
Callum Law
5381146e85 LibWeb: Include PropertyID.h in fewer header files
This reduces the size of the recompile when PropertyID.h is modified
from ~1500 to ~125
2025-10-27 14:50:54 +00:00
Tim Ledbetter
9dceb06992 LibWeb: Don't paint canvas objects with non-visible fill styles 2025-10-26 16:45:38 +01:00
Tim Ledbetter
1c00279488 LibWeb: Reset Painter when resetting canvas to its initial state 2025-10-23 18:52:36 +02: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
Tim Ledbetter
976912f3e9 LibWeb: Normalize negative drawImage() source/destination dimensions 2025-10-22 12:29:04 +02:00
Tim Ledbetter
c4e56cc845 LibWeb: Throw error when calling drawImage() with a broken image 2025-10-22 10:44:58 +02:00
Tim Ledbetter
f1571c4217 LibWeb: Ensure drawImage() always uses the first image frame 2025-10-22 01:25:46 +02:00
Tim Ledbetter
7db73118e9 LibWeb+LibGfx: Draw shadows for stroke joins and caps 2025-10-21 18:55:08 +02:00
Tim Ledbetter
0f295e8989 LibWeb: Take transforms into account when drawing shadows 2025-10-21 18:55:08 +02:00
Tim Ledbetter
0516c414d4 LibWeb: Don't draw shadows for transparent gradient fills 2025-10-21 18:55:08 +02:00
Tim Ledbetter
13f551612c LibWeb: Don't draw shadows if shadow offset and blur are not set 2025-10-21 18:55:08 +02:00
Tim Ledbetter
eb44cca5bd LibWeb: Ignore non-finite shadow offset values 2025-10-21 18:55:08 +02:00
Tim Ledbetter
b99c0c6a7f LibWeb: Account for paint style and global alpha when drawing shadows 2025-10-21 18:55:08 +02:00
Tim Ledbetter
494fcc40ac LibWeb: Account for transforms in isPointInPath() 2025-10-21 17:42:28 +02:00