Skip to content

Paint and render scene API

Declared by <huxerui/paint.h> and <huxerui/render_scene.h>.

  • ImageFit: None, Contain, Cover, Fill, or ScaleDown.
  • GradientStop, LinearGradient, and RadialGradient.
  • ImageVariant: ImageResource, ImageAsset, or VectorAsset.
  • ImageFill: source, fit, alignment, sampling, tint, and opacity.
  • Brush: immutable color, linear-gradient, or radial-gradient source paint. VisualFill combines Brush and ImageFill, also accepting colors, gradients, ImageResource, ImageAsset, and VectorAsset directly.

PaintCommand is a variant of:

  • DrawRectCommand carrying a Brush, and DrawLineCommand carrying stroke geometry.
  • DrawTextCommand, TextRun, DrawTextRunsCommand.
  • DrawImageCommand, DrawExternalTextureCommand.
  • DrawCircleCommand, DrawArcCommand, DrawBorderCommand, DrawShadowCommand.
  • FillPathCommand, StrokePathCommand, DrawPathShadowCommand.
  • PushClipCommand, PopClipCommand, PushPathClipCommand.
  • PushTransformCommand, PopTransformCommand.
  • PlacePlatformViewCommand, whose queries expose identity, type, properties/revision, and bounds.

Each command is immutable platform-neutral data with equality. Command fields correspond to the matching PaintContext parameters.

PaintSequence exposes Commands, conservative Bounds, Revision, and whether it contains external textures. PaintContext(sequence, bounds) records drawing through DrawRect, gradient, text/text-runs, image/image-rect, external texture, circle, arc, border, rect/path shadow, fill/stroke path, clip, and transform methods. Bounds() returns local recording bounds; Finish() validates balanced stacks and closes recording.

  • RenderClip: rectangular or path clip command.
  • RenderNode: stable ID, parent-local offset, presentation transform, group opacity, descendant clips, child transform, content/foreground sequences, child pointers, visibility, and revision.
  • RenderScene: non-owning root pointer.
  • DamageRegion: full flag or dirty rectangles.
  • RenderFrame: scene, damage, and revision.
  • FrameCommit: render frame, immutable semantic frame, and optional absolute next-frame deadline.

The scene/frame types are the platform renderer boundary. Their non-owning pointers remain valid only until the next runtime frame construction or destruction.

#include <huxerui/huxerui.h>
using namespace huxerui;
View StatusCanvas() {
return Canvas([](PaintContext& paint, Size size) {
const Point center {size.width / 2.0F, size.height / 2.0F};
paint.DrawCircle(center, 36.0F, Color::Rgb(92, 61, 180));
paint.DrawArc(center, 28.0F, -1.57F, 4.2F, Color::Rgb(255, 255, 255), StrokeStyle{.width = 6.0F});
}).With(Frame {.width = 160.0F, .height = 160.0F});
}

The painter receives local size and emits platform-neutral commands. It does not own a platform canvas or world-coordinate transform.

A Brush contains Color, LinearGradient, or RadialGradient. A VisualFill additionally permits image-backed surfaces; it is used by Background and component styles. Do not pass an ImageFill to a Brush-only path operation and assume the renderer will resolve a resource there. Resolve an image during composition when drawing it explicitly with PaintContext.

Gradient stops require at least two ordered offsets in [0, 1]; equal offsets intentionally create a hard transition. LinearGradient’s start/end and RadialGradient’s center/radius use normalized destination coordinates. Radial radii must be positive. Their transform changes sampling coordinates, not the geometry being painted. Use PushTransform when the shape itself must move or rotate.

ImageFill contains source, fit, horizontal_alignment, vertical_alignment, sampling, optional tint, and opacity in [0, 1]. Fit defaults to Fill. Vector tint and raster sampling have source-specific rules; see Image.

Operations Inputs and important distinction
DrawRect Rect, Brush, and optional CornerRadii. A Color/gradient converts to Brush.
DrawText Rect, string or AttributedText, TextStyle, TextLayoutOptions, optional paragraph offset.
DrawTextRun / DrawTextRuns Explicit run bounds and baseline origins; use when the caller already owns run positioning.
DrawImage Whole ImageAsset, VectorAsset, or shared ExternalTexture into a destination rectangle.
DrawImageRect A source subrectangle into a destination; source coordinates are intrinsic logical units, not encoded pixel coordinates.
DrawCircle, DrawLine, DrawArc Color-based primitives; line/arc take StrokeStyle, arc angles are radians.
DrawBorder / DrawShadow Rectangular border or shadow geometry; shadow offset, blur, and spread are separate values.
FillPath / StrokePath Path plus Brush and fill rule or stroke style; optional explicit brush bounds decouple gradient mapping from path bounds.
DrawPathShadow A path silhouette rather than a rectangular shadow.
PushClip / PushPathClip Intersect the recording clip with a rounded rectangle or path.
PushTransform Compose an affine transform for subsequent commands.

Raster/texture image overloads accept ImageSampling and opacity; vector overloads accept optional tint and opacity. Drawing an image rectangle does not apply ImageFit automatically: the caller already chose source/destination geometry.

Inside a Canvas callback, use the supplied context and balance every push with its corresponding pop. Runtime owns finishing that recording. When an extension/integration explicitly constructs PaintContext(sequence, bounds), it owns one recording and must call Finish once; Finish validates balanced stacks and closes the context. Its bounds do not implicitly clip drawing.

Do not retain a PaintContext beyond the callback, append to a finished one, or mutate resources referenced by immutable commands behind the renderer’s back. PaintSequence’s bounds are conservative damage information, not a per-pixel hit mask. For input, use the View’s geometry and semantics rather than interpreting a sequence as an interactive scene graph.

RenderScene, RenderNode, RenderFrame, and FrameCommit are integration contracts, not values an application edits to move a component. Their borrowed pointers cannot be cached across Runtime frame construction. A renderer must handle every command variant, preserve clipping/transform balance, and respect group opacity and child ordering. Adding a PaintCommand therefore requires every renderer to implement it; ordinary application custom drawing should stay with Canvas, paths, and existing commands.