This page covers the implementation of web platform APIs in Ladybird, focusing on four major areas: WebGL (3D graphics), Web Crypto (cryptographic operations), IndexedDB (client-side storage), and media playback (LibMedia). These APIs demonstrate the binding layer architecture and implementation patterns used throughout Ladybird's web platform support. Detailed coverage of each area is in sub-pages 6.1 through 6.4.
For information about WebIDL binding generation, see WebIDL Bindings System.
Web platform APIs in Ladybird follow a three-layer architecture: IDL definitions specify the JavaScript interface, generated bindings handle type conversions and lifecycle management, and C++ implementation classes provide the actual functionality.
Web Platform APIs: Class and Layer Mapping
Sources:
WebIDL files define the JavaScript-visible API surface. The IDL code generator produces C++ bindings that handle type conversions, parameter validation, and method dispatch.
Key WebIDL Bindings
| Interface | IDL File | Implementation Class |
|---|---|---|
WebGLRenderingContext | WebGLRenderingContextBase.idl | WebGLRenderingContextImpl |
WebGL2RenderingContext | WebGL2RenderingContextBase.idl | WebGL2RenderingContextImpl |
SubtleCrypto | SubtleCrypto.idl | SubtleCrypto |
IDBObjectStore | IDBObjectStore.idl | IDBObjectStore |
IDBIndex | IDBIndex.idl | IDBIndex |
The binding generator handles:
Sources:
WebGL provides JavaScript access to OpenGL ES for hardware-accelerated 3D graphics. Ladybird implements both WebGL 1.0 and WebGL 2.0 contexts.
WebGL Context Class Hierarchy
WebGL contexts are created through HTMLCanvasElement.getContext(). The context manages OpenGL state and delegates OpenGL calls through OpenGLContext.
Key Implementation Classes:
WebGLRenderingContextImpl - Implements WebGL 1.0 API methods, maps to OpenGL ES 2.0WebGL2RenderingContextImpl - Extends with WebGL 2.0 API methods, maps to OpenGL ES 3.0OpenGLContext - Manages the underlying OpenGL/ANGLE context and framebufferWebGL resources like buffers, textures, and shaders are represented by WebGLObject subclasses:
| Class | Purpose | OpenGL Handle |
|---|---|---|
WebGLBuffer | Vertex/index buffers | GLuint buffer |
WebGLTexture | Textures and samplers | GLuint texture |
WebGLProgram | Shader programs | GLuint program |
WebGLShader | Vertex/fragment shaders | GLuint shader |
WebGLFramebuffer | Render targets | GLuint framebuffer |
WebGLRenderbuffer | Render buffers | GLuint renderbuffer |
Each WebGLObject tracks its OpenGL handle and validates that operations occur on the correct context.
WebGLRenderingContextImpl maintains the current WebGL binding state as GC::Ptr members: buffer bindings (m_array_buffer_binding, m_element_array_buffer_binding, plus WebGL 2 bindings for pixel pack/unpack, uniform buffer, and transform feedback buffers), texture bindings (m_texture_2d_binding, m_texture_cube_map_binding), framebuffer (m_framebuffer_binding), and renderbuffer (m_renderbuffer_binding). State changes are validated against WebGL rules before forwarding to OpenGL. For example, bind_buffer() checks buffer compatibility with the target binding point before calling glBindBuffer, and bind_framebuffer() substitutes the context's default framebuffer handle when null is passed.
Sources:
WebGL 2.0 adds features like:
tex_image3d() and tex_sub_image3d()draw_arrays_instanced() and draw_elements_instanced()Sources:
The Web Crypto API provides cryptographic operations to web applications through the SubtleCrypto interface. Operations are asynchronous and return Promises.
SubtleCrypto Operations Flow
SubtleCrypto delegates to algorithm-specific classes in CryptoAlgorithms.cpp:
| Algorithm | Class | Operations |
|---|---|---|
| RSA-OAEP | RSAOAEP | encrypt, decrypt, generateKey, importKey, exportKey |
| RSA-PSS | RSAPSS | sign, verify, generateKey, importKey, exportKey |
| RSA-PKCS1 | RSASSAPKCS1 | sign, verify, generateKey, importKey, exportKey |
| AES-CBC | AesCbc | encrypt, decrypt, generateKey, importKey, exportKey |
| AES-GCM | AesGcm | encrypt, decrypt, generateKey, importKey, exportKey |
| AES-CTR | AesCtr | encrypt, decrypt, generateKey, importKey, exportKey |
| ECDSA | ECDSA | sign, verify, generateKey, importKey, exportKey |
| ECDH | ECDH | deriveBits, generateKey, importKey, exportKey |
| HMAC | HMAC | sign, verify, generateKey, importKey, exportKey |
| HKDF | HKDF | deriveBits, importKey |
| PBKDF2 | PBKDF2 | deriveBits, importKey |
Each algorithm class inherits from AlgorithmMethods and implements the relevant operations.
normalize_an_algorithm() in Libraries/LibWeb/Crypto/SubtleCrypto.cpp66-134 takes an AlgorithmIdentifier (string or object) and an operation name, returning a NormalizedAlgorithmAndParameter struct that bundles a NonnullOwnPtr<AlgorithmMethods> with a NonnullOwnPtr<AlgorithmParams>. The function looks up the algorithm name (case-insensitively) in the supported_algorithms() map — keyed first by operation name, then by algorithm name — and calls the matched algorithm's parameter_from_value() factory to produce the typed parameter from the JavaScript object.
Algorithm-specific parameters extend AlgorithmParams Libraries/LibWeb/Crypto/CryptoAlgorithms.h62-73 Each struct holds algorithm-specific fields and a static from_value() factory that extracts those fields from the JavaScript parameter object passed to the API method. Representative parameter types include:
| Struct | Key Fields |
|---|---|
RsaOaepParams | label (ByteBuffer) |
AesGcmParams | iv, optional additional_data, optional tag_length |
AesCtrParams | counter, length |
EcdsaParams | hash (HashAlgorithmIdentifier) |
HKDFParams | hash, salt, info |
PBKDF2Params | salt, iterations, hash |
The full set of parameter structs is defined in Libraries/LibWeb/Crypto/CryptoAlgorithms.h76-420
All cryptographic operations follow this pattern:
The encrypt() method in Libraries/LibWeb/Crypto/SubtleCrypto.cpp136-191 demonstrates the full pattern: after normalization and promise creation, Platform::EventLoopPlugin::the().deferred_invoke() queues a lambda that establishes a TemporaryExecutionContext, calls normalized_algorithm.methods->encrypt(), then calls WebIDL::resolve_promise() on success or WebIDL::reject_promise() on error.
Keys are imported from various formats:
The parse_a_subject_public_key_info() and parse_a_private_key_info() functions use LibCrypto::ASN1::Decoder to parse DER-encoded keys.
JWK import uses base64_url_uint_decode() to decode Base64url-encoded BigInteger parameters.
Sources:
IndexedDB provides a transactional database system for storing structured data in the browser. The implementation follows the IndexedDB specification's complex asynchronous operation model.
IndexedDB Architecture
Opening a database involves version negotiation and potential upgrade:
open_a_database_connection() queues request on connection queueversionchange events on existing connectionsupgrade_a_database() with upgrade transactionupgradeneeded event on requestsuccess event; on abort, fire error eventThe connection queue ensures serialized access per storage key and database name. open_a_database_connection() in Libraries/LibWeb/IndexedDB/Internal/Algorithms.cpp79-232 uses ConnectionQueueHandler::for_key_and_name() to obtain the per-(storageKey, name) queue, appends the request, then calls queue.all_previous_requests_processed() with a callback containing the full version negotiation and upgrade logic.
Transactions have four states: Inactive, Active, Committing, Finished.
Transaction State Machine
Upgrade transactions are special - they must complete before the database version changes:
Object stores support CRUD operations and cursor-based iteration:
Put/Add Operation:
Get Operation:
Key paths specify how to extract keys from stored values:
Key paths can be:
"name""person.address.city"["firstName", "lastName"]Cursors provide sequential access to records:
Cursor directions: next, nextunique, prev, prevunique.
All IndexedDB operations are asynchronous and use IDBRequest:
Keys have a total ordering: number < date < string < binary < array.
Sources:
Web platform APIs share several implementation patterns that enable consistent behavior across different API surfaces.
Asynchronous operations return Promises and execute on the event loop:
This pattern:
deferred_invoke()TemporaryExecutionContext for callbackMany APIs accept BufferSource (ArrayBuffer, TypedArray, or DataView):
The get_buffer_source_copy() function handles all three buffer types uniformly.
Operations can throw WebIDL-defined exceptions:
Common exception types: DataError, InvalidAccessError, NotSupportedError, OperationError, QuotaExceededError, SyntaxError, TypeError.
All web platform objects integrate with LibJS garbage collection:
The visit_edges() method ensures all GC-managed references are traced.
Web APIs dispatch events using the DOM event system:
Events can bubble, be cancelable, and have custom initialization parameters.
Sources:
The IDL code generation system is a crucial part of the Web API implementation. It automates the creation of the binding code between JavaScript and C++.
The process works as follows:
The code generator supports various WebIDL features including:
Sources:
Web APIs in Ladybird are organized into logical namespaces that reflect their functionality:
Sources:
The Web APIs system in Ladybird provides a comprehensive implementation of standard web interfaces through a robust IDL-based binding generation approach. This system allows for efficient mapping between JavaScript and C++ while maintaining compatibility with web standards.
The modular architecture enables continued expansion of supported APIs and facilitates maintenance through automated code generation from IDL definitions.
Refresh this wiki