Added SDK

This commit is contained in:
Andrew Zambazos
2026-06-11 14:01:22 +12:00
commit c0395a49bd
2155 changed files with 451005 additions and 0 deletions
+106
View File
@@ -0,0 +1,106 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#ifndef ULTRALIGHT_ALLOCATOR_H
#define ULTRALIGHT_ALLOCATOR_H
#include <stddef.h>
#include <stdbool.h>
#include <Ultralight/Exports.h>
#ifdef __cplusplus
extern "C" {
#endif
///
/// User-defined allocator interface.
///
/// @pre This API is only available in the Pro edition when the UL_ENABLE_ALLOCATOR_OVERRIDE
/// build option is enabled.
///
/// The library uses this to allocate memory. You can override the default allocator functions
/// by setting the ulAllocator object with your own functions.
///
/// This should be done before calling any other library functions.
///
/// @see ulAllocator
///
typedef struct {
//
// Allocate a block of memory of at least |bytes| size.
//
void* (*malloc)(size_t bytes);
//
// Reallocate a block of memory to at least |bytes| size.
//
void* (*realloc)(void* address, size_t bytes);
//
// Free a block of memory allocated with malloc or realloc.
//
void (*free)(void* address);
//
// Allocate a block of memory of at least |bytes| size, aligned to |alignment|.
//
void* (*aligned_malloc)(size_t bytes, size_t alignment);
//
// Reallocate a block of memory to at least |bytes| size, aligned to |alignment|.
//
void* (*aligned_realloc)(void* address, size_t bytes, size_t alignment);
//
// Free a block of memory allocated with aligned_malloc or aligned_realloc.
//
void (*aligned_free)(void* address);
//
// Get the size of the memory block that backs the allocation at |address|. The memory
// block size is always at least as large as the allocation it backs, and may be larger.
// * Windows equivalent: _msize
// * POSIX equivalent: malloc_size
//
size_t (*get_size_estimate)(void* address);
} ULAllocator;
///
/// Get the allocator interface object for the library.
///
/// @pre This API is only available in the Pro edition when the UL_ENABLE_ALLOCATOR_OVERRIDE
/// build option is enabled.
///
/// The C functions set in this object will be used for allocating memory inside the library
/// when the `UL_ENABLE_ALLOCATOR_OVERRIDE` build option is enabled.
///
/// Default functions are already set for all of these but you can override them with your own.
///
/// Platform specific notes:
/// * __Windows__: The default functions use `HeapAlloc` / `HeapReAlloc` / `HeapFree`.
///
extern UCExport ULAllocator ulAllocator;
#ifdef _WIN32
///
/// Get the handle to the private heap used by the library.
///
/// This is the handle returned by `HeapCreate()`, you should destroy it after unloading the library
/// by calling `HeapDestroy()`.
///
/// This is only valid if the UL_ENABLE_ALLOCATOR_OVERRIDE build option is enabled and the default
/// functions are set in the ulAllocator object.
///
UCExport void* ulGetHeapHandle();
#endif
#ifdef __cplusplus
}
#endif
#endif // ULTRALIGHT_ALLOCATOR_H
+49
View File
@@ -0,0 +1,49 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
#include <Ultralight/String.h>
namespace ultralight {
///
/// User-defined clipboard interface.
///
/// The library uses this to read and write data to the system's clipboard.
///
/// AppCore automatically provides a platform-specific implementation of this that cuts, copies,
/// and pastes to the OS clipboard when you call App::Create().
///
/// If you are using Renderer::Create() instead of App::Create(), you will need to provide your own
/// implementation of this. @see Platform::set_clipboard().
///
class UExport Clipboard {
public:
virtual ~Clipboard();
///
/// Clear the clipboard.
///
virtual void Clear() = 0;
///
/// Read plain text from the clipboard
///
/// This is called when the library wants to read text from the OS clipboard.
///
virtual String ReadPlainText() = 0;
///
/// Write plain text to the clipboard.
///
/// This is called when the library wants to write text to the OS clipboard.
///
virtual void WritePlainText(const String& text) = 0;
};
} // namespace ultralight
+274
View File
@@ -0,0 +1,274 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2025 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
#include <Ultralight/String.h>
namespace ultralight {
///
/// The winding order for front-facing triangles. (Only used when the GPU renderer is used)
///
enum class FaceWinding : uint8_t {
///
/// Clockwise Winding (Direct3D, etc.)
///
Clockwise,
///
/// Counter-Clockwise Winding (OpenGL, etc.)
///
CounterClockwise,
};
enum class FontHinting : uint8_t {
///
/// Lighter hinting algorithm-- glyphs are slightly fuzzier but better resemble their original
/// shape. This is achieved by snapping glyphs to the pixel grid only vertically which better
/// preserves inter-glyph spacing.
///
Smooth,
///
/// Default hinting algorithm-- offers a good balance between sharpness and shape at smaller font
/// sizes.
///
Normal,
///
/// Strongest hinting algorithm-- outputs only black/white glyphs. The result is usually
/// unpleasant if the underlying TTF does not contain hints for this type of rendering.
///
Monochrome,
///
/// No hinting is performed-- fonts may be blurry at smaller font sizes.
///
None,
};
enum class EffectQuality : uint8_t {
///
/// Fastest effect quality-- uses the lowest quality effects (half-resolution, fewer passes, etc.)
///
Low,
///
/// Default effect quality-- strikes a good balance between quality and performance.
///
Medium,
///
/// Highest effect quality-- favors quality over performance.
///
High,
};
///
/// Core configuration for the renderer.
///
/// These are various configuration options that can be used to customize the behavior of the
/// library. These options can only be set once before creating the Renderer.
///
/// ## Setting the Config
///
/// You should create an instance of the Config struct, set its members, and then call
/// Platform::set_config() before creating the Renderer at the beginning of your
/// application's lifetime.
///
/// @par Example usage
/// ```
/// Config config;
/// config.user_stylesheet = "body { background: purple; }";
///
/// Platform::instance().set_config(config);
/// // (Setup other Platform interfaces here.)
///
/// auto renderer = Renderer::Create();
/// ```
///
struct UExport Config {
///
/// A writable OS file path to store persistent Session data in.
///
/// This data may include cookies, cached network resources, indexed DB, etc.
///
/// @note Files are only written to the path when using a persistent Session.
///
/// @see Renderer::CreateSession()
///
String cache_path;
///
/// The relative path to the resources folder (loaded via the FileSystem API).
///
/// The library loads certain resources (SSL certs, ICU data, etc.) from the FileSystem API
/// during runtime (eg, `file:///resources/cacert.pem`).
///
/// You can customize the relative file path to the resources folder by modifying this setting.
///
/// @see FileSystem
///
String resource_path_prefix = "resources/";
///
/// The winding order for front-facing triangles.
///
/// @pre Only used when GPU rendering is enabled for the View.
///
/// @see FaceWinding
///
FaceWinding face_winding = FaceWinding::CounterClockwise;
///
/// The hinting algorithm to use when rendering fonts.
///
/// @see FontHinting
///
FontHinting font_hinting = FontHinting::Normal;
///
/// The gamma to use when compositing font glyphs.
///
/// You can change this value to adjust font contrast (Adobe and Apple prefer 1.8).
///
double font_gamma = 1.8;
///
/// Global user-defined CSS string (included before any CSS on the page).
///
/// You can use this to override default styles for various elements on the page.
///
/// @note This is an actual string of CSS, not a file path.
///
String user_stylesheet;
///
/// Whether or not to continuously repaint any Views, regardless if they are dirty.
///
/// This is mainly used to diagnose painting/shader issues and profile performance.
///
bool force_repaint = false;
///
/// The delay (in seconds) between every tick of a CSS animation. (Default: 60 FPS)
///
double animation_timer_delay = 1.0 / 60.0;
///
/// The delay (in seconds) between every tick of a smooth scroll animation. (Default: 60 FPS)
///
double scroll_timer_delay = 1.0 / 60.0;
///
/// The delay (in seconds) between every call to the recycler.
///
/// The library attempts to reclaim excess memory during calls to the internal recycler. You can
/// change how often this is run by modifying this value.
///
double recycle_delay = 4.0;
///
/// The size of WebCore's memory cache in bytes.
///
/// @note You should increase this if you anticipate handling pages with large resources, Safari
/// typically uses 128+ MiB for its cache.
///
uint32_t memory_cache_size = 64 * 1024 * 1024;
///
/// The number of pages to keep in the cache. (Default: 0, none)
///
/// @note
/// \parblock
///
/// Safari typically caches about 5 pages and maintains an on-disk cache to support typical
/// web-browsing activities.
///
/// If you increase this, you should probably increase the memory cache size as well.
///
/// \endparblock
///
uint32_t page_cache_size = 0;
///
/// The system's physical RAM size in bytes.
///
/// JavaScriptCore tries to detect the system's physical RAM size to set reasonable allocation
/// limits. Set this to anything other than 0 to override the detected value. Size is in bytes.
///
/// This can be used to force JavaScriptCore to be more conservative with its allocation strategy
/// (at the cost of some performance).
///
uint32_t override_ram_size = 0;
///
/// The minimum size of large VM heaps in JavaScriptCore.
///
/// Set this to a lower value to make these heaps start with a smaller initial value.
///
uint32_t min_large_heap_size = 32 * 1024 * 1024;
///
/// The minimum size of small VM heaps in JavaScriptCore.
///
/// Set this to a lower value to make these heaps start with a smaller initial value.
///
uint32_t min_small_heap_size = 1 * 1024 * 1024;
///
/// The number of threads to use in the Renderer (for parallel painting on the CPU, etc.).
///
/// You can set this to a certain number to limit the number of threads to spawn.
///
/// @note
/// \parblock
///
/// If this value is 0, the number of threads will be determined at runtime using the following
/// formula:
///
/// ```
/// max(PhysicalProcessorCount() - 1, 1)
/// ```
///
/// \endparblock
///
uint32_t num_renderer_threads = 0;
///
/// The max amount of time (in seconds) to allow repeating timers to run during each call to
/// Renderer::Update.
///
/// The library will attempt to throttle timers if this time budget is exceeded.
///
double max_update_time = 1.0 / 200.0;
///
/// The alignment (in bytes) of the BitmapSurface when using the CPU renderer.
///
/// The underlying bitmap associated with each BitmapSurface will have row_bytes padded to reach
/// this alignment.
///
/// Aligning the bitmap helps improve performance when using the CPU renderer. Determining the
/// proper value to use depends on the CPU architecture and max SIMD instruction set used.
///
/// We generally target the 128-bit SSE2 instruction set across most PC platforms so '16' is
/// a safe value to use.
///
/// You can set this to '0' to perform no padding (row_bytes will always be width * 4) at a
/// slight cost to performance.
///
uint32_t bitmap_alignment = 16;
///
/// The quality of effects (blurs, CSS filters, SVG filters, etc.) to use when rendering.
///
EffectQuality effect_quality = EffectQuality::Medium;
};
} // namespace ultralight
+105
View File
@@ -0,0 +1,105 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
#include <Ultralight/String.h>
#include <Ultralight/Buffer.h>
namespace ultralight {
///
/// User-defined file system interface.
///
/// The library uses this to load file data (ie, raw file bytes) for a given file URL
/// (eg, `file:///page.html`) .
///
/// You can provide the library with your own FileSystem implementation so that file data is
/// provided directly by your application (eg, from memory, from a virtual file system, etc).
///
/// ## Default Implementation
///
/// A platform-specific implementation of FileSystem is provided for you when you call
/// App::Create().
///
/// If you are using Renderer::Create(), you **must** provide your own. You can still use AppCore's
/// implementation however-- see the helper functions defined in <AppCore/Platform.h>.
///
/// ## Setting the File System
///
/// To provide your own custom FileSystem implementation, you should inherit from this class,
/// handle the virtual member functions, and then pass an instance of your class to
/// Platform::set_file_system() before calling Renderer::Create() or App::Create().
///
class UExport FileSystem {
public:
virtual ~FileSystem();
///
/// Check if a file exists within the file system.
///
/// @param file_path Relative file path (the string following the file:/// prefix)
///
/// @return Returns whether or not a file exists at the path specified.
///
virtual bool FileExists(const String& file_path) = 0;
///
/// Get the mime-type of a file (eg "text/html").
///
/// This is usually determined by analyzing the file extension.
///
/// If a mime-type cannot be determined, this should return "application/unknown".
///
/// @param file_path Relative file path (the string following the file:/// prefix)
///
/// @return Returns whether or not a file exists at the path specified.
///
virtual String GetFileMimeType(const String& file_path) = 0;
///
/// Get the charset / encoding of a file (eg "utf-8", "iso-8859-1").
///
/// @note This is only applicable for text-based files (eg, "text/html", "text/plain") and is
/// usually determined by analyzing the contents of the file.
///
/// @param file_path Relative file path (the string following the file:/// prefix)
///
/// @return Returns the charset of the specified file. If a charset cannot be determined, a safe
/// default to return is "utf-8".
///
virtual String GetFileCharset(const String& file_path) = 0;
///
/// Open a file for reading and map it to a Buffer.
///
/// To minimize copies, you should map the requested file into memory and use Buffer::Create()
/// to wrap the data pointer (unmapping should be performed in the destruction callback).
///
/// @note
/// \parblock
/// File data addresses returned from this function should generally be aligned to 16-byte
/// boundaries (the default alignment on most operating systems-- if you're using C stdlib or
/// C++ STL functions this is already handled for you).
///
/// This requirement is currently necessary when loading the ICU data file (eg, icudt67l.dat),
/// and may be relaxed for other files (but you may still see a performance benefit due to cache
/// line alignment).
///
/// If you can't guarantee alignment or are unsure, you can use Buffer::CreateFromCopy to copy
/// the file data content to an aligned block (at the expense of data duplication).
/// \endparblock
///
/// @param file_path Relative file path (the string following the file:/// prefix)
///
/// @return If the file was able to be opened, this returns a Buffer object representing the
/// contents of the file. If the file was unable to be opened, you should return nullptr.
///
virtual RefPtr<Buffer> OpenFile(const String& file_path) = 0;
};
} // namespace ultralight
+129
View File
@@ -0,0 +1,129 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
#include <Ultralight/String.h>
#include <Ultralight/Buffer.h>
namespace ultralight {
///
/// Represents a font file, either on-disk path or in-memory file contents.
///
class UExport FontFile : public RefCounted {
public:
///
/// Create a font file from an on-disk file path.
///
/// @note The file path should already exist.
///
static RefPtr<FontFile> Create(const String& filepath);
///
/// Create a font file from an in-memory buffer.
///
static RefPtr<FontFile> Create(RefPtr<Buffer> buffer);
///
/// Whether or not this font file was created from an in-memory buffer.
///
virtual bool is_in_memory() const = 0;
///
/// The file path (if any).
///
virtual String filepath() const = 0;
///
/// The in-memory buffer (if any).
///
virtual RefPtr<Buffer> buffer() const = 0;
///
/// Unique hash (if this is a filepath, only the path string is hashed).
///
virtual uint32_t hash() const = 0;
protected:
FontFile();
virtual ~FontFile();
FontFile(const FontFile&);
void operator=(const FontFile&);
};
///
/// User-defined font loader interface.
///
/// The library uses this to load a font file (eg, `Arial.ttf`) for a given font description (eg,
/// `font-family: Arial;`).
///
/// Every OS has its own library of installed system fonts. The FontLoader interface is used to
/// lookup these fonts and fetch the actual font data (raw TTF/OTF file data) for a given font
/// description.
///
/// You can provide the library with your own font loader implementation so that you can bundle
/// fonts with your application rather than relying on the system's installed fonts.
///
/// ## Default Implementation
///
/// A platform-specific implementation of FontLoader is provided for you when you call
/// App::Create().
///
/// If you are using Renderer::Create(), you **must** provide your own. You can still use AppCore's
/// implementation however-- see the helper functions defined in <AppCore/Platform.h>.
///
/// ## Setting the Font Loader
///
/// To provide your own custom FontLoader implementation, you should inherit from this class,
/// handle the virtual member functions, and then pass an instance of your class to
/// Platform::set_font_loader() before calling Renderer::Create() or App::Create().
///
class UExport FontLoader {
public:
virtual ~FontLoader();
///
/// Fallback font family name. Will be used if all other fonts fail to load.
///
/// @note This font should be guaranteed to exist (eg, FontLoader::Load won't fail when passed
/// this font family name).
///
virtual String fallback_font() const = 0;
///
/// Fallback font family name that can render the specified characters. Mainly used to support
/// CJK (Chinese, Japanese, Korean) text display.
///
/// @param characters One or more UTF-16 characters. This is almost always a single character.
///
/// @param weight Font weight.
///
/// @param italic Whether or not italic is requested.
///
/// @return Returns a font family name that can render the text.
///
virtual String fallback_font_for_characters(const String& characters, int weight,
bool italic) const = 0;
///
/// Get the actual font file data (TTF/OTF) for a given font description.
///
/// @param family Font family name.
///
/// @param weight Font weight.
///
/// @param italic Whether or not italic is requested.
///
/// @return A font file matching the given description (either an on-disk font filepath or an
/// in-memory file contents). You can return NULL here and the loader will fallback to
/// another font.
///
virtual RefPtr<FontFile> Load(const String& family, int weight, bool italic) = 0;
};
} // namespace ultralight
+436
View File
@@ -0,0 +1,436 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
// clang-format off
#pragma once
#pragma warning(disable : 4251)
#include <Ultralight/Defines.h>
#include <Ultralight/Geometry.h>
#include <Ultralight/Matrix.h>
#include <Ultralight/Bitmap.h>
namespace ultralight {
/// \cond ignore
/// This pragma pack(push, 1) command is important!
/// GPU structs should not be padded with any bytes.
/// \endcond
#pragma pack(push, 1)
///
/// Render buffer description.
///
/// This structure describes a render buffer that can be used as a target for drawing commands.
///
/// @see GPUDriver::CreateRenderBuffer.
///
struct UExport RenderBuffer {
uint32_t texture_id; ///< The backing texture for this RenderBuffer
uint32_t width; ///< The width of the RenderBuffer texture
uint32_t height; ///< The height of the RenderBuffer texture
bool has_stencil_buffer; ///< Currently unused, always false.
bool has_depth_buffer; ///< Currently unsued, always false.
};
///
/// Vertex layout for path vertices.
///
/// This struct is the in-memory layout for each path vertex (useful for synthesizing or modifying
/// your own vertex data).
///
struct Vertex_2f_4ub_2f {
float pos[2];
unsigned char color[4];
float obj[2];
};
///
/// Vertex layout for quad vertices.
///
/// This struct is the in-memory layout for each quad vertex (useful for synthesizing or modifying
/// your own vertex data).
///
struct Vertex_2f_4ub_2f_2f_28f {
float pos[2];
unsigned char color[4];
float tex[2];
float obj[2];
float data0[4];
float data1[4];
float data2[4];
float data3[4];
float data4[4];
float data5[4];
float data6[4];
};
///
/// Vertex buffer formats.
///
/// This enumeration describes the format of a vertex buffer.
///
/// @note Identifiers start with an underscore due to C++ naming rules.
///
/// @see VertexBuffer
///
enum class VertexBufferFormat : uint8_t {
_2f_4ub_2f, ///< Vertex_2f_4ub_2f (used for path rendering)
_2f_4ub_2f_2f_28f, ///< Vertex_2f_4ub_2f_2f_28f (used for quad rendering)
};
///
/// Vertex buffer description.
///
/// @see GPUDriver::CreateGeometry
///
struct UExport VertexBuffer {
VertexBufferFormat format; ///< The format of the vertex buffer.
uint32_t size; ///< The size of the vertex buffer in bytes.
uint8_t* data; ///< The raw vertex buffer data.
};
///
/// Vertex index type.
///
typedef uint32_t IndexType;
///
/// Index buffer description.
///
/// This structure describes an index buffer that can be used to index into a vertex buffer.
///
/// @note The index buffer is a simple array of IndexType values.
///
/// @see GPUDriver::CreateGeometry
///
struct UExport IndexBuffer {
uint32_t size; ///< The size of the index buffer in bytes.
uint8_t* data; ///< The raw index buffer data.
};
///
/// Shader program types.
///
/// Each of these correspond to a vertex/pixel shader pair. You can find stock shader code for
/// these in the `shaders` folder of the AppCore repo.
///
/// @see GPUState::shader_type
///
enum class ShaderType : uint8_t {
Fill, ///< Shader program for filling quad geometry.
FillPath, ///< Shader program for filling tesselated path geometry.
};
///
/// The state of the GPU for a given draw command.
///
/// This structure describes the current state of the GPU for a given draw command.
///
/// @see Command::gpu_state
///
struct UExport GPUState {
/// Viewport width in pixels
uint32_t viewport_width;
/// Viewport height in pixels
uint32_t viewport_height;
/// Transform matrix-- you should multiply this with the screen-space orthographic projection
/// matrix then pass to the vertex shader.
Matrix4x4 transform;
/// Whether or not we should enable texturing for the current draw command.
bool enable_texturing;
/// Whether or not we should enable blending for the current draw command. If blending is
/// disabled, any drawn pixels should overwrite existing. This is mainly used so we can modify
/// alpha values of the RenderBuffer during scissored clears.
bool enable_blend;
/// The vertex/pixel shader program pair to use for the current draw command.
ShaderType shader_type;
/// The render buffer to use for the current draw command.
uint32_t render_buffer_id;
/// The texture id to bind to slot #1. (Will be 0 if none)
uint32_t texture_1_id;
/// The texture id to bind to slot #2. (Will be 0 if none)
uint32_t texture_2_id;
/// The texture id to bind to slot #3. (Will be 0 if none)
uint32_t texture_3_id;
/// The uniform scalars (passed to the pixel shader via uniforms).
float uniform_scalar[8];
/// The uniform vectors (passed to the pixel shader via uniforms).
vec4 uniform_vector[8];
/// The clip size (passed to the pixel shader via uniforms).
uint8_t clip_size;
/// The clip stack (passed to the pixel shader via uniforms).
Matrix4x4 clip[8];
/// Whether or not scissor testing should be used for the current draw command.
bool enable_scissor;
/// The scissor rect to use for scissor testing (units in pixels)
IntRect scissor_rect;
};
///
/// The types of commands.
///
/// This enumeration describes the type of command to execute on the GPU.
///
/// @see Command
///
enum class CommandType : uint8_t {
ClearRenderBuffer, ///< Clear the specified render buffer.
DrawGeometry, ///< Draw the specified geometry to the specified render buffer.
};
///
/// A command to execute on the GPU.
///
/// This structure describes a command to be executed on the GPU.
///
/// Commands are dispatched to the GPU driver asynchronously via GPUDriver::UpdateCommandList(),
/// the GPU driver should consume these commands and execute them at an appropriate time.
///
/// @see CommandList
///
struct UExport Command {
CommandType command_type; ///< The type of command to dispatch.
GPUState gpu_state; ///< The current GPU state.
uint32_t geometry_id; ///< The geometry ID to bind. (used with CommandType::DrawGeometry)
uint32_t indices_count; ///< The number of indices. (used with CommandType::DrawGeometry)
uint32_t indices_offset; ///< The index to start from. (used with CommandType::DrawGeometry)
};
///
/// List of commands to execute on the GPU.
///
/// @see GPUDriver::UpdateCommandList
///
struct UExport CommandList {
uint32_t size; ///< The number of commands in the list.
Command* commands; ///< The raw command list data.
};
#pragma pack(pop)
///
/// User-defined GPU driver interface.
///
/// The library uses this to optionally render Views on the GPU (see ViewConfig::is_accelerated).
///
/// You can provide the library with your own GPU driver implementation so that all rendering is
/// performed using an existing GPU context (useful for game engines).
///
/// When a View is rendered on the GPU, you can retrieve the backing texture ID via
/// View::render_target().
///
/// ## Default Implementation
///
/// A platform-specific implementation of GPUDriver is provided for you when you call App::Create(),
/// (currently D3D11, Metal, and OpenGL). We recommend using these classes as a starting point for
/// your own implementation (available open-source in the AppCore repository on GitHub).
///
/// ## Setting the GPU Driver
///
/// When using Renderer::Create(), you can provide your own implementation of this
/// class via Platform::set_gpu_driver().
///
/// ## State Synchronization
///
/// During each call to Renderer::Render(), the library will update the state of the GPU driver
/// (textures, render buffers, geometry, command lists, etc.) to match the current state of the
/// library.
///
/// ### Detecting State Changes
///
/// The library will call BeginSynchronize() before any state is updated and EndSynchronize() after
/// all state is updated. All `Create` / `Update` / `Destroy` calls will be made between these two
/// calls.
///
/// This allows the GPU driver implementation to prepare the GPU for any state changes.
///
/// ## Drawing
///
/// All drawing is done via command lists (UpdateCommandList()) to allow asynchronous execution
/// of commands on the GPU.
///
/// The library will dispatch a list of commands to the GPU driver during state synchronization. The
/// GPU driver implementation should periodically consume the command list and execute the commands
/// at an appropriate time.
///
/// @see Platform::set_gpu_driver()
///
class UExport GPUDriver {
public:
virtual ~GPUDriver();
///
/// Called before any state (eg, CreateTexture(), UpdateTexture(), DestroyTexture(), etc.) is
/// updated during a call to Renderer::Render().
///
/// This is a good time to prepare the GPU for any state updates.
///
virtual void BeginSynchronize() = 0;
///
/// Called after all state has been updated during a call to Renderer::Render().
///
virtual void EndSynchronize() = 0;
///
/// Get the next available texture ID.
///
/// This is used to generate a unique texture ID for each texture created by the library. The
/// GPU driver implementation is responsible for mapping these IDs to a native ID.
///
/// @note Numbering should start at 1, 0 is reserved for "no texture".
///
/// @return Returns the next available texture ID.
///
virtual uint32_t NextTextureId() = 0;
///
/// Create a texture with a certain ID and optional bitmap.
///
/// @param texture_id The texture ID to use for the new texture.
///
/// @param bitmap The bitmap to initialize the texture with (can be empty).
///
/// @note If the Bitmap is empty (Bitmap::IsEmpty), then a RTT Texture should be created instead.
/// This will be used as a backing texture for a new RenderBuffer.
///
/// @warning A deep copy of the bitmap data should be made if you are uploading it to the GPU
/// asynchronously, it will not persist beyond this call.
///
virtual void CreateTexture(uint32_t texture_id, RefPtr<Bitmap> bitmap) = 0;
///
/// Update an existing non-RTT texture with new bitmap data.
///
/// @param texture_id The texture to update.
///
/// @param bitmap The new bitmap data.
///
/// @warning A deep copy of the bitmap data should be made if you are uploading it to the GPU
/// asynchronously, it will not persist beyond this call.
///
virtual void UpdateTexture(uint32_t texture_id, RefPtr<Bitmap> bitmap) = 0;
///
/// Destroy a texture.
///
/// @param texture_id The texture to destroy.
///
virtual void DestroyTexture(uint32_t texture_id) = 0;
///
/// Get the next available render buffer ID.
///
/// This is used to generate a unique render buffer ID for each render buffer created by the
/// library. The GPU driver implementation is responsible for mapping these IDs to a native ID.
///
/// @note Numbering should start at 1, 0 is reserved for "no render buffer".
///
/// @return Returns the next available render buffer ID.
///
virtual uint32_t NextRenderBufferId() = 0;
///
/// Create a render buffer with certain ID and buffer description.
///
/// @param render_buffer_id The render buffer ID to use for the new render buffer.
///
/// @param buffer The render buffer description.
///
virtual void CreateRenderBuffer(uint32_t render_buffer_id, const RenderBuffer& buffer) = 0;
///
/// Destroy a render buffer.
///
/// @param render_buffer_id The render buffer to destroy.
///
virtual void DestroyRenderBuffer(uint32_t render_buffer_id) = 0;
///
/// Get the next available geometry ID.
///
/// This is used to generate a unique geometry ID for each geometry created by the library. The
/// GPU driver implementation is responsible for mapping these IDs to a native ID.
///
/// @note Numbering should start at 1, 0 is reserved for "no geometry".
///
/// @return Returns the next available geometry ID.
///
virtual uint32_t NextGeometryId() = 0;
///
/// Create geometry with certain ID and vertex/index data.
///
/// @param geometry_id The geometry ID to use for the new geometry.
///
/// @param vertices The vertex buffer data.
///
/// @param indices The index buffer data.
///
/// @warning A deep copy of the vertex/index data should be made if you are uploading it to the
/// GPU asynchronously, it will not persist beyond this call.
///
virtual void CreateGeometry(uint32_t geometry_id, const VertexBuffer& vertices,
const IndexBuffer& indices)
= 0;
///
/// Update existing geometry with new vertex/index data.
///
/// @param geometry_id The geometry to update.
///
/// @param vertices The new vertex buffer data.
///
/// @param indices The new index buffer data.
///
/// @warning A deep copy of the vertex/index data should be made if you are uploading it to the
/// GPU asynchronously, it will not persist beyond this call.
///
virtual void UpdateGeometry(uint32_t geometry_id, const VertexBuffer& vertices,
const IndexBuffer& indices)
= 0;
///
/// Destroy geometry.
///
/// @param geometry_id The geometry to destroy.
///
virtual void DestroyGeometry(uint32_t geometry_id) = 0;
///
/// Update the pending command list with commands to execute on the GPU.
///
/// Commands are dispatched to the GPU driver asynchronously via this method. The GPU driver
/// implementation should consume these commands and execute them at an appropriate time.
///
/// @param list The list of commands to execute.
///
/// @warning Implementations should make a deep copy of the command list, it will not persist
/// beyond this call.
///
virtual void UpdateCommandList(const CommandList& list) = 0;
};
} // namespace ultralight
// clang-format on
+42
View File
@@ -0,0 +1,42 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
#include <Ultralight/String.h>
namespace ultralight {
///
/// Log levels, used with Logger::LogMessage
///
enum class LogLevel : uint8_t {
Error,
Warning,
Info
};
///
/// User-defined logging interface.
///
/// The library uses this to display log messages for debugging during development.
///
/// This is intended to be implemented by users and defined before creating the Renderer.
///
/// @see Platform::set_logger()
///
class UExport Logger {
public:
virtual ~Logger();
///
/// Called when the library wants to display a log message.
///
virtual void LogMessage(LogLevel log_level, const String& message) = 0;
};
} // namespace ultralight
+182
View File
@@ -0,0 +1,182 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
namespace ultralight {
struct Config;
class Logger;
class GPUDriver;
class FontLoader;
class FileSystem;
class Clipboard;
class SurfaceFactory;
class ThreadFactory;
///
/// Global platform singleton, manages user-defined platform handlers and global config.
///
/// The library uses the Platform API for most platform-specific operations (eg, file access,
/// clipboard, font loading, GPU access, pixel buffer transport, etc.).
///
/// ## Motivation
///
/// Ultralight is designed to work in as many platforms and environments as possible. To achieve
/// this, we've factored out most platform-specific code into a set of interfaces that you can
/// implement and set on the Platform singleton.
///
/// ## Default Implementations
///
/// We provide a number of default implementations for desktop platforms (eg, Windows, macOS, Linux)
/// for you when you call App::Create(). These implementations are defined in the
/// [AppCore repository](https://github.com/ultralight-ux/AppCore/tree/master/src), we recommend
/// using their source code as a starting point for your own implementations.
///
/// ## Required Handlers
///
/// When using Renderer::Create() directly, you'll need to provide your own implementations for
/// FileSystem and FontLoader at a minimum.
///
/// @par Overview of which platform handlers are required / optional / provided:
///
/// | | Renderer::Create() | App::Create() |
/// |----------------|--------------------|---------------|
/// | FileSystem | **Required** | *Provided* |
/// | FontLoader | **Required** | *Provided* |
/// | Clipboard | *Optional* | *Provided* |
/// | GPUDriver | *Optional* | *Provided* |
/// | Logger | *Optional* | *Provided* |
/// | SurfaceFactory | *Provided* | *Provided* |
/// | ThreadFactory | *Optional* | *Optional* |
///
/// @note This singleton should be set up before creating the Renderer or App.
///
class UExport Platform {
public:
///
/// Get the Platform singleton
///
static Platform& instance();
virtual ~Platform();
///
/// Set the Config
///
virtual void set_config(const Config& config) = 0;
///
/// Get the Config
///
virtual const Config& config() const = 0;
///
/// Set the Logger (to handle error messages and debug output).
///
/// @param logger A user-defined Logger implementation, ownership remains with the caller.
///
virtual void set_logger(Logger* logger) = 0;
///
/// Get the Logger
///
virtual Logger* logger() const = 0;
///
/// Set the GPU Driver (will handle all rendering)
///
/// @param gpu_driver A user-defined GPUDriver implementation, ownership remains with the
/// caller.
///
virtual void set_gpu_driver(GPUDriver* gpu_driver) = 0;
///
/// Get the GPU Driver
///
virtual GPUDriver* gpu_driver() const = 0;
///
/// Set the Font Loader (will be used to map font families to actual fonts)
///
/// @param font_loader A user-defined FontLoader implementation, ownership remains with the
/// caller.
///
virtual void set_font_loader(FontLoader* font_loader) = 0;
///
/// Get the Font Loader
///
virtual FontLoader* font_loader() const = 0;
///
/// Set the File System (will be used for all file system operations)
///
/// @param file_system A user-defined FileSystem implementation, ownership remains with the
/// caller.
///
virtual void set_file_system(FileSystem* file_system) = 0;
///
/// Get the File System
///
virtual FileSystem* file_system() const = 0;
///
/// Set the Clipboard (will be used for all clipboard operations)
///
/// @param clipboard A user-defined Clipboard implementation, ownership remains with the
/// caller.
///
virtual void set_clipboard(Clipboard* clipboard) = 0;
///
/// Get the Clipboard
///
virtual Clipboard* clipboard() const = 0;
///
/// Set the SurfaceFactory
///
/// This can be used to provide a platform-specific bitmap surface for View to paint into when
/// the CPU renderer is enabled. See View::surface().
///
/// @param surface_factory A user-defined SurfaceFactory implementation, ownership remains with
/// the caller.
///
/// @note A default BitmapSurfaceFactory is defined if you never call this, View::surface() can
/// be safely cast to BitmapSurface.
///
virtual void set_surface_factory(SurfaceFactory* surface_factory) = 0;
///
/// Get the SurfaceFactory
///
/// @note A default BitmapSurfaceFactory is set by default, View::surface() can be safely cast
/// to BitmapSurface if you don't define your own.
///
virtual SurfaceFactory* surface_factory() const = 0;
///
/// Set the ThreadFactory
///
/// This can be used to provide a platform-specific ThreadFactory implementation for the library
/// to use when creating threads.
///
/// @param thread_factory A user-defined ThreadFactory implementation, ownership remains with the
/// caller.
///
virtual void set_thread_factory(ThreadFactory* thread_factory) = 0;
///
/// Get the ThreadFactory
///
virtual ThreadFactory* thread_factory() const = 0;
};
} // namespace ultralight
+204
View File
@@ -0,0 +1,204 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
#include <Ultralight/RefPtr.h>
#include <Ultralight/Bitmap.h>
#include <Ultralight/Geometry.h>
namespace ultralight {
///
/// User-defined pixel buffer surface.
///
/// The library uses this to store pixel data when rendering Views on the CPU (see
/// ViewConfig::is_accelerated).
///
/// You can provide the library with your own Surface implementation to reduce the latency of
/// displaying pixels in your application (Views will be drawn directly to a block of memory
/// controlled by you).
///
/// When a View is rendered on the CPU, you can retrieve the backing Surface via View::surface().
///
/// @pre This is automatically managed for you when using App::Create(), if you want to override
/// Surface or SurfaceFactory, you'll need to use Renderer::Create() instead.
///
/// ## Default Implementation
///
/// A default Surface implementation, BitmapSurface, is automatically provided by the library when
/// you call Renderer::Create() without defining a custom SurfaceFactory.
///
/// You should cast the Surface to a BitmapSurface to access the underlying Bitmap.
///
/// ## Setting the Surface Implementation
///
/// To define your own implementation, you should inherit from this class, handle the virtual
/// member functions, and then define a custom SurfaceFactory that creates/destroys an
/// instance of your class.
///
/// After that, you should pass an instance of your custom SurfaceFactory class to
/// Platform::set_surface_factory() before calling Renderer::Create().
///
class UExport Surface {
public:
virtual ~Surface();
///
/// Width (in pixels).
///
virtual uint32_t width() const = 0;
///
/// Height (in pixels).
///
virtual uint32_t height() const = 0;
///
/// Number of bytes between rows (usually width * 4)
///
virtual uint32_t row_bytes() const = 0;
///
/// Size in bytes.
///
virtual size_t size() const = 0;
///
/// Lock the pixel buffer and get a pointer to the beginning of the data for reading/writing.
///
/// @note Native pixel format is premultiplied BGRA 32-bit (8 bits per channel).
///
virtual void* LockPixels() = 0;
///
/// Unlock the pixel buffer.
///
virtual void UnlockPixels() = 0;
///
/// Resize the pixel buffer to a certain width and height (both in pixels).
///
/// This should never be called while pixels are locked.
///
virtual void Resize(uint32_t width, uint32_t height) = 0;
///
/// Set the dirty bounds to a certain value.
///
/// This is called after the Renderer paints to an area of the pixel buffer. (The new value will
/// be joined with the existing dirty_bounds())
///
virtual void set_dirty_bounds(const IntRect& bounds);
///
/// Get the dirty bounds.
///
/// This value can be used to determine which portion of the pixel buffer has been updated since
/// the last call to ClearDirtyBounds().
///
/// The general algorithm to determine if a Surface needs display is:
/// <pre>
/// if (!surface.dirty_bounds().IsEmpty()) {
/// // Surface pixels are dirty and needs display.
/// // Cast Surface to native Surface and use it here (pseudo code)
/// DisplaySurface(surface);
///
/// // Once you're done, clear the dirty bounds:
/// surface.ClearDirtyBounds();
/// }
/// </pre>
///
virtual IntRect dirty_bounds() const;
///
/// Clear the dirty bounds.
///
/// You should call this after you're done displaying the Surface.
///
virtual void ClearDirtyBounds();
protected:
Surface();
IntRect dirty_bounds_;
};
///
/// User-defined factory to provide your own surface implementation.
///
/// The library uses this to create/destroy Surface instances when rendering Views on the CPU.
///
/// @pre This is automatically managed for you when using App::Create(), if you want to override
/// Surface or SurfaceFactory, you'll need to use Renderer::Create() instead.
///
/// ## Setting the Surface Factory
///
/// The default factory creates/destroys a BitmapSurface but you can override this by providing your
/// own factory to Platform::set_surface_factory().
///
class UExport SurfaceFactory {
public:
virtual ~SurfaceFactory();
///
/// Create a native Surface with a certain width and height (in pixels).
///
virtual Surface* CreateSurface(uint32_t width, uint32_t height) = 0;
///
/// Destroy a native Surface previously created by CreateSurface().
///
virtual void DestroySurface(Surface* surface) = 0;
};
///
/// The default surface implementation, backed by a bitmap.
///
/// This is automatically provided by the library when you call Renderer::Create() without defining
/// a custom SurfaceFactory.
///
/// This implementation uses a Bitmap to store pixel data (retrieve it via BitmapSurface::bitmap()).
///
class UExport BitmapSurface : public Surface {
public:
virtual uint32_t width() const override;
virtual uint32_t height() const override;
virtual uint32_t row_bytes() const override;
virtual size_t size() const override;
virtual void* LockPixels() override;
virtual void UnlockPixels() override;
virtual void Resize(uint32_t width, uint32_t height) override;
///
/// Get the underlying Bitmap.
///
RefPtr<Bitmap> bitmap();
protected:
BitmapSurface(uint32_t width, uint32_t height);
virtual ~BitmapSurface();
BitmapSurface(const BitmapSurface&) = delete;
void operator=(const BitmapSurface&) = delete;
friend class BitmapSurfaceFactory;
void* impl_;
};
///
/// Get the default Bitmap Surface Factory singleton. (Do not destroy this, this singleton is owned
/// by the library).
///
UExport SurfaceFactory* GetBitmapSurfaceFactory();
} // namespace ultralight
+93
View File
@@ -0,0 +1,93 @@
/**************************************************************************************************
* This file is a part of Ultralight. *
* *
* See <https://ultralig.ht> for licensing and more. *
* *
* (C) 2024 Ultralight, Inc. *
**************************************************************************************************/
#pragma once
#include <Ultralight/Defines.h>
namespace ultralight {
///
/// Unique id of the thread, used for referencing the created thread later.
/// * on Windows this should match the thread identifier returned by either _beginthreadex()
/// or GetCurrentThreadId()
/// * on POSIX this can be whatever unique id you want
///
typedef uint32_t ThreadId;
///
/// Platform-specific handle
/// * on Windows this is HANDLE
/// * on POSIX this is pthread_t
///
typedef uint64_t ThreadHandle;
///
/// Entry point for the thread, this function should be called by the thread once it is active
/// and should be passed entry_point_data as the argument.
///
typedef void (*ThreadEntryPoint)(void*);
///
/// The type of thread, you can choose to optionally handle these for better performance.
///
enum class ThreadType : uint8_t {
Unknown = 0,
JavaScript,
Compiler,
GarbageCollection,
Network,
Graphics,
Audio,
};
///
/// Result of creating a new thread.
///
/// This struct is used to return the id and handle of the created thread.
///
struct UExport CreateThreadResult {
ThreadId id; ///< The unique id of the thread. @see ThreadId
ThreadHandle handle; ///< The platform-specific handle of the thread. @see ThreadHandle
};
///
/// User-defined factory for creating new threads.
///
/// You can implement this interface so that the library will use your own implementation for
/// creating threads (useful for tracking thread creation, setting thread names, etc).
///
/// ## Default Implementation
///
/// When no factory is defined, the library will create threads using the default platform-specific
/// thread creation functions (eg, `_beginthreadex()` on Windows, `pthread_create()` on POSIX).
///
/// ## Setting the Thread Factory
///
/// To provide your own custom ThreadFactory implementation, you should inherit from this class,
/// handle the virtual member functions, and then pass an instance to
/// Platform::set_thread_factory().
///
class UExport ThreadFactory {
public:
virtual ~ThreadFactory() = default;
///
/// Create a new thread.
///
/// @param name The name of the thread (can be nullptr).
/// @param type The type of thread.
/// @param entry_point The entry point for the thread.
/// @param entry_point_data The data to pass to the entry point.
/// @param result The resulting id and handle of the thread creation.
///
/// @return Returns whether or not the thread was created successfully.
///
virtual bool CreateThread(const char* name, ThreadType type, ThreadEntryPoint entry_point,
void* entry_point_data, CreateThreadResult& result) = 0;
};
} // namespace ultralight