LibGfx: The Core Graphics Engine Behind Ladybird's Rendering Pipeline

LibGfx is the foundational 2D graphics subsystem in Ladybird that abstracts all pixel-level operations through a backend-agnostic Painter API, enabling the browser to render web content, canvas elements, and UI surfaces using Skia, Vulkan, or Metal without changing high-level drawing logic.

LadybirdBrowser/ladybird relies on LibGfx as the single source of truth for every visual output in the browser. This core library provides the essential data structures, drawing primitives, and rasterization abstractions that bridge the high-level rendering logic of LibWeb with hardware-accelerated backends.

LibGfx Architecture: Bridging High-Level Rendering and Hardware Acceleration

LibGfx serves as the intermediary layer between Ladybird's web engine and the underlying graphics hardware. The library exposes a unified interface that allows the rest of the codebase to remain agnostic about whether pixels are being pushed by a CPU rasterizer or a GPU compute pipeline.

Core Data Structures: Bitmaps and Geometry

At the heart of LibGfx are the pixel buffer abstractions defined in Libraries/LibGfx/Bitmap.h and Libraries/LibGfx/Bitmap.cpp. The library provides three primary bitmap types:

  • Bitmap – A mutable, memory-backed pixel buffer used as the primary paint target
  • ImmutableBitmap – A read-optimized variant for static image data
  • ShareableBitmap – A buffer designed for cross-process texture sharing

These are complemented by essential geometry primitives including Point, Rect, Size, and VectorN, alongside color management utilities like Color, Palette, and SystemTheme defined in the Gfx namespace.

The Painter API: Backend-Agnostic Drawing

The abstract Painter interface in Libraries/LibGfx/Painter.h defines the complete set of 2D drawing operations available to the rest of Ladybird. This includes:

  • Rectangular fills and strokes
  • Path-based rendering (stroke and fill)
  • Bitmap blitting and compositing
  • Clipping regions and transform matrices
  • Blend modes and alpha compositing

Calling Gfx::Painter::create() instantiates the default Skia-based implementation (PainterSkia.cpp), though the same interface can target Vulkan (VulkanContext.h/.cpp) or Metal (MetalContext.h/.mm) when hardware acceleration is enabled.

Image Decoding and Encoding Pipeline

LibGfx handles all image format I/O through decoders located in Libraries/LibGfx/ImageFormats/. These loaders support PNG, JPEG, WebP, GIF, TIFF, and other formats, decoding raw bytes into Bitmap instances that the layout engine can paint directly.

When a web page references an image, Ladybird's ImageDecoder service utilizes these LibGfx loaders to produce a Bitmap. Conversely, the PNGWriter and similar encoders allow the browser to export rendered content back to standard file formats.

Integration Points: How LibGfx Powers Ladybird's Components

Every visual output in Ladybird passes through LibGfx, from HTML canvas elements to native UI surfaces.

HTML5 Canvas Implementation

In Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp, the web engine creates a Gfx::Painter instance bound to the canvas's backing bitmap. This allows the Canvas 2D API methods to map directly to LibGfx drawing commands:

auto painter = Gfx::Painter::create(image_data->bitmap());
// Canvas fill_path(), stroke_path(), etc. implemented via painter-> methods

UI Front-End Rendering

Platform-specific UI layers obtain a Painter to composite the final frame. In UI/Qt/WebContentView.cpp, the Qt front-end allocates a Bitmap, wraps it with a Painter, and has LibWeb paint the page layout into it before handing the pixels to Qt for display. Similarly, UI/Android/src/main/cpp/WebViewImplementationNative.cpp uses the same pattern for Android surfaces.

System Theme and Color Management

The PageClient::setup_palette() method constructs a Gfx::PaletteImpl using LibGfx types, ensuring consistent color handling across the browser chrome and rendered web content.

Practical Usage Examples

The following examples demonstrate how LibGfx operates within the Ladybird codebase.

Creating a Bitmap, Drawing, and Exporting to PNG

This pattern from Libraries/LibGfx/ shows the complete workflow from allocation to file output:

// Allocate a 200×100 RGBA bitmap
auto bitmap = Gfx::Bitmap::create(Gfx::BitmapFormat::RGBA8888, Gfx::IntSize {200, 100}).release_value();

// Obtain a Painter for the bitmap (Skia backend by default)
auto painter = Gfx::Painter::create(*bitmap);

// Fill the whole bitmap with a light‑gray background
painter->fill_rect({0, 0, 200, 100}, Gfx::Color(0xd0d0d0ff));

// Draw a red rectangle with a 5‑pixel border
painter->fill_rect({20, 20, 160, 60}, Gfx::Color::Red);
painter->stroke_rect({20, 20, 160, 60}, Gfx::Color::Black, 5);

// Flush drawing commands (Skia does this automatically on destruction)
painter.clear();

// Encode the bitmap as PNG and write to disk
Gfx::PNGWriter writer;
writer.write_bitmap_to_file("example.png", *bitmap);

Rendering HTML5 Canvas Content

As implemented in Libraries/LibWeb/HTML/CanvasRenderingContext2D.cpp:

// Inside CanvasRenderingContext2D.cpp
auto painter = Gfx::Painter::create(image_data->bitmap());
// ... use painter->fill_path(), stroke_path(), etc. to implement the Canvas API

Compositing to a Native Qt Surface

From UI/Qt/WebContentView.cpp, simplified:

auto bitmap = Gfx::Bitmap::create(...);
auto painter = Gfx::Painter::create(bitmap);
// LibWeb paints the layout into the bitmap
page.paint(painter, ...);
// The bitmap is then handed to Qt for display

Key Implementation Files

Understanding LibGfx requires familiarity with these specific source files in the LadybirdBrowser/ladybird repository:

Summary

  • LibGfx provides the foundational Bitmap data model and Painter abstraction that every visual element in Ladybird requires.
  • The library's backend-agnostic design allows seamless switching between Skia (CPU), Vulkan, and Metal (GPU) rasterization without modifying high-level rendering code.
  • All image I/O operations pass through LibGfx's format-specific decoders in ImageFormats/, producing standard Bitmap objects for layout and painting.
  • Integration points in LibWeb, Qt, and Android front-ends demonstrate that LibGfx is the single source of truth for pixel-level operations across the entire browser architecture.

Frequently Asked Questions

What graphics backends does LibGfx support in Ladybird?

LibGfx currently supports three rasterization backends. The default implementation uses Skia (PainterSkia.cpp) for CPU-accelerated 2D drawing. When hardware acceleration is enabled, LibGfx can target Vulkan (VulkanContext.h/.cpp) on supported platforms or Metal (MetalContext.h/.mm) on macOS, all through the same abstract Painter interface.

How does LibGfx handle image loading for web pages?

When Ladybird encounters an image resource, the ImageDecoder service invokes LibGfx's format-specific loaders located in Libraries/LibGfx/ImageFormats/. These decoders handle PNG, JPEG, WebP, GIF, and TIFF formats, converting raw file bytes into Bitmap instances that the layout engine can composite onto the page using the standard Painter API.

Is LibGfx used only for web content rendering?

No. While LibGfx powers the LibWeb rendering pipeline for HTML and Canvas, it also handles all UI chrome rendering for Ladybird's native front-ends. Both the Qt (UI/Qt/WebContentView.cpp) and Android (UI/Android/src/main/cpp/WebViewImplementationNative.cpp) implementations use LibGfx to allocate bitmaps and obtain Painter instances for drawing the final composed frames displayed to users.

Can LibGfx be used independently of the Ladybird browser?

Yes. LibGfx is a standalone library within the Ladybird project (Libraries/LibGfx/) that depends only on lower-level system libraries and optional graphics backends like Skia. The code examples in this article demonstrate how to create bitmaps, draw primitives, and encode images using only LibGfx APIs without requiring the full web engine stack.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →