Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
pulp::canvas::Canvas Class Referenceabstract

#include <canvas.hpp>

Classes

struct  AffineTransform2x3
 Affine 2x3 transform snapshot, six floats laid out as CanvasRenderingContext2D.setTransform / DOMMatrix: [ a c e ] [ b d f ] [ 0 0 1 ] Identity is {1, 0, 0, 1, 0, 0}. More...
struct  LayerHandle
 An opaque reference to a compositing layer owned by the canvas. More...
struct  FilterChainEntry
 Full CSS filter-chain layer save. More...
struct  FontFeature
struct  TextMetrics
 Full text metrics for layout and intrinsic sizing. More...
struct  SDFStyle
struct  WaveformStyle
 Draw a waveform using GPU shader (SDF anti-aliased line + fill). More...
struct  ShaderUniforms
 Uniforms passed to custom widget shaders. More...
struct  NamedUniform
 An arbitrary named shader uniform (name → float / vec2 / vec3 / vec4). More...
struct  ShaderDataTexture
 Latest-wins audio/vector payload exposed to an SkSL child shader. More...
struct  ShaderGeometry
struct  ShaderDrawOptions
struct  FitResult
 Placement rectangle produced by fit_image_rect. More...

Public Types

enum class  ImageSmoothingQuality { low , medium , high }
 Canvas2D image-smoothing quality enum. More...
enum class  PatternTileMode { repeat , no_repeat }
 Canvas2D ctx.createPattern. More...
enum class  BlendMode {
  normal = 0 , multiply , screen , overlay ,
  darken , lighten , color_dodge , color_burn ,
  hard_light , soft_light , difference , exclusion ,
  hue , saturation , color , luminosity ,
  source_over , destination_over , source_in , destination_in ,
  source_out , destination_out , source_atop , destination_atop ,
  xor_mode , copy , lighter
}
 Indices 0..15 match the existing W3C "advanced" composite ops and must stay stable — set_blend_mode in the JS bridge currently passes int_val 1/2/3 = multiply/screen/overlay. More...
enum class  TextAnchor { Baseline , GlyphTop , GlyphCenter , EmBoxTop }
 Explicit, typed vertical-anchor API. More...
enum class  SDFShape {
  rect , circle , rounded_rect , arc ,
  diamond , squircle , triangle , ring ,
  stadium , cross , flat_segment , rounded_segment ,
  flat_arc , quadratic_bezier
}
 Draw an SDF shape with anti-aliased edges via GPU shader. More...
enum class  TextDirection { ltr , rtl , inherit }
 Canvas2D ctx.direction. More...
enum class  ImageFit {
  fill , contain , cover , none ,
  scale_down
}
 Preserve-aspect fit modes for fit_image_rect / draw_image_fitted: fill — stretch to the destination box, ignoring aspect ratio. More...
using Point2D = pulp::canvas::Point2D
 Stroke a continuous polyline through an array of points.

Public Member Functions

virtual ~Canvas ()=default
virtual RendererBackend renderer_backend () const noexcept
 Identity of the renderer this canvas actually wraps.
virtual float backing_scale () const noexcept
 Effective device pixels per local canvas unit at the current transform.
virtual void save ()=0
virtual void restore ()=0
virtual int save_count () const
 Return the current save-stack depth.
virtual void restore_to_count (int target)
 Pop the save stack down to target (typically captured earlier via save_count()).
virtual void translate (float x, float y)=0
virtual void scale (float sx, float sy)=0
virtual void rotate (float radians)=0
virtual void set_transform (float a, float b, float c, float d, float e, float f)
 Replace the current transform with the affine matrix [ a c e ] [ b d f ] [ 0 0 1 ] Mirrors CanvasRenderingContext2D.setTransform(a, b, c, d, e, f).
virtual void capture_paint_baseline_transform ()
 Snapshot the current device matrix as the baseline for subsequent set_transform() calls.
virtual void concat_transform (float a, float b, float c, float d, float e, float f)
 Concat (multiply) the supplied affine matrix onto the current transform — does NOT replace it.
virtual AffineTransform2x3 current_transform () const
 Snapshot the current device matrix (CTM) without mutating canvas state.
virtual void clip_rect (float x, float y, float w, float h)=0
virtual void clip (FillRule rule=FillRule::nonzero)
 Intersect the current clip region with the current path.
virtual void clip_path_svg (const std::string &svg_path_d)
 CSS clip-path: path("...") — intersect the current clip with an SVG-path-d string.
virtual void set_fill_color (Color c)=0
virtual void set_stroke_color (Color c)=0
virtual void set_line_width (float w)=0
virtual void set_line_cap (LineCap cap)=0
virtual void set_line_join (LineJoin join)=0
virtual void set_miter_limit (float limit)
 Canvas2D ctx.miterLimit.
virtual void set_image_smoothing (bool enabled, ImageSmoothingQuality quality=ImageSmoothingQuality::low)
 Canvas2D ctx.imageSmoothingEnabled + imageSmoothingQuality.
virtual void set_fill_gradient_linear (float x0, float y0, float x1, float y1, const Color *colors, const float *positions, int count)
 Set a linear gradient as the fill paint.
virtual void set_fill_gradient_radial (float cx, float cy, float radius, const Color *colors, const float *positions, int count)
 Set a radial gradient as the fill paint.
virtual void set_fill_gradient_radial_elliptical (float cx, float cy, float rx, float ry, const Color *colors, const float *positions, int count)
 Radial gradient with an independent radius per axis — the ending shape CSS calls an ellipse, which is radial-gradient's DEFAULT shape and the only one a two-value size (90% 70%) can express.
virtual void set_fill_gradient_radial_two_circles (float x0, float y0, float r0, float x1, float y1, float r1, const Color *colors, const float *positions, int count)
 Canvas2D ctx.createRadialGradient(x0,y0,r0,x1,y1,r1) two-circle form.
virtual void set_fill_gradient_conic (float cx, float cy, float start_angle, const Color *colors, const float *positions, int count)
 Set a conic (sweep) gradient as the fill paint.
virtual void clear_fill_gradient ()
 Clear gradient, return to solid fill color.
virtual void set_stroke_gradient_linear (float x0, float y0, float x1, float y1, const Color *colors, const float *positions, int count)
virtual void set_stroke_gradient_radial (float cx, float cy, float radius, const Color *colors, const float *positions, int count)
virtual void set_stroke_gradient_radial_two_circles (float x0, float y0, float r0, float x1, float y1, float r1, const Color *colors, const float *positions, int count)
 Two-circle radial gradient on stroke (mirrors fill counterpart).
virtual void set_stroke_gradient_conic (float cx, float cy, float start_angle, const Color *colors, const float *positions, int count)
virtual void clear_stroke_gradient ()
 Clear stroke gradient/pattern shader, restore solid stroke color.
virtual void set_fill_pattern (const std::string &image_src, PatternTileMode tile_x, PatternTileMode tile_y)
 Set an image pattern as the fill paint.
virtual void set_stroke_pattern (const std::string &image_src, PatternTileMode tile_x, PatternTileMode tile_y)
 Stroke counterpart.
virtual void set_blend_mode (BlendMode mode)
 Set the compositing blend mode for subsequent draw operations.
virtual void begin_path ()
 Begin a new path.
virtual void move_to (float x, float y)
 Move the pen to (x, y) without drawing.
virtual void line_to (float x, float y)
 Add a line segment to (x, y).
virtual void quad_to (float cpx, float cpy, float x, float y)
 Add a quadratic bezier curve to (x, y) with control point (cpx, cpy).
virtual void cubic_to (float cp1x, float cp1y, float cp2x, float cp2y, float x, float y)
 Add a cubic bezier curve.
virtual void arc (float cx, float cy, float radius, float start_angle, float end_angle, bool anticlockwise)
 Native arc subpath.
virtual void arc_to (float x1, float y1, float x2, float y2, float radius)
 Native arcTo.
virtual void ellipse (float cx, float cy, float rx, float ry, float rotation, float start_angle, float end_angle, bool anticlockwise)
 Native ellipse subpath.
virtual void round_rect (float x, float y, float w, float h, float tl_x, float tl_y, float tr_x, float tr_y, float br_x, float br_y, float bl_x, float bl_y)
 Native rounded-rectangle subpath with per-corner radii.
virtual void close_path ()
 Close the current path subpath.
virtual void fill_current_path (FillRule rule=FillRule::nonzero)
 Fill the current path.
virtual void stroke_current_path ()
 Stroke the current path.
virtual void save_layer_with_bloom (float x, float y, float w, float h, float intensity, float threshold, float radius)
 Save a compositing layer that applies a real bloom/glow post-effect to the subtree painted into it.
virtual void fill_rect (float x, float y, float w, float h)=0
virtual void stroke_rect (float x, float y, float w, float h)=0
virtual void fill_rounded_rect (float x, float y, float w, float h, float radius)=0
virtual void stroke_rounded_rect (float x, float y, float w, float h, float radius)=0
virtual void fill_circle (float cx, float cy, float radius)=0
virtual void stroke_circle (float cx, float cy, float radius)=0
virtual void clear_rect (float x, float y, float w, float h)
 Clear a rectangular region to transparent black (rgba 0,0,0,0).
virtual void stroke_arc (float cx, float cy, float radius, float start_angle, float end_angle)=0
virtual void stroke_line (float x0, float y0, float x1, float y1)=0
virtual void stroke_path (const Point2D *points, size_t count)
 Stroke a continuous polyline — much smoother than individual stroke_line calls.
virtual void fill_path (const Point2D *points, size_t count, FillRule rule=FillRule::nonzero)
 Fill a closed polygon defined by points, honoring rule.
virtual void draw_image (void *native_handle, float x, float y, float w, float h)
 Draw an image identified by an opaque, platform-specific handle into the rectangle (x, y, w, h).
virtual void fill_path (const Path &path, FillRule rule=FillRule::nonzero)
 Fill path under rule.
virtual void stroke_path (const Path &path, const StrokeStyle &style)
 Stroke path with style.
virtual void clip_path (const Path &path, FillRule rule=FillRule::nonzero)
 Intersect the current clip with path. Caller owns save()/restore().
virtual void draw_path_shadow (const Path &path, float dx, float dy, float blur, float spread, Color color)
 Draw ONLY the drop shadow cast by path — not the path itself.
virtual void set_opacity (float alpha)
 Set global alpha for subsequent drawing operations (0.0-1.0).
virtual LayerHandle begin_layer (Rect2D bounds, bool cacheable=false)
 Begin recording into an offscreen layer covering bounds (in current user space).
virtual LayerHandle end_layer ()
 Seal the layer opened by the last begin_layer() and return its handle.
virtual void draw_layer (LayerHandle layer, float alpha=1.0f, BlendMode mode=BlendMode::normal)
 Composite a sealed layer at its recorded position.
virtual void draw_layer_fitted (LayerHandle layer, Rect2D dest)
 Composite a sealed layer scaled into dest.
virtual void draw_layer_rotated (LayerHandle layer, float angle_rad)
 Composite a sealed layer rotated about its own center.
virtual bool layer_valid (LayerHandle layer) const
 Is layer still backed by a live texture that can be drawn WITHOUT re-recording it?
virtual void invalidate_layer (LayerHandle layer)
 Drop layer's texture.
virtual std::shared_ptr< SceneRecording > record_scene (float w, float h, const std::function< void(Canvas &)> &paint)
 Record paint into a replayable SceneRecording, capturing its draw commands ONCE so later frames can draw_scene() the result instead of re-running the (recursive, allocating) paint.
virtual bool draw_scene (const SceneRecording &rec)
 Replay a recording produced by THIS backend's record_scene() at the current transform/clip.
virtual void save_layer (float x, float y, float w, float h, float opacity=1.0f, float blur_radius=0.0f)
 Save a compositing layer.
virtual void save_layer_with_blend (float x, float y, float w, float h, float opacity, float blur_radius, BlendMode mode)
 Save a compositing layer with an explicit blend mode.
virtual void save_layer_with_filters (float x, float y, float w, float h, float opacity, const FilterChainEntry *chain, int count)
virtual void save_layer_with_shader_effect (float x, float y, float w, float h, const std::string &effect_name, float intensity)
 Curated, named GPU post-effect layer save.
virtual void save_layer_with_mask (float x, float y, float w, float h, float opacity, const std::string &mask_image, const std::string &mask_size)
 CSS mask-image + mask-size paint slice.
virtual void set_font (const std::string &family, float size)=0
virtual void set_text_align (TextAlign align)=0
virtual void fill_text (const std::string &text, float x, float y)=0
virtual float measure_text (const std::string &text)=0
virtual float text_x_for_byte (const std::string &text, std::size_t byte_index)
 Caret x (in text-local space, measured from the text's leading edge) for the glyph boundary at byte_index within text.
virtual void fill_text_anchored (const std::string &text, float x, float y, TextAnchor anchor)
virtual void fill_text_with_max_width (const std::string &text, float x, float y, float max_width)
 Canvas2D fillText(text, x, y, maxWidth) spec form.
virtual void stroke_text (const std::string &text, float x, float y, float max_width=0.0f)
 Canvas2D strokeText(text, x, y, maxWidth) spec form.
virtual void set_font_full (const std::string &family, float size, int weight, int slant, float letter_spacing)
 Richer font setter that propagates CSS font-weight (100..900), font-slant (0=upright, 1=italic), and letter-spacing (px between glyphs) through to the backend.
virtual void set_font_smoothing (FontSmoothing smoothing)
 CSS -webkit-font-smoothing for the text drawn and measured after it.
virtual void set_font_features (std::vector< FontFeature > features)
virtual void clear_font_features ()
virtual void fill_text_sdf (const std::string &text, float x, float y, const class SdfAtlas &atlas)
 Render text using an SDF glyph atlas for resolution-independent rendering.
virtual bool supports (CanvasCapability) const
 Report whether this backend renders cap's verb faithfully.
bool supports_image_draw () const
 Whether this backend can actually decode + draw a raster image (the draw_image_from_* verbs below).
virtual bool draw_image_from_data (const uint8_t *data, size_t size, float x, float y, float w, float h)
 Draw an image from encoded data (PNG, JPEG, WebP) at the given rect.
virtual bool draw_image_from_file (const std::string &path, float x, float y, float w, float h)
 Draw an image from a file path at the given rect.
virtual bool draw_svg (const std::string &svg_document, float x, float y, float w, float h)
 Render an SVG document (the literal <svg>…</svg> string) into the box [x,y,w,h], scaled to fit.
virtual bool draw_image_from_file_rect (const std::string &path, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh)
virtual bool draw_image_from_data_rect (const uint8_t *data, size_t size, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh)
virtual bool measure_image_from_file (const std::string &path, float &out_width, float &out_height)
 Decoded-image intrinsic dimensions in pixels.
virtual TextMetrics measure_text_full (const std::string &text)
 Measure text with full font metrics using current font settings.
virtual void set_line_dash (const float *intervals, int count, float phase=0.0f)
 Set the line dash pattern for stroke operations.
virtual bool read_pixels (int x, int y, int width, int height, uint8_t *out)
 Read RGBA pixels from the current surface into out (size must be at least width*height*4).
virtual bool write_pixels (const uint8_t *data, int width, int height, int dx, int dy)
 Write RGBA pixels (data size = width*height*4) to the current surface at destination (dx, dy).
virtual void draw_sdf_shape (SDFShape shape, float x, float y, float w, float h, const SDFStyle &style)
virtual bool draw_sdf_shape_with_shader (SDFShape shape, float x, float y, float w, float h, const SDFStyle &style, const std::string &sksl, const ShaderDrawOptions &options)
 Draw a shape through an author-supplied geometry chart shader.
virtual void draw_blurred_backdrop (float x, float y, float w, float h, float blur_radius, float corner_radius=0, Color tint=Color::rgba(0.0f, 0.0f, 0.0f, 0.314f))
 Save a blurred snapshot of the current canvas content as a backdrop.
virtual void save_backdrop_filter (float x, float y, float w, float h, float blur_radius)
 CSS backdrop-filter: blur(Npx) — push a compositing layer whose initial contents are the parent surface filtered through a Gaussian blur of blur_radius.
virtual void save_backdrop_filter_chain (float x, float y, float w, float h, const FilterChainEntry *chain, int count)
 CSS backdrop-filter with its full function list — saturate(0.2), brightness(2), invert(1), a grayscale(1) brightness(1.6) pair.
virtual void draw_box_shadow (float x, float y, float w, float h, float dx, float dy, float blur, float spread, Color color, bool inset=false, float corner_radius=0.0f)
 Draw a CSS-style box shadow around (or inside, when inset) a rounded rectangle anchored at (x, y, w, h).
virtual void set_shadow_color (Color color)
 Sticky drop-shadow state that wraps subsequent draw operations, matching the CanvasRenderingContext2D shadowColor / shadowBlur / shadowOffsetX / shadowOffsetY properties.
virtual void set_shadow_blur (float blur)
virtual void set_shadow_offset_x (float dx)
virtual void set_shadow_offset_y (float dy)
virtual void set_direction (TextDirection direction)
virtual void set_filter (const std::string &filter)
 Canvas2D ctx.filter.
virtual void draw_waveform (const float *samples, size_t count, float x, float y, float width, float height, const WaveformStyle &style)
virtual bool draw_with_sksl (const std::string &sksl, float x, float y, float w, float h, const ShaderUniforms &uniforms)
 Draw a rectangle filled by a custom SkSL shader.
virtual bool draw_with_sksl (const std::string &sksl, float x, float y, float w, float h, const ShaderDrawOptions &options)
virtual bool save_layer_with_sksl_post_effect (float x, float y, float w, float h, const std::string &sksl, const ShaderUniforms &uniforms, float sample_radius=0.0f, const std::vector< NamedUniform > &extra_uniforms={}, BlendMode blend_mode=BlendMode::normal)
 Save a compositing layer whose ALREADY-PAINTED content is post-processed by a custom SkSL shader.
virtual void draw_image_transformed (void *native_handle, float w, float h, const AffineTransform &t)
 Draw an opaque image handle (see draw_image) under an arbitrary affine transform.
virtual void draw_image_fitted (void *native_handle, float iw, float ih, float dx, float dy, float dw, float dh, ImageFit fit, float align_x=0.5f, float align_y=0.5f)
 Draw an opaque image handle fitted into a destination box with a preserve-aspect fit mode and alignment.
virtual bool draw_image_file_fitted (const std::string &path, float dx, float dy, float dw, float dh, ImageFit fit, float align_x=0.5f, float align_y=0.5f)
 Draw a file-path image fitted into a destination box.
virtual void draw_image_tiled (void *native_handle, float tile_w, float tile_h, float dx, float dy, float dw, float dh, float offset_x=0.0f, float offset_y=0.0f)
 Fill the destination box (dx, dy, dw, dh) by tiling an opaque image handle at cells of size (tile_w x tile_h).
virtual void set_fill_gradient_conic_repeating (float cx, float cy, float start_angle, float sweep_turns, const Color *colors, const float *positions, int count)
 Set a REPEATING conic gradient (CSS repeating-conic-gradient).
virtual void set_fill_gradient_linear_repeating (float x0, float y0, float x1, float y1, const Color *colors, const float *positions, int count)
 Set a REPEATING linear gradient (CSS repeating-linear-gradient).
virtual bool draw_image_from_static_data_rect (const uint8_t *data, size_t size, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh)
 Source-rect draw for bytes with static storage duration and immutable contents.
virtual bool draw_image_from_keyed_data (const std::string &content_key, const uint8_t *data, size_t size, float x, float y, float w, float h)
 Draw encoded image bytes identified by content_key, the lowercase hex SHA-256 of exactly those bytes.
virtual bool draw_image_from_keyed_data_rect (const std::string &content_key, const uint8_t *data, size_t size, float sx, float sy, float sw, float sh, float dx, float dy, float dw, float dh)
 Source-rect form of draw_image_from_keyed_data, with the same key contract.
virtual bool measure_image_from_data (const uint8_t *data, size_t size, float &out_width, float &out_height)
 Intrinsic pixel size of encoded image bytes, read from the image header without decoding pixels: the size draw_image_from_data would draw the full image at.
virtual void set_gradient_interpolation (GradientInterpolation m)
 Colour space every LATER gradient setter blends its stops in (CSS <color-interpolation-method>), until set again; save() does not keep it.
GradientInterpolation gradient_interpolation () const

Static Public Member Functions

static constexpr uint32_t make_font_feature_tag (const char(&s)[5])
 Builds a 4-byte big-endian OpenType tag from a 4-char string.
static std::string compile_sksl (const std::string &sksl)
 Validate and compile an SkSL shader without drawing.
static std::string compile_sdf_chart_sksl (SDFShape shape, const std::string &sksl)
 Compile an author chart shader against the geometry prelude used by draw_sdf_shape_with_shader.
static float sdf_feather_min_reach (const SDFStyle &style)
 The smallest draw-rect reach that holds style's feather: 3 sigma for the glow (1) and outer (3) modes, whose coverage lives outside the shape, and 0 for every other mode or a zero sigma.
static bool sksl_declares_uniform (const std::string &sksl, const std::string &uniform_name)
 Whether an SkSL shader declares a uniform of the given name.
static FitResult fit_image_rect (float iw, float ih, float dx, float dy, float dw, float dh, ImageFit fit, float align_x=0.5f, float align_y=0.5f)
 Pure geometry: place a source image of intrinsic size (iw x ih) into the destination box (dx, dy, dw, dh) per fit.

Protected Attributes

float font_size_ = 14.0f
 Current font size (set by set_font).

Member Typedef Documentation

◆ Point2D

Stroke a continuous polyline through an array of points.

Much smoother than individual stroke_line calls — produces proper anti-aliased curves with line joins between segments. Alias, not a second type. The canonical point lives at namespace scope in <pulp/canvas/affine_transform.hpp> so Path can use it; this name keeps every existing Canvas::Point2D call site working. (It is spelled Point2D rather than Point because Apple's MacTypes.h declares a global Point — see the note on pulp::canvas::Point2D.)

Member Enumeration Documentation

◆ BlendMode

Indices 0..15 match the existing W3C "advanced" composite ops and must stay stable — set_blend_mode in the JS bridge currently passes int_val 1/2/3 = multiply/screen/overlay.

Indices 16+ are Porter-Duff and "extra" CSS composite ops added so the JS bridge can support the full CanvasRenderingContext2D.globalCompositeOperation surface.

Enumerator
normal 
multiply 
screen 
overlay 
darken 
lighten 
color_dodge 
color_burn 
hard_light 
soft_light 
difference 
exclusion 
hue 
saturation 
color 
luminosity 
source_over 
destination_over 
source_in 
destination_in 
source_out 
destination_out 
source_atop 
destination_atop 
xor_mode 
copy 
lighter 

◆ ImageFit

enum class pulp::canvas::Canvas::ImageFit
strong

Preserve-aspect fit modes for fit_image_rect / draw_image_fitted: fill — stretch to the destination box, ignoring aspect ratio.

contain — scale (preserving aspect) to the largest size that fits fully inside the box; may leave margins. cover — scale (preserving aspect) to the smallest size that fully covers the box; may crop (clipped to the box). none — natural pixel size, no scaling; positioned by alignment. scale_down — like none when the image already fits, otherwise like contain (never scales up).

Enumerator
fill 
contain 
cover 
none 
scale_down 

◆ ImageSmoothingQuality

Canvas2D image-smoothing quality enum.

Mirrors the spec's imageSmoothingQuality attribute. The bridge maps the JS string values ("low" | "medium" | "high") onto these.

Enumerator
low 
medium 
high 

◆ PatternTileMode

Canvas2D ctx.createPattern.

Tile mode per axis: repeat mirrors Skia's SkTileMode::kRepeat, no_repeat mirrors SkTileMode::kDecal. Spec values map as: "repeat" → (repeat, repeat) "repeat-x" → (repeat, no_repeat) "repeat-y" → (no_repeat, repeat) "no-repeat" → (no_repeat, no_repeat)

Enumerator
repeat 
no_repeat 

◆ SDFShape

enum class pulp::canvas::Canvas::SDFShape
strong

Draw an SDF shape with anti-aliased edges via GPU shader.

Enumerator
rect 
circle 
rounded_rect 
arc 
diamond 
squircle 
triangle 
ring 
stadium 
cross 
flat_segment 
rounded_segment 
flat_arc 
quadratic_bezier 

◆ TextAnchor

Explicit, typed vertical-anchor API.

The historical fill_text(text, x, y) follows the Canvas2D spec (web-compat baseline semantics) — y is the text baseline. Non-spec callers (widgets that mix labels with knobs / faders inside flex rows) need to opt for a different reference line so mixed-fontSize centered rows align on glyph reference, not box reference. Anchor modes:

Baseline — y is the baseline (Canvas2D web-spec default). GlyphTop — y is the top of the worst-case glyph bbox (SkFontMetrics::fTop). Useful when the caller computes top-of-text manually. GlyphCenter — y is the vertical CENTER of the glyph bbox. Use for vertical-align: middle semantics where you want the painted glyphs (not the measure box) centered on a target line. EmBoxTop — y is the top of the em-box (font-size based, font-independent). Use when laying out uniform-sized glyph grids.

Default implementation ignores anchor and treats y as the baseline, delegating straight to fill_text. Backends with font metrics override to translate y into a per-anchor baseline-y so glyphs land on the exact pixel the parity harness asserts.

Enumerator
Baseline 
GlyphTop 
GlyphCenter 
EmBoxTop 

◆ TextDirection

Canvas2D ctx.direction.

Sticky text-shaping direction that applies to subsequent fillText / strokeText calls. Spec values: ltr — left-to-right (default; matches SkShaper leftToRight=true) rtl — right-to-left (HarfBuzz buffer direction RTL) inherit — pulled from the canvas element / document writing direction. On backends without a per-View writing direction yet, treated as ltr (the most common case). Default no-op so backends without a real bidi/HarfBuzz path remain unaffected; SkiaCanvas overrides to wire through to the SkShaper invocation flag, RecordingCanvas captures one set_direction command per setter so canvas2d harness tests can assert flush order. Real bidi support (mixed-script paragraphs requiring the Bidi algorithm) tracks separately.

Enumerator
ltr 
rtl 
inherit 

Constructor & Destructor Documentation

◆ ~Canvas()

virtual pulp::canvas::Canvas::~Canvas ( )
virtualdefault

Member Function Documentation

◆ arc()

virtual void pulp::canvas::Canvas::arc ( float cx,
float cy,
float radius,
float start_angle,
float end_angle,
bool anticlockwise )
inlinevirtual

Native arc subpath.

Maps to Canvas2D ctx.arc(cx, cy, r, startAngle, endAngle, anticlockwise) and to SkPath::arcTo(SkRect, startDeg, sweepDeg, false) on Skia. Replaces the JS shim's bezier approximation. The default fallback emits a quadrant-segmented cubic-bezier polyline so capture-only backends (RecordingCanvas) still produce a meaningful command stream when they choose not to override.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ arc_to()

virtual void pulp::canvas::Canvas::arc_to ( float x1,
float y1,
float x2,
float y2,
float radius )
inlinevirtual

Native arcTo.

Maps to Canvas2D ctx.arcTo(x1, y1, x2, y2, radius) and to SkPath::arcTo(p1, p2, radius) on Skia (the 5-arg overload that computes the tangent arc between the current point, p1, and p2).

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ backing_scale()

virtual float pulp::canvas::Canvas::backing_scale ( ) const
inlinevirtualnoexcept

Effective device pixels per local canvas unit at the current transform.

Backends with an inspectable CTM override this when necessary; the default is correct for logical 1x recording/test canvases.

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ begin_layer()

virtual LayerHandle pulp::canvas::Canvas::begin_layer ( Rect2D bounds,
bool cacheable = false )
inlinevirtual

Begin recording into an offscreen layer covering bounds (in current user space).

Drawing between this and end_layer() goes to the layer, not the canvas.

cacheable asks the backend to KEEP the layer's texture after end_layer() so it can be redrawn on later frames without re-recording. A non-cacheable layer may be discarded as soon as it has been drawn once.

Backends without offscreen support return the null handle and draw through to the canvas directly. That degrades to "re-record every frame", which is correct — just not cached — because layer_valid() keeps returning false and the caller's if above keeps re-recording.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ begin_path()

virtual void pulp::canvas::Canvas::begin_path ( )
inlinevirtual

Begin a new path.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ capture_paint_baseline_transform()

virtual void pulp::canvas::Canvas::capture_paint_baseline_transform ( )
inlinevirtual

Snapshot the current device matrix as the baseline for subsequent set_transform() calls.

CanvasWidget::paint() calls this at entry so JS-supplied setTransform() composes onto the parent View transform rather than wiping it. Default no-op for non-Skia backends.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ clear_fill_gradient()

virtual void pulp::canvas::Canvas::clear_fill_gradient ( )
inlinevirtual

Clear gradient, return to solid fill color.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ clear_font_features()

virtual void pulp::canvas::Canvas::clear_font_features ( )
inlinevirtual

◆ clear_rect()

virtual void pulp::canvas::Canvas::clear_rect ( float x,
float y,
float w,
float h )
inlinevirtual

Clear a rectangular region to transparent black (rgba 0,0,0,0).

Equivalent to CanvasRenderingContext2D.clearRect — replaces existing pixels rather than compositing over them. Pixel backends (SkiaCanvas) override with a kSrc/kClear paint so the underlying texels actually become transparent; the default falls back to a SrcOver fill with a transparent color (a no-op on most surfaces, but keeps recording / introspection backends inert). Without this replacement path, ctx.clearRect() on the canvas widget would not clear residual or parent-painted pixels.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ clear_stroke_gradient()

virtual void pulp::canvas::Canvas::clear_stroke_gradient ( )
inlinevirtual

Clear stroke gradient/pattern shader, restore solid stroke color.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ clip()

virtual void pulp::canvas::Canvas::clip ( FillRule rule = FillRule::nonzero)
inlinevirtual

Intersect the current clip region with the current path.

Mirrors CanvasRenderingContext2D.clip(). Default no-op so backends without a path builder remain unaffected. rule selects nonzero vs evenodd winding.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ clip_path()

virtual void pulp::canvas::Canvas::clip_path ( const Path & path,
FillRule rule = FillRule::nonzero )
inlinevirtual

Intersect the current clip with path. Caller owns save()/restore().

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ clip_path_svg()

virtual void pulp::canvas::Canvas::clip_path_svg ( const std::string & svg_path_d)
inlinevirtual

CSS clip-path: path("...") — intersect the current clip with an SVG-path-d string.

Skia maps to SkPath::FromSVGString + SkCanvas::clipPath. RecordingCanvas captures a clip_path_svg command for tests; backends without a path parser fall back to a no-op so callers can invoke it unconditionally without breaking save/restore bookkeeping. The caller is responsible for save()/restore() balancing — typical usage is save(); clip_path_svg("M..."); ...children...; restore();.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ clip_rect()

virtual void pulp::canvas::Canvas::clip_rect ( float x,
float y,
float w,
float h )
pure virtual

◆ close_path()

virtual void pulp::canvas::Canvas::close_path ( )
inlinevirtual

Close the current path subpath.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ compile_sdf_chart_sksl()

std::string pulp::canvas::Canvas::compile_sdf_chart_sksl ( SDFShape shape,
const std::string & sksl )
static

Compile an author chart shader against the geometry prelude used by draw_sdf_shape_with_shader.

The author source must define shade(PulpChart).

◆ compile_sksl()

std::string pulp::canvas::Canvas::compile_sksl ( const std::string & sksl)
static

Validate and compile an SkSL shader without drawing.

Returns error string (empty = success). Static so it can be called without a Canvas instance. Non-Skia builds return a non-empty "Skia not available" error rather than reporting a false success — there is no compiler to ask.

◆ concat_transform()

virtual void pulp::canvas::Canvas::concat_transform ( float a,
float b,
float c,
float d,
float e,
float f )
inlinevirtual

Concat (multiply) the supplied affine matrix onto the current transform — does NOT replace it.

Used by View::paint_all() when a JS-supplied setTransform(id,a,b,c,d,e,f) is active on a View, so the View's transform composes with parent transforms (translate to bounds, outer transforms, etc.) rather than wiping them. Mirrors SkCanvas::concat. Matrix layout matches CanvasRenderingContext2D.setTransform: [ a c e ] [ b d f ] [ 0 0 1 ] Default no-op so non-Skia backends compile; Skia overrides to call SkCanvas::concat, RecordingCanvas overrides to capture the command.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ cubic_to()

virtual void pulp::canvas::Canvas::cubic_to ( float cp1x,
float cp1y,
float cp2x,
float cp2y,
float x,
float y )
inlinevirtual

Add a cubic bezier curve.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ current_transform()

virtual AffineTransform2x3 pulp::canvas::Canvas::current_transform ( ) const
inlinevirtual

Snapshot the current device matrix (CTM) without mutating canvas state.

Used by CanvasWidget::paint() diagnostics to log the inbound transform per paint when PULP_LOG_CANVAS_PAINT=1 is set, so we can confirm whether a missing canvas paint is caused by the CTM ending up off-window vs the widget never being painted at all. Default returns identity for backends without an introspectable matrix; SkiaCanvas (getTotalMatrix), CoreGraphicsCanvas (CGContextGetCTM), and RecordingCanvas (manual matrix tracking) override.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ draw_blurred_backdrop()

virtual void pulp::canvas::Canvas::draw_blurred_backdrop ( float x,
float y,
float w,
float h,
float blur_radius,
float corner_radius = 0,
Color tint = Color::rgba(0.0f, 0.0f, 0.0f, 0.314f) )
inlinevirtual

Save a blurred snapshot of the current canvas content as a backdrop.

Call before painting the overlay content.

◆ draw_box_shadow()

virtual void pulp::canvas::Canvas::draw_box_shadow ( float x,
float y,
float w,
float h,
float dx,
float dy,
float blur,
float spread,
Color color,
bool inset = false,
float corner_radius = 0.0f )
virtual

Draw a CSS-style box shadow around (or inside, when inset) a rounded rectangle anchored at (x, y, w, h).

When inset is false this is a drop shadow rendered outside the box; when true it is an inner shadow rendered inside the box clipped to the box geometry. Default implementation is a CPU fallback that approximates the blur with stacked translucent rounded rects — Skia overrides with SkImageFilters::DropShadowOnly for a true Gaussian shadow. The out-of-line definition lives in core/canvas/src/recording_canvas.cpp so the CPU fallback is exercised by the canvas-level tests during coverage runs.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ draw_image()

virtual void pulp::canvas::Canvas::draw_image ( void * native_handle,
float x,
float y,
float w,
float h )
inlinevirtual

Draw an image identified by an opaque, platform-specific handle into the rectangle (x, y, w, h).

The handle is the native_handle published by pulp::view::ImageCache (see core/view/include/pulp/view/image_cache.hpp). Backends know how to interpret their own handles:

  • CoreGraphicsCanvas: CGImageRef
  • SkiaCanvas: SkImage* Canvases without an image pipeline are a no-op by default so widgets can call this unconditionally — the placeholder layer behind them keeps the UI non-blank.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ draw_image_file_fitted()

virtual bool pulp::canvas::Canvas::draw_image_file_fitted ( const std::string & path,
float dx,
float dy,
float dw,
float dh,
ImageFit fit,
float align_x = 0.5f,
float align_y = 0.5f )
inlinevirtual

Draw a file-path image fitted into a destination box.

Consults measure_image_from_file for the intrinsic size; if the backend cannot measure it, falls back to stretching the image to the box (the plain draw_image_from_file behavior). Returns whatever the underlying draw returns (false when the backend cannot draw the image).

◆ draw_image_fitted()

virtual void pulp::canvas::Canvas::draw_image_fitted ( void * native_handle,
float iw,
float ih,
float dx,
float dy,
float dw,
float dh,
ImageFit fit,
float align_x = 0.5f,
float align_y = 0.5f )
inlinevirtual

Draw an opaque image handle fitted into a destination box with a preserve-aspect fit mode and alignment.

iw / ih are the image's intrinsic pixel dimensions (the handle is opaque, so the caller supplies them). The default clips to the destination box — so cover cannot paint outside it — and draws the fitted rectangle via draw_image.

◆ draw_image_from_data()

virtual bool pulp::canvas::Canvas::draw_image_from_data ( const uint8_t * data,
size_t size,
float x,
float y,
float w,
float h )
inlinevirtual

Draw an image from encoded data (PNG, JPEG, WebP) at the given rect.

Returns true if the image was decoded and drawn successfully.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ draw_image_from_data_rect()

virtual bool pulp::canvas::Canvas::draw_image_from_data_rect ( const uint8_t * data,
size_t size,
float sx,
float sy,
float sw,
float sh,
float dx,
float dy,
float dw,
float dh )
inlinevirtual

◆ draw_image_from_file()

virtual bool pulp::canvas::Canvas::draw_image_from_file ( const std::string & path,
float x,
float y,
float w,
float h )
inlinevirtual

Draw an image from a file path at the given rect.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ draw_image_from_file_rect()

virtual bool pulp::canvas::Canvas::draw_image_from_file_rect ( const std::string & path,
float sx,
float sy,
float sw,
float sh,
float dx,
float dy,
float dw,
float dh )
inlinevirtual

◆ draw_image_from_keyed_data()

virtual bool pulp::canvas::Canvas::draw_image_from_keyed_data ( const std::string & content_key,
const uint8_t * data,
size_t size,
float x,
float y,
float w,
float h )
inlinevirtual

Draw encoded image bytes identified by content_key, the lowercase hex SHA-256 of exactly those bytes.

A backend may retain the decoded or GPU-uploaded image under that key across frames, so the key must change whenever the bytes do and must never be derived from the buffer address (a freed buffer's address is reused for different bytes). An empty key draws uncached. The default does not cache; it draws exactly as draw_image_from_data. Appended to preserve existing vtable slots.

◆ draw_image_from_keyed_data_rect()

virtual bool pulp::canvas::Canvas::draw_image_from_keyed_data_rect ( const std::string & content_key,
const uint8_t * data,
size_t size,
float sx,
float sy,
float sw,
float sh,
float dx,
float dy,
float dw,
float dh )
inlinevirtual

Source-rect form of draw_image_from_keyed_data, with the same key contract.

The default draws exactly as draw_image_from_data_rect.

◆ draw_image_from_static_data_rect()

virtual bool pulp::canvas::Canvas::draw_image_from_static_data_rect ( const uint8_t * data,
size_t size,
float sx,
float sy,
float sw,
float sh,
float dx,
float dy,
float dw,
float dh )
inlinevirtual

Source-rect draw for bytes with static storage duration and immutable contents.

GPU backends may retain a decoded/uploaded image across frames. Appended to preserve the slots of existing Canvas virtual methods. Never use this for a mutable or short-lived buffer.

◆ draw_image_tiled()

virtual void pulp::canvas::Canvas::draw_image_tiled ( void * native_handle,
float tile_w,
float tile_h,
float dx,
float dy,
float dw,
float dh,
float offset_x = 0.0f,
float offset_y = 0.0f )
inlinevirtual

Fill the destination box (dx, dy, dw, dh) by tiling an opaque image handle at cells of size (tile_w x tile_h).

offset_x / offset_y shift the tile origin (for scrolling patterns). The default clips to the box and lays whole tiles via repeated draw_image; the trailing row / column overshoot the box but are clipped away. Pixel backends may override with a single tiled-shader fill; set_fill_pattern is the sticky shader-based alternative when a fill PATH (rather than a direct box) is what needs the tiling.

◆ draw_image_transformed()

virtual void pulp::canvas::Canvas::draw_image_transformed ( void * native_handle,
float w,
float h,
const AffineTransform & t )
inlinevirtual

Draw an opaque image handle (see draw_image) under an arbitrary affine transform.

The image's natural box [0, 0, w, h] is painted through t, composed onto the current transform. Default composes concat_transform + draw_image inside a save / restore pair so the caller's transform state is preserved.

◆ draw_layer()

virtual void pulp::canvas::Canvas::draw_layer ( LayerHandle layer,
float alpha = 1.0f,
BlendMode mode = BlendMode::normal )
inlinevirtual

Composite a sealed layer at its recorded position.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ draw_layer_fitted()

virtual void pulp::canvas::Canvas::draw_layer_fitted ( LayerHandle layer,
Rect2D dest )
inlinevirtual

Composite a sealed layer scaled into dest.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ draw_layer_rotated()

virtual void pulp::canvas::Canvas::draw_layer_rotated ( LayerHandle layer,
float angle_rad )
inlinevirtual

Composite a sealed layer rotated about its own center.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ draw_path_shadow()

virtual void pulp::canvas::Canvas::draw_path_shadow ( const Path & path,
float dx,
float dy,
float blur,
float spread,
Color color )
inlinevirtual

Draw ONLY the drop shadow cast by path — not the path itself.

This is a shadow-*rendering* primitive, deliberately separate from save_layer_with_filters's drop_shadow filter Kind (which shadows a whole painted subtree). The split exists because the common case — "shadow behind this icon, then the icon on top, in a different color" — needs the shadow WITHOUT the source, and a filter chain always composites the source too.

spread grows the shadow's silhouette before blurring, matching the CSS box-shadow spread term. The default fallback approximates it by scaling the path about its own center, which is exact for convex shapes and an approximation for concave ones (a true spread is a Minkowski sum / path outset, which is not something the immediate-mode API can express).

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ draw_scene()

virtual bool pulp::canvas::Canvas::draw_scene ( const SceneRecording & rec)
inlinevirtual

Replay a recording produced by THIS backend's record_scene() at the current transform/clip.

Returns false when rec is not this backend's recording type (defensive — a foreign or base recording is never drawn), leaving the caller to fall back to a direct paint.

◆ draw_sdf_shape()

virtual void pulp::canvas::Canvas::draw_sdf_shape ( SDFShape shape,
float x,
float y,
float w,
float h,
const SDFStyle & style )
inlinevirtual

◆ draw_sdf_shape_with_shader()

virtual bool pulp::canvas::Canvas::draw_sdf_shape_with_shader ( SDFShape shape,
float x,
float y,
float w,
float h,
const SDFStyle & style,
const std::string & sksl,
const ShaderDrawOptions & options )
inlinevirtual

Draw a shape through an author-supplied geometry chart shader.

The shader must define half4 shade(PulpChart g).

Charted shapes are flat_arc, ring, flat_segment, rounded_segment and stadium; any other shape is refused, by name, rather than drawn. g.cross is the signed offset from the centre line, g.d the band's distance. g.valid is zero for degenerate geometry (no sweep, length or band); callers must not interpret chart fields when it is zero.

g.px is one device pixel expressed in the same units as g.d, taken from backing_scale(), so 2.0 * g.px is two device pixels at any backing scale rather than only at 1x.

The shader is evaluated over the w x h rect grown by options.reach on every side, so a feather or glow can paint past the shape's box. A glow or outer feather whose reach is below sdf_feather_min_reach(style) is refused (returns false, draws nothing) rather than drawn with its falloff cut off at the rect edge.

◆ draw_svg()

virtual bool pulp::canvas::Canvas::draw_svg ( const std::string & svg_document,
float x,
float y,
float w,
float h )
inlinevirtual

Render an SVG document (the literal <svg>…</svg> string) into the box [x,y,w,h], scaled to fit.

Backed by Skia's SkSVGDOM, so gradients, filters (drop shadows), masks, opacities, and transforms render exactly as authored — the faithful-vector design-import lane draws a Figma node's own SVG export through here instead of approximating it. Returns false if the backend can't render SVG (non-Skia) or the document fails to parse.

◆ draw_waveform()

virtual void pulp::canvas::Canvas::draw_waveform ( const float * samples,
size_t count,
float x,
float y,
float width,
float height,
const WaveformStyle & style )
inlinevirtual

◆ draw_with_sksl() [1/2]

virtual bool pulp::canvas::Canvas::draw_with_sksl ( const std::string & sksl,
float x,
float y,
float w,
float h,
const ShaderDrawOptions & options )
inlinevirtual

◆ draw_with_sksl() [2/2]

virtual bool pulp::canvas::Canvas::draw_with_sksl ( const std::string & sksl,
float x,
float y,
float w,
float h,
const ShaderUniforms & uniforms )
inlinevirtual

Draw a rectangle filled by a custom SkSL shader.

Only works on GPU backends (SkiaCanvas). CPU backends draw a fallback rect. The shader receives: uniform float2 resolution, float value, float time, layout(color) float4 accentColor/bgColor/trackColor/fillColor/thumbColor.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ ellipse()

virtual void pulp::canvas::Canvas::ellipse ( float cx,
float cy,
float rx,
float ry,
float rotation,
float start_angle,
float end_angle,
bool anticlockwise )
inlinevirtual

Native ellipse subpath.

Maps to Canvas2D ctx.ellipse(cx, cy, rx, ry, rotation, startAngle, endAngle, anticlockwise). Honours rotation (rx/ry axis rotation in radians) by transforming the arc through SkMatrix on Skia.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ end_layer()

virtual LayerHandle pulp::canvas::Canvas::end_layer ( )
inlinevirtual

Seal the layer opened by the last begin_layer() and return its handle.

After this, drawing goes back to the canvas (or the enclosing layer).

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ fill_circle()

virtual void pulp::canvas::Canvas::fill_circle ( float cx,
float cy,
float radius )
pure virtual

◆ fill_current_path()

virtual void pulp::canvas::Canvas::fill_current_path ( FillRule rule = FillRule::nonzero)
inlinevirtual

Fill the current path.

rule selects nonzero vs evenodd winding, matching Canvas2D ctx.fill('evenodd').

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ fill_path() [1/2]

virtual void pulp::canvas::Canvas::fill_path ( const Path & path,
FillRule rule = FillRule::nonzero )
inlinevirtual

Fill path under rule.

Resets the current path, matching the Canvas2D convention that a shape-drawing call owns the path it builds.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ fill_path() [2/2]

virtual void pulp::canvas::Canvas::fill_path ( const Point2D * points,
size_t count,
FillRule rule = FillRule::nonzero )
inlinevirtual

Fill a closed polygon defined by points, honoring rule.

rule selects nonzero vs even-odd winding, exactly as fill_current_path(rule) / Canvas2D ctx.fill('evenodd') do. Without it a compound point array (an outer contour followed by an inner one) could only ever fill as a solid disc — there was no way to punch the hole that makes it a ring.

The default is NOT a no-op. It synthesizes the polygon through the path API — begin_path / move_to / line_to / close_path / fill_current_path(rule) — which every backend already implements, so a Canvas subclass that does not override fill_path still draws the polygon instead of silently dropping it. Backends override only to skip the state round-trip (SkiaCanvas builds one SkPath; CoreGraphicsCanvas one CGPath).

Note the default resets the current path (begin_path), matching the Canvas2D convention that a shape-drawing call owns the path it builds. Degenerate input (null array, or fewer than three points — no enclosed area) draws nothing and never reads the array.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ fill_rect()

virtual void pulp::canvas::Canvas::fill_rect ( float x,
float y,
float w,
float h )
pure virtual

◆ fill_rounded_rect()

virtual void pulp::canvas::Canvas::fill_rounded_rect ( float x,
float y,
float w,
float h,
float radius )
pure virtual

◆ fill_text()

virtual void pulp::canvas::Canvas::fill_text ( const std::string & text,
float x,
float y )
pure virtual

◆ fill_text_anchored()

virtual void pulp::canvas::Canvas::fill_text_anchored ( const std::string & text,
float x,
float y,
TextAnchor anchor )
inlinevirtual

◆ fill_text_sdf()

virtual void pulp::canvas::Canvas::fill_text_sdf ( const std::string & text,
float x,
float y,
const class SdfAtlas & atlas )
inlinevirtual

Render text using an SDF glyph atlas for resolution-independent rendering.

The atlas must be pre-built via SdfAtlas::build(). Falls back to fill_text() if GPU is unavailable or the atlas doesn't contain the required glyphs.

◆ fill_text_with_max_width()

virtual void pulp::canvas::Canvas::fill_text_with_max_width ( const std::string & text,
float x,
float y,
float max_width )
inlinevirtual

Canvas2D fillText(text, x, y, maxWidth) spec form.

When max_width > 0 and the natural rendered advance exceeds it, the backend MUST scale the text horizontally so the resulting run is exactly max_width px wide (vertical metrics unchanged). The default implementation falls through to fill_text(text, x, y), preserving legacy behavior for backends that don't yet honor the constraint (RecordingCanvas, base mocks). Skia and CoreGraphics override this to apply an SkMatrix::Scale(maxWidth/measured, 1) (Skia) / CGContextScaleCTM(scale, 1) (CG) around the text origin. Glyph cluster boundaries are unaffected — HarfBuzz already shapes each cluster as an indivisible unit, so horizontal compression preserves cluster integrity by construction.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ fit_image_rect()

FitResult pulp::canvas::Canvas::fit_image_rect ( float iw,
float ih,
float dx,
float dy,
float dw,
float dh,
ImageFit fit,
float align_x = 0.5f,
float align_y = 0.5f )
inlinestatic

Pure geometry: place a source image of intrinsic size (iw x ih) into the destination box (dx, dy, dw, dh) per fit.

Alignment align_x / align_y are fractions in [0, 1]: 0 = left / top, 0.5 = center, 1 = right / bottom, positioning the scaled image inside (or, for cover, over) the box. Side-effect free, so it is unit-testable on its own without a backend.

◆ gradient_interpolation()

GradientInterpolation pulp::canvas::Canvas::gradient_interpolation ( ) const
inline

◆ invalidate_layer()

virtual void pulp::canvas::Canvas::invalidate_layer ( LayerHandle layer)
inlinevirtual

Drop layer's texture.

The next layer_valid() returns false, so the caller re-records it. Call this when the layer's contents change; backends may also perform the same retirement for context/scale changes.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ layer_valid()

virtual bool pulp::canvas::Canvas::layer_valid ( LayerHandle layer) const
inlinevirtual

Is layer still backed by a live texture that can be drawn WITHOUT re-recording it?

Check every frame: explicit invalidation and backend context/backing-scale lifecycle changes may retire a handle.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ line_to()

virtual void pulp::canvas::Canvas::line_to ( float x,
float y )
inlinevirtual

Add a line segment to (x, y).

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ make_font_feature_tag()

constexpr uint32_t pulp::canvas::Canvas::make_font_feature_tag ( const char(&) s[5])
inlinestaticconstexpr

Builds a 4-byte big-endian OpenType tag from a 4-char string.

Caller supplies exactly 4 ASCII chars (e.g. "tnum"); shorter strings are a compile error.

◆ measure_image_from_data()

virtual bool pulp::canvas::Canvas::measure_image_from_data ( const uint8_t * data,
size_t size,
float & out_width,
float & out_height )
inlinevirtual

Intrinsic pixel size of encoded image bytes, read from the image header without decoding pixels: the size draw_image_from_data would draw the full image at.

Returns false (sizes 0) when the bytes are not an image this backend can decode. The default reads a PNG IHDR only, so a backend with no decoder still sizes PNGs; Skia and CoreGraphics read every format their decoders accept. Appended after the existing virtuals.

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ measure_image_from_file()

virtual bool pulp::canvas::Canvas::measure_image_from_file ( const std::string & path,
float & out_width,
float & out_height )
inlinevirtual

Decoded-image intrinsic dimensions in pixels.

Returned via out-params so backends without image decode just leave them at 0 and callers short-circuit to "use destination bounds" (the previous behavior). Used by ImageView::paint to honor CSS object-fit / object-position and by canvas2d sprite sizing. Default returns false; Skia overrides to consult its decoder.

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ measure_text()

virtual float pulp::canvas::Canvas::measure_text ( const std::string & text)
pure virtual

◆ measure_text_full()

virtual TextMetrics pulp::canvas::Canvas::measure_text_full ( const std::string & text)
inlinevirtual

Measure text with full font metrics using current font settings.

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ move_to()

virtual void pulp::canvas::Canvas::move_to ( float x,
float y )
inlinevirtual

Move the pen to (x, y) without drawing.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ quad_to()

virtual void pulp::canvas::Canvas::quad_to ( float cpx,
float cpy,
float x,
float y )
inlinevirtual

Add a quadratic bezier curve to (x, y) with control point (cpx, cpy).

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ read_pixels()

virtual bool pulp::canvas::Canvas::read_pixels ( int x,
int y,
int width,
int height,
uint8_t * out )
inlinevirtual

Read RGBA pixels from the current surface into out (size must be at least width*height*4).

Returns true on success. Default returns false (RecordingCanvas, CG fallback) — only Skia raster surfaces implement this end-to-end. Mirrors CanvasRenderingContext2D.getImageData().

◆ record_scene()

virtual std::shared_ptr< SceneRecording > pulp::canvas::Canvas::record_scene ( float w,
float h,
const std::function< void(Canvas &)> & paint )
inlinevirtual

Record paint into a replayable SceneRecording, capturing its draw commands ONCE so later frames can draw_scene() the result instead of re-running the (recursive, allocating) paint.

w/h are the recorded content's logical size — the recording is resolution-INDEPENDENT (it stores commands in logical coordinates), so a DPI change replays the same recording with no re-record and no image re-upload.

Distinct from the begin_layer/draw_layer texture cache above: that snapshots a rasterised texture (Visage-style), this records the command stream (a lighter, resolution-free cache). Both are opt-in caches over the same "paint a subtree once, reuse it" need.

Returns nullptr when the backend cannot record (the base class, the CoreGraphics backend, and RecordingCanvas all do) — the caller MUST then paint directly every frame. supports(CanvasCapability::scene_cache) reports which backends record for real, so a caller can decide up front.

◆ renderer_backend()

virtual RendererBackend pulp::canvas::Canvas::renderer_backend ( ) const
inlinevirtualnoexcept

Identity of the renderer this canvas actually wraps.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ restore()

virtual void pulp::canvas::Canvas::restore ( )
pure virtual

◆ restore_to_count()

virtual void pulp::canvas::Canvas::restore_to_count ( int target)
inlinevirtual

Pop the save stack down to target (typically captured earlier via save_count()).

Backends that support it pop any leftover saves so an unbalanced JS draw script can't leak a ctx.save() into the parent View's paint scope. Default is a no-op so non-tracking backends keep their existing behavior; the CanvasWidget defense is meaningful only on backends that override both methods.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ rotate()

virtual void pulp::canvas::Canvas::rotate ( float radians)
pure virtual

◆ round_rect()

virtual void pulp::canvas::Canvas::round_rect ( float x,
float y,
float w,
float h,
float tl_x,
float tl_y,
float tr_x,
float tr_y,
float br_x,
float br_y,
float bl_x,
float bl_y )
inlinevirtual

Native rounded-rectangle subpath with per-corner radii.

Maps to Canvas2D ctx.roundRect(x, y, w, h, radii) and to SkRRect::MakeRectRadii on Skia. Radii layout matches the CSS 8-value form: top-left x/y, top-right x/y, bottom-right x/y, bottom-left x/y. The JS shim normalizes the 1/2/3/4-value forms to 8 floats before crossing the bridge.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ save()

virtual void pulp::canvas::Canvas::save ( )
pure virtual

◆ save_backdrop_filter()

virtual void pulp::canvas::Canvas::save_backdrop_filter ( float x,
float y,
float w,
float h,
float blur_radius )
inlinevirtual

CSS backdrop-filter: blur(Npx) — push a compositing layer whose initial contents are the parent surface filtered through a Gaussian blur of blur_radius.

Subsequent draws into this layer composite over the blurred backdrop. Must be paired with restore().

Skia maps to SkCanvas::saveLayer(SaveLayerRec{ .fBackdrop = Blur }). CPU/recording fallback is a plain save() so the matching restore() stays balanced — visual fidelity downgrades to an unblurred overlay.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ save_backdrop_filter_chain()

virtual void pulp::canvas::Canvas::save_backdrop_filter_chain ( float x,
float y,
float w,
float h,
const FilterChainEntry * chain,
int count )
inlinevirtual

CSS backdrop-filter with its full function list — saturate(0.2), brightness(2), invert(1), a grayscale(1) brightness(1.6) pair.

Same layer contract as save_backdrop_filter: the layer's initial contents are the parent surface run through the composed filter, and it must be paired with restore().

The default keeps exactly the behaviour every backend already had — blur entries summed, everything else dropped — so a backend that has not implemented the chain renders an unfiltered (or merely blurred) backdrop rather than an unbalanced canvas stack. Query CanvasCapability::backdrop_filter_chain to find out which you got.

◆ save_count()

virtual int pulp::canvas::Canvas::save_count ( ) const
inlinevirtual

Return the current save-stack depth.

Used by CanvasWidget::paint() to defend against JS-driven ctx.save() / ctx.restore() imbalance: snapshot the depth at paint entry, replay the queued commands, then restore_to_count(initial_depth) to drop any leftover saves. Mirrors SkCanvas::getSaveCount / CGContext save-stack depth. Default returns 0 — backends without an introspectable stack rely on the default restore_to_count no-op below to leave behavior unchanged.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ save_layer()

virtual void pulp::canvas::Canvas::save_layer ( float x,
float y,
float w,
float h,
float opacity = 1.0f,
float blur_radius = 0.0f )
inlinevirtual

Save a compositing layer.

All drawing until restore() is composited with the given opacity and optional blur. This is the correct way to implement CSS opacity and filter:blur() — the subtree paints into an offscreen buffer and is composited back as a single unit.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ save_layer_with_blend()

virtual void pulp::canvas::Canvas::save_layer_with_blend ( float x,
float y,
float w,
float h,
float opacity,
float blur_radius,
BlendMode mode )
inlinevirtual

Save a compositing layer with an explicit blend mode.

Used by CSS / RN mix-blend-mode: the subtree paints into the offscreen layer and the layer-paint composites back with the requested blend mode. Default BlendMode::normal is equivalent to the plain save_layer overload (kSrcOver). Subclasses that don't know how to honor the blend mode fall back to the plain overload.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ save_layer_with_bloom()

virtual void pulp::canvas::Canvas::save_layer_with_bloom ( float x,
float y,
float w,
float h,
float intensity,
float threshold,
float radius )
inlinevirtual

Save a compositing layer that applies a real bloom/glow post-effect to the subtree painted into it.

The layer content is thresholded (only pixels brighter than threshold contribute), blurred by radius, and additively composited (kPlus) back over the original — so bright regions bleed a glow beyond their edges. Restored by the matching restore().

Parameters
intensityglow gain applied to the thresholded highlights
thresholdbrightness cutoff in [0,1]; pixels below it don't glow
radiusblur radius (px) of the glow

The base implementation has no offscreen post-processing, so it degrades to a plain blurred layer (save_layer with radius * intensity blur) — the de-facto behavior effects had before a real bloom existed. Only the GPU backend (SkiaCanvas) implements the true threshold+blur+additive graph; RecordingCanvas records the bloom intent for headless assertions.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ save_layer_with_filters()

virtual void pulp::canvas::Canvas::save_layer_with_filters ( float x,
float y,
float w,
float h,
float opacity,
const FilterChainEntry * chain,
int count )
inlinevirtual

Reimplemented in pulp::canvas::RecordingCanvas.

◆ save_layer_with_mask()

virtual void pulp::canvas::Canvas::save_layer_with_mask ( float x,
float y,
float w,
float h,
float opacity,
const std::string & mask_image,
const std::string & mask_size )
inlinevirtual

CSS mask-image + mask-size paint slice.

Composes the subtree with a mask shader applied via SkBlendMode:: kDstIn so the painted result keeps only the alpha that the mask permits. The Pulp pipeline: saveLayer(opacity) <- subtree paint target ... subtree paints into the layer ... saveLayer(SkBlendMode::kDstIn) <- mask composite layer drawShader(mask_image, scaled by mask_size) restore() <- composes the mask alpha onto the subtree restore() <- composes the masked subtree to the parent

mask_image is the CSS value verbatim — typically linear-gradient(...), radial-gradient(...), url(...), or none. mask_size is the CSS mask-size value (auto | cover | contain | <length>{1,2}).

The matching restore() call drives the mask composite (the canvas tracks pending masks on its save stack). Subclasses that can't honor the mask fall back to the plain save_layer overload (no mask applied — matches the existing behavior for backends without shader support). Unrecognized / unparseable mask_image values also fall back to the no-mask path so authors don't lose their content to a parser error.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ save_layer_with_shader_effect()

virtual void pulp::canvas::Canvas::save_layer_with_shader_effect ( float x,
float y,
float w,
float h,
const std::string & effect_name,
float intensity )
inlinevirtual

Curated, named GPU post-effect layer save.

This is the SAFE shader-effect entry for scripted / generated UIs: the subtree paints into an offscreen layer, and at restore() the whole layer is post-processed by ONE of a small vetted set of SkSL effects selected BY NAME — never arbitrary shader source. Known names (see core/canvas/src/named_shader_effects.hpp): crt, grain, vignette, noise, brushed, bloom. intensity is the single 0..1 strength knob (clamped by the backend).

Unknown names, degenerate sizes, or a Skia/GPU-unavailable backend all degrade gracefully to a plain save_layer (effect skipped) so a generated UI can request an effect unconditionally and headless CPU renders never crash. The default impl here IS that fallback; only SkiaCanvas builds the runtime-effect image filter.

◆ save_layer_with_sksl_post_effect()

virtual bool pulp::canvas::Canvas::save_layer_with_sksl_post_effect ( float x,
float y,
float w,
float h,
const std::string & sksl,
const ShaderUniforms & uniforms,
float sample_radius = 0.0f,
const std::vector< NamedUniform > & extra_uniforms = {},
BlendMode blend_mode = BlendMode::normal )
inlinevirtual

Save a compositing layer whose ALREADY-PAINTED content is post-processed by a custom SkSL shader.

Unlike draw_with_sksl (which fills a fresh rect from a generative shader), this is a child-shader compositor: the subtree paints into the layer, then on restore() the shader runs over that content. The SkSL MUST declare uniform shader content; as its child — content.eval(xy) samples the subtree's rendered pixels — e.g. uniform shader content; half4 main(float2 xy) { return content.eval(xy).bgra; } // channel swap The same fixed uniform vocabulary as draw_with_sksl (resolution / value / time / accentColor / bgColor / trackColor / fillColor / thumbColor) is bound when declared, PLUS any arbitrary extra_uniforms (name → float/vec) the shader declares — guarded by findUniform, so unknown names are ignored.

blend_mode is how the finished post-effect layer composites back onto its parent (default source-over). BlendMode::lighter gives the additive audio-UI glow pattern.

sample_radius is the maximum distance (px) the shader may sample content.eval() away from the pixel being shaded — Skia needs this so a shader that reads neighboring texels (e.g. chromatic aberration's per-channel offset) gets valid samples near the layer edge instead of transparent black. Leave 0 for shaders that only read the current pixel.

Returns true when the shader was installed on the layer. Only the GPU backend (SkiaCanvas) implements it; the base falls back to a plain save_layer (still balanced — the subtree renders unfiltered) and returns false so callers can log the unsupported path once.

◆ scale()

virtual void pulp::canvas::Canvas::scale ( float sx,
float sy )
pure virtual

◆ sdf_feather_min_reach()

float pulp::canvas::Canvas::sdf_feather_min_reach ( const SDFStyle & style)
inlinestatic

The smallest draw-rect reach that holds style's feather: 3 sigma for the glow (1) and outer (3) modes, whose coverage lives outside the shape, and 0 for every other mode or a zero sigma.

Beyond 3 sigma the Gaussian falloff is under 0.15%, so a reach at or above this value never shows a hard edge where the draw rect ends.

◆ set_blend_mode()

virtual void pulp::canvas::Canvas::set_blend_mode ( BlendMode mode)
inlinevirtual

Set the compositing blend mode for subsequent draw operations.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_direction()

virtual void pulp::canvas::Canvas::set_direction ( TextDirection direction)
inlinevirtual

Reimplemented in pulp::canvas::RecordingCanvas.

◆ set_fill_color()

virtual void pulp::canvas::Canvas::set_fill_color ( Color c)
pure virtual

◆ set_fill_gradient_conic()

virtual void pulp::canvas::Canvas::set_fill_gradient_conic ( float cx,
float cy,
float start_angle,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Set a conic (sweep) gradient as the fill paint.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_fill_gradient_conic_repeating()

virtual void pulp::canvas::Canvas::set_fill_gradient_conic_repeating ( float cx,
float cy,
float start_angle,
float sweep_turns,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Set a REPEATING conic gradient (CSS repeating-conic-gradient).

The stop list spans sweep_turns of a full turn — positions are normalized to 0..1 across that band — and the band tiles around the circle.

Declared LAST, and as its own virtual rather than a wider set_fill_gradient_conic, on both of the usual grounds: a signature change would reorder this vtable under every prebuilt SDK consumer, and the Canvas2D command recorders would have to grow a field to carry the span. The default paints the band ONCE and clamps the rest, which is what a backend that cannot tile should show — recognisably the right colours in the wrong places, rather than nothing or a silent full-circle stretch.

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ set_fill_gradient_linear()

virtual void pulp::canvas::Canvas::set_fill_gradient_linear ( float x0,
float y0,
float x1,
float y1,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Set a linear gradient as the fill paint.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_fill_gradient_linear_repeating()

virtual void pulp::canvas::Canvas::set_fill_gradient_linear_repeating ( float x0,
float y0,
float x1,
float y1,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Set a REPEATING linear gradient (CSS repeating-linear-gradient).

The two points delimit ONE BAND rather than the whole box — positions are normalized to 0..1 across that band — and the band tiles along the gradient line in both directions.

Declared after the conic form above and for the same two reasons: a wider set_fill_gradient_linear would reorder this vtable under every prebuilt SDK consumer, and the Canvas2D command recorders would have to grow a field to carry the tile mode. The default paints the band ONCE and clamps the rest, which is what a backend that cannot tile should show — recognisably the right colours in the wrong places, rather than nothing or a silent stretch across the box.

◆ set_fill_gradient_radial()

virtual void pulp::canvas::Canvas::set_fill_gradient_radial ( float cx,
float cy,
float radius,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Set a radial gradient as the fill paint.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_fill_gradient_radial_elliptical()

virtual void pulp::canvas::Canvas::set_fill_gradient_radial_elliptical ( float cx,
float cy,
float rx,
float ry,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Radial gradient with an independent radius per axis — the ending shape CSS calls an ellipse, which is radial-gradient's DEFAULT shape and the only one a two-value size (90% 70%) can express.

Backends that can carry a local matrix on the shader override this; the default forwards to the circular overload using the horizontal radius, which is the pre-existing approximation rather than a blank fill.

◆ set_fill_gradient_radial_two_circles()

virtual void pulp::canvas::Canvas::set_fill_gradient_radial_two_circles ( float x0,
float y0,
float r0,
float x1,
float y1,
float r1,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Canvas2D ctx.createRadialGradient(x0,y0,r0,x1,y1,r1) two-circle form.

(x0,y0,r0) is the inner / start circle, (x1,y1,r1) is the outer / end circle. Backends with a real two-circle shader (Skia MakeTwoPointConical, CG CGContextDrawRadialGradient) override; the default forwards to the single-circle overload using the outer circle so older fallbacks still get a usable gradient.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_fill_pattern()

virtual void pulp::canvas::Canvas::set_fill_pattern ( const std::string & image_src,
PatternTileMode tile_x,
PatternTileMode tile_y )
inlinevirtual

Set an image pattern as the fill paint.

image_src is a file path or data: URL — same identifier shape draw_image_from_file consumes, so backends share one decode path. Default is no-op so CPU-only / minimal canvases compile; SkiaCanvas overrides with a real SkShader::MakeImage. Empty image_src clears any active pattern (mirrors clear_fill_gradient's reset semantics).

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_filter()

virtual void pulp::canvas::Canvas::set_filter ( const std::string & filter)
inlinevirtual

Canvas2D ctx.filter.

Sticky CSS <filter-function-list> string applied to subsequent fill / stroke / text / image draws. Spec supports: blur, brightness, contrast, drop-shadow, grayscale, hue-rotate, invert, opacity, saturate, sepia. The default is "none". SkiaCanvas parses the string into an SkImageFilter chain and applies via SkPaint::setImageFilter; CG and other backends can store the value but render unfiltered. RecordingCanvas captures the raw string. Distinct from CSS filter on a View: that filter applies to the View element, this one applies to the per-context Canvas2D paints inside it.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ set_font()

virtual void pulp::canvas::Canvas::set_font ( const std::string & family,
float size )
pure virtual

◆ set_font_features()

virtual void pulp::canvas::Canvas::set_font_features ( std::vector< FontFeature > features)
inlinevirtual

◆ set_font_full()

virtual void pulp::canvas::Canvas::set_font_full ( const std::string & family,
float size,
int weight,
int slant,
float letter_spacing )
inlinevirtual

Richer font setter that propagates CSS font-weight (100..900), font-slant (0=upright, 1=italic), and letter-spacing (px between glyphs) through to the backend.

Default implementation forwards to the legacy set_font(family, size) so non-Label callers keep working unchanged. Backends that honor these properties (Skia, CoreText, RecordingCanvas) override this to capture or apply them. Label widget honors setFontFamily / setFontWeight / setLetterSpacing from JS.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_font_smoothing()

virtual void pulp::canvas::Canvas::set_font_smoothing ( FontSmoothing smoothing)
inlinevirtual

CSS -webkit-font-smoothing for the text drawn and measured after it.

antialiased turns glyph hinting off, which with a chromium surface (pulp/canvas/text_raster_policy.hpp) reproduces Chromium's antialiased glyphs; auto keeps the default light hinting. Scoped by save()/restore() like the clip and matrix. Skia, CoreGraphics and RecordingCanvas implement it; the default ignores it.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_gradient_interpolation()

virtual void pulp::canvas::Canvas::set_gradient_interpolation ( GradientInterpolation m)
inlinevirtual

Colour space every LATER gradient setter blends its stops in (CSS <color-interpolation-method>), until set again; save() does not keep it.

Appended for the vtable. Skia blends natively, CoreGraphics resamples.

Reimplemented in pulp::canvas::RecordingCanvas.

◆ set_image_smoothing()

virtual void pulp::canvas::Canvas::set_image_smoothing ( bool enabled,
ImageSmoothingQuality quality = ImageSmoothingQuality::low )
inlinevirtual

Canvas2D ctx.imageSmoothingEnabled + imageSmoothingQuality.

Sticky paint flag honored by subsequent drawImage calls. When enabled is false the backend uses nearest-neighbor sampling; when true the quality enum picks the resampler. Default no-op so backends without smoothing support compile; SkiaCanvas (SkSamplingOptions) and CoreGraphicsCanvas (CGContextSetInterpolationQuality) override. RecordingCanvas captures a set_image_smoothing command for tests.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_line_cap()

virtual void pulp::canvas::Canvas::set_line_cap ( LineCap cap)
pure virtual

◆ set_line_dash()

virtual void pulp::canvas::Canvas::set_line_dash ( const float * intervals,
int count,
float phase = 0.0f )
inlinevirtual

Set the line dash pattern for stroke operations.

Mirrors CanvasRenderingContext2D.setLineDash(). intervals alternate "on" / "off" lengths in pixels. An empty pattern (count == 0) clears the dash and reverts to solid strokes. HTML5 spec: an odd-length pattern is duplicated to even length; callers that want spec compliance must duplicate before invoking this method (the JS bridge does so). Default no-op for backends without dash support.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_line_join()

virtual void pulp::canvas::Canvas::set_line_join ( LineJoin join)
pure virtual

◆ set_line_width()

virtual void pulp::canvas::Canvas::set_line_width ( float w)
pure virtual

◆ set_miter_limit()

virtual void pulp::canvas::Canvas::set_miter_limit ( float limit)
inlinevirtual

Canvas2D ctx.miterLimit.

Sticky stroke state — controls when a miter join collapses to a bevel (Skia / CG default = 10). Spec requires non-finite or non-positive values to be silently ignored; callers that want spec semantics should clamp at the JS bridge. Default no-op so backends without miter-limit support compile; SkiaCanvas (SkPaint::setStrokeMiter) and CoreGraphicsCanvas (CGContextSetMiterLimit) override. RecordingCanvas captures a set_miter_limit command for tests.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_opacity()

virtual void pulp::canvas::Canvas::set_opacity ( float alpha)
inlinevirtual

Set global alpha for subsequent drawing operations (0.0-1.0).

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ set_shadow_blur()

virtual void pulp::canvas::Canvas::set_shadow_blur ( float blur)
inlinevirtual

◆ set_shadow_color()

virtual void pulp::canvas::Canvas::set_shadow_color ( Color color)
inlinevirtual

Sticky drop-shadow state that wraps subsequent draw operations, matching the CanvasRenderingContext2D shadowColor / shadowBlur / shadowOffsetX / shadowOffsetY properties.

The shadow renders only when color.a > 0 AND (blur > 0 OR offset_x != 0 OR offset_y != 0) — same gate Chromium / WebKit use. Setting color to fully transparent (alpha == 0) effectively disables the shadow even if blur/offset are non-zero, mirroring spec semantics.

Backends that draw via SkPaint / CGContext layer the shadow onto the next draw call by configuring an image filter (Skia DropShadow) or CGContextSetShadowWithColor respectively. The default implementation here is a no-op so backends that haven't opted into shadow support compile unchanged; SkiaCanvas, CoreGraphicsCanvas, and RecordingCanvas override to actually honor (or capture) the state.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_shadow_offset_x()

virtual void pulp::canvas::Canvas::set_shadow_offset_x ( float dx)
inlinevirtual

◆ set_shadow_offset_y()

virtual void pulp::canvas::Canvas::set_shadow_offset_y ( float dy)
inlinevirtual

◆ set_stroke_color()

virtual void pulp::canvas::Canvas::set_stroke_color ( Color c)
pure virtual

◆ set_stroke_gradient_conic()

virtual void pulp::canvas::Canvas::set_stroke_gradient_conic ( float cx,
float cy,
float start_angle,
const Color * colors,
const float * positions,
int count )
inlinevirtual

◆ set_stroke_gradient_linear()

virtual void pulp::canvas::Canvas::set_stroke_gradient_linear ( float x0,
float y0,
float x1,
float y1,
const Color * colors,
const float * positions,
int count )
inlinevirtual

◆ set_stroke_gradient_radial()

virtual void pulp::canvas::Canvas::set_stroke_gradient_radial ( float cx,
float cy,
float radius,
const Color * colors,
const float * positions,
int count )
inlinevirtual

◆ set_stroke_gradient_radial_two_circles()

virtual void pulp::canvas::Canvas::set_stroke_gradient_radial_two_circles ( float x0,
float y0,
float r0,
float x1,
float y1,
float r1,
const Color * colors,
const float * positions,
int count )
inlinevirtual

Two-circle radial gradient on stroke (mirrors fill counterpart).

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_stroke_pattern()

virtual void pulp::canvas::Canvas::set_stroke_pattern ( const std::string & image_src,
PatternTileMode tile_x,
PatternTileMode tile_y )
inlinevirtual

Stroke counterpart.

Rare in production code; default no-op. SkiaCanvas overrides via the same SkShader::MakeImage path applied to the stroke paint.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ set_text_align()

virtual void pulp::canvas::Canvas::set_text_align ( TextAlign align)
pure virtual

◆ set_transform()

virtual void pulp::canvas::Canvas::set_transform ( float a,
float b,
float c,
float d,
float e,
float f )
inlinevirtual

Replace the current transform with the affine matrix [ a c e ] [ b d f ] [ 0 0 1 ] Mirrors CanvasRenderingContext2D.setTransform(a, b, c, d, e, f).

Default implementation is a no-op so non-GPU backends still compile; SkiaCanvas overrides to compose the supplied matrix onto the paint baseline captured via capture_paint_baseline_transform().

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ sksl_declares_uniform()

bool pulp::canvas::Canvas::sksl_declares_uniform ( const std::string & sksl,
const std::string & uniform_name )
static

Whether an SkSL shader declares a uniform of the given name.

Compiles via the same process-lifetime cache as compile_sksl, so repeat queries are free; false if the source does not compile.

Used to decide whether a shader is time-driven and needs continuous repaint. Not a substring search: a timeline uniform must not pin the render loop, and a differently-spelled one must not silently freeze.

◆ stroke_arc()

virtual void pulp::canvas::Canvas::stroke_arc ( float cx,
float cy,
float radius,
float start_angle,
float end_angle )
pure virtual

◆ stroke_circle()

virtual void pulp::canvas::Canvas::stroke_circle ( float cx,
float cy,
float radius )
pure virtual

◆ stroke_current_path()

virtual void pulp::canvas::Canvas::stroke_current_path ( )
inlinevirtual

Stroke the current path.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ stroke_line()

virtual void pulp::canvas::Canvas::stroke_line ( float x0,
float y0,
float x1,
float y1 )
pure virtual

◆ stroke_path() [1/2]

virtual void pulp::canvas::Canvas::stroke_path ( const Path & path,
const StrokeStyle & style )
inlinevirtual

Stroke path with style.

Unlike the set_line_width / set_line_cap / set_line_join triplet, the whole stroke configuration arrives as one value and cannot be half-applied.

NOTE the default fallback mutates the canvas's stroke state (width / cap / join / dash) and does not restore it, because the immediate-mode API has no way to read the previous values back. Backends that override this — Skia and CoreGraphics both do — keep the style local to the one draw. Callers that care should save()/restore() around it.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ stroke_path() [2/2]

virtual void pulp::canvas::Canvas::stroke_path ( const Point2D * points,
size_t count )
inlinevirtual

Stroke a continuous polyline — much smoother than individual stroke_line calls.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ stroke_rect()

virtual void pulp::canvas::Canvas::stroke_rect ( float x,
float y,
float w,
float h )
pure virtual

◆ stroke_rounded_rect()

virtual void pulp::canvas::Canvas::stroke_rounded_rect ( float x,
float y,
float w,
float h,
float radius )
pure virtual

◆ stroke_text()

virtual void pulp::canvas::Canvas::stroke_text ( const std::string & text,
float x,
float y,
float max_width = 0.0f )
inlinevirtual

Canvas2D strokeText(text, x, y, maxWidth) spec form.

True outlined-glyph rendering: builds a stroked paint (SkPaint::kStroke_Style on Skia, CG text drawing mode kCTLineDrawingModeStroke on CoreGraphics) so the glyph outlines honor the current lineWidth / strokeStyle. The default implementation degrades to fill_text with the stroke color pre-set by the caller — visually approximate but spec-incompatible. Backends override to render real glyph outlines. max_width semantics match fill_text_with_max_width.

Reimplemented in pulp::canvas::CoreGraphicsCanvas, and pulp::canvas::RecordingCanvas.

◆ supports()

virtual bool pulp::canvas::Canvas::supports ( CanvasCapability ) const
inlinevirtual

Report whether this backend renders cap's verb faithfully.

Base returns false for everything: the base-class verb defaults are all degradations (silent no-op, color/mask/blur op dropped, filename placeholder). Concrete backends override to advertise the subset they actually implement. Callers branch on this to log-once and keep the documented fallback rather than silently emitting an unfaithful frame.

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ supports_image_draw()

bool pulp::canvas::Canvas::supports_image_draw ( ) const
inline

Whether this backend can actually decode + draw a raster image (the draw_image_from_* verbs below).

Thin alias for supports(CanvasCapability::images) — kept because it is public API used by headless tooling (ImageView placeholder path, CG image tests). Not virtual: backends express image support through supports(), and this forwards to it so there is one vocabulary and one source of truth.

◆ text_x_for_byte()

virtual float pulp::canvas::Canvas::text_x_for_byte ( const std::string & text,
std::size_t byte_index )
inlinevirtual

Caret x (in text-local space, measured from the text's leading edge) for the glyph boundary at byte_index within text.

This is the drift-proof companion to measure_text: it shapes the FULL run with the current font state (family / size / weight / slant / letter-spacing / direction / features) and returns the caret offset for the cluster boundary at byte_index, so a kerned pair like "AV" reports the same advance the painter actually draws — not the sum of isolated glyph widths.

The default implementation measures the prefix substring, which is correct for unkerned, unspaced text but drifts on kerned runs. The Skia backend overrides this to query the shaped paragraph directly.

Reimplemented in pulp::canvas::CoreGraphicsCanvas.

◆ translate()

virtual void pulp::canvas::Canvas::translate ( float x,
float y )
pure virtual

◆ write_pixels()

virtual bool pulp::canvas::Canvas::write_pixels ( const uint8_t * data,
int width,
int height,
int dx,
int dy )
inlinevirtual

Write RGBA pixels (data size = width*height*4) to the current surface at destination (dx, dy).

Returns true on success. Mirrors CanvasRenderingContext2D.putImageData().

Reimplemented in pulp::canvas::RecordingCanvas.

Member Data Documentation

◆ font_size_

float pulp::canvas::Canvas::font_size_ = 14.0f
protected

Current font size (set by set_font).


The documentation for this class was generated from the following file:
  • /home/runner/work/pulp/pulp/core/canvas/include/pulp/canvas/canvas.hpp