Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
recording_canvas.hpp
Go to the documentation of this file.
1#pragma once
2
3// RecordingCanvas: a Canvas that captures draw commands instead of rendering,
4// for inspection and tests. canvas.hpp includes this header at its tail, so
5// existing consumers keep compiling unchanged; new code should include this
6// header directly.
7
9
10namespace pulp::canvas {
11
12// ── Recording canvas ─────────────────────────────────────────────────────────
13// Captures draw commands for inspection/testing
14// Does not actually render anything
15
17 // A hand-aligned table: clang-format would re-flow every row of it.
18 // clang-format off
19 enum class Type {
29 // Canvas2D `strokeText(text, x, y, maxWidth)` records
30 // a distinct cmd so tests can assert that the bridge routed the
31 // call through the dedicated stroke_text path (rather than the
32 // fillText-with-stroke-color approximation). Layout
33 // matches fill_text: text in `text`, (x,y) in f[0..1], optional
34 // maxWidth in f[2] (<=0 = no limit).
36 // Full font setter: family in `text`, size/weight/slant/
37 // letter_spacing in f[0..3]. Emitted alongside (in addition to) the
38 // legacy set_font command so existing tests that count set_font
39 // continue to pass.
41 // ── Canvas2D API coverage ────────────────────────────────────
45 // ── setBoxShadow / draw_box_shadow ──────────────────────────
47 // ── Canvas2D shadow* state setters ──────────────────────────
48 // Sticky state changes; the recording target captures one cmd
49 // per setter so tests can assert on the bridge's flush order.
54 // ── Canvas2D state setters ──────────────────────────────────
55 // Sticky stroke / image state. Captured one cmd per setter so
56 // the canvas2d bridge harness can assert flush order.
60 // Canvas2D ctx.direction / ctx.filter sticky setters.
61 // Direction enum (0=ltr, 1=rtl, 2=inherit) packed into f[0];
62 // filter raw CSS <filter-function-list> string (e.g.
63 // "blur(5px) sepia(80%)") in `text`. RecordingCanvas captures
64 // each setter so tests can assert the JS shim flushed the
65 // sticky state before the next text/image/fill draw.
68 // Canvas2D ctx.createPattern.
69 // image source path / data URI in `text`, tile modes packed into
70 // f[0] (x) and f[1] (y) — 0 = repeat, 1 = no_repeat.
73 // Canvas2D `ctx.strokeStyle =
74 // createLinearGradient(...) | createRadialGradient(...) |
75 // createConicGradient(...)`. Mirrors the fill-side gradient cmds
76 // so canvas2d harness tests can assert that the bridge plumbed
77 // the stroke-gradient setter at the right point in the stream.
78 // Layout matches the fill counterparts: linear (x0,y0)→(x1,y1)
79 // packed as f[0..3]; radial (cx,cy,r) as (f[0],f[1],f[2]); conic
80 // (cx,cy,startAngle) as (f[0],f[1],f[2]); two-circle (x0,y0,r0,
81 // x1,y1,r1) as (f[0]..f[5]). Stops in `floats` interleaved as
82 // [pos0, r0, g0, b0, a0, pos1, r1, g1, b1, a1, ...] — same shape
83 // RecordingCanvas already uses for fill gradients.
89 // ── FILL gradients ──────────────────────────────────────────
90 // The stroke-side gradient commands above existed without these
91 // fill-side counterparts, so RecordingCanvas silently dropped every
92 // `set_fill_gradient_*` call: a headless test that set a fill
93 // gradient and asserted on the result was really asserting on the
94 // last solid `set_fill_color`, and would keep passing if the
95 // gradient plumbing broke entirely. Layout mirrors the stroke
96 // commands exactly — linear (x0,y0)→(x1,y1) in f[0..3]; radial
97 // (cx,cy,r) in f[0..2]; conic (cx,cy,startAngle) in f[0..2];
98 // two-circle (x0,y0,r0,x1,y1,r1) in f[0..5]; stops interleaved in
99 // `floats` as [pos, r, g, b, a, ...].
105 // ── Retained Path draws ─────────────────────────────────────
106 // The path's geometry is captured as an SVG `d` string in `text`
107 // (so a test can assert on the exact geometry without walking a
108 // command stream), and the fill rule / stroke style in `f`.
113 // ── Retained compositing LAYERS (handle-based) ──────────────
114 // begin/end bracket the recording of a layer; draw_layer composites
115 // a sealed one. The handle id is captured in f[0] so a test can
116 // assert that the SAME layer was reused across frames rather than
117 // silently re-recorded.
124 // ── save_backdrop_filter for frosted-glass overlays ─────────
126 // ── CSS clip-path: path("...") ──────────────────────────────
127 // Recording target captures the SVG-path-d string in `text` so
128 // tests can assert that View::paint_all installs the clip
129 // before painting children. Skia parses via SkParsePath /
130 // SkPath::FromSVGString; backends without a path parser
131 // degrade to a no-op (no clip applied).
133 // ── real clearRect that replaces pixels ─────────────────────
135 // ── Canvas2D path API recording ─────────────────────────────
136 // Captured so widgets that emit path commands (SvgPathWidget,
137 // CanvasWidget JS path-replays) can be asserted at the
138 // command-stream level without a Skia raster surface.
147 // ── native arc subpaths ─
148 // Captured so widgets that emit native arc commands can be
149 // asserted at the command-stream level without a Skia raster
150 // surface. Maps 1:1 to the new Canvas::arc / arc_to / ellipse /
151 // round_rect virtual methods.
156 // ── Compositing layer saves (save_layer family) ─────────────
157 // Before these existed, RecordingCanvas inherited the base
158 // save_layer* methods, which all collapse to a bare save(). A
159 // recording therefore could not distinguish an opacity / filter /
160 // blend / mask compositing layer from a plain save() — which is
161 // exactly why the effect facades (bloom/vignette/chromatic) went
162 // undetected by command-stream tests. Each of these records the
163 // layer intent, and its RecordingCanvas override still increments
164 // the save stack by exactly one so save_count() balance holds.
170 // Custom SkSL draw recorded as intent. The base draw_with_sksl
171 // fills a CPU placeholder rect and returns false; RecordingCanvas
172 // instead captures the shader source + rect and returns false
173 // (a recorder cannot compile/execute SkSL). Callers that test the
174 // base CPU fallback must invoke `rc.Canvas::draw_with_sksl(...)`.
177 };
178 // clang-format on
179
181 // Generic storage for command parameters
182 float f[6] = {};
184 std::string text;
185 // Optional variable-length payload — used by set_line_dash and
186 // write_pixels (which store raw bytes packed as floats / characters
187 // respectively). Kept off the default cmd to avoid bloating the
188 // happy path.
189 std::vector<float> floats;
190};
191
192class RecordingCanvas : public Canvas {
193public:
194 RendererBackend renderer_backend() const noexcept override {
196 }
197 const std::vector<DrawCommand>& commands() const { return commands_; }
198 void clear() { commands_.clear(); }
199 size_t command_count() const { return commands_.size(); }
200
201 // Count commands of a specific type
202 size_t count(DrawCommand::Type type) const;
203
204 // Number of times capture_paint_baseline_transform() was called — useful
205 // for asserting CanvasWidget::paint() snapshots the inbound device matrix
206 // exactly once at entry.
207 size_t baseline_capture_count() const { return baseline_capture_count_; }
208
209 void save() override;
210 void restore() override;
211 int save_count() const override { return save_depth_; }
212 void restore_to_count(int target) override;
213 void translate(float x, float y) override;
214 void scale(float sx, float sy) override;
215 void rotate(float radians) override;
216 void set_transform(float a, float b, float c,
217 float d, float e, float f) override;
219 void concat_transform(float a, float b, float c,
220 float d, float e, float f) override;
222 void clip_rect(float x, float y, float w, float h) override;
223 void clip(FillRule rule = FillRule::nonzero) override;
224 void clip_path_svg(const std::string& svg_path_d) override;
225 void set_blend_mode(BlendMode mode) override;
226 void set_fill_color(Color c) override;
227 void set_stroke_color(Color c) override;
228 void set_line_width(float w) override;
229 void set_line_cap(LineCap cap) override;
230 void set_line_join(LineJoin join) override;
231 void fill_rect(float x, float y, float w, float h) override;
232 void clear_rect(float x, float y, float w, float h) override;
233 void stroke_rect(float x, float y, float w, float h) override;
234 void fill_rounded_rect(float x, float y, float w, float h, float radius) override;
235 void stroke_rounded_rect(float x, float y, float w, float h, float radius) override;
236 void fill_circle(float cx, float cy, float radius) override;
237 void stroke_circle(float cx, float cy, float radius) override;
238 void stroke_arc(float cx, float cy, float radius,
239 float start_angle, float end_angle) override;
240 void stroke_line(float x0, float y0, float x1, float y1) override;
241 void set_font(const std::string& family, float size) override;
242 void set_font_full(const std::string& family, float size,
243 int weight, int slant, float letter_spacing) override;
244 void set_text_align(TextAlign align) override;
245 void fill_text(const std::string& text, float x, float y) override;
246 // Canvas2D fillText(text,x,y,maxWidth) + strokeText.
247 // The recording target captures `max_width` in `f[2]` so harness
248 // tests can assert the bridge plumbed the optional fourth arg
249 // through. `<=0` is the spec sentinel for "no constraint".
250 void fill_text_with_max_width(const std::string& text,
251 float x, float y, float max_width) override;
252 void stroke_text(const std::string& text, float x, float y,
253 float max_width = 0.0f) override;
254 float measure_text(const std::string& text) override;
255
256 // Capture Canvas2D API commands so JS-driven tests can assert
257 // on them via DrawCommand::Type::set_line_dash / draw_image /
258 // write_pixels. Source path is stored in DrawCommand::text.
259 void set_line_dash(const float* intervals, int count, float phase) override;
260 // Capture the opaque-handle image draw so the image transform / fit / tile
261 // helpers are assertable headlessly. Records a `draw_image` command with
262 // the destination rect in f[0..3] and an EMPTY `text` (file / data draws
263 // put the source in `text`, so empty text distinguishes a handle draw).
264 void draw_image(void* native_handle,
265 float x, float y, float w, float h) override;
266 bool draw_image_from_data(const uint8_t* data, size_t size,
267 float x, float y, float w, float h) override;
268 bool draw_image_from_file(const std::string& path,
269 float x, float y, float w, float h) override;
270 // Record the source-rect overload so widget-bridge tests
271 // can assert that the JS shim plumbed sx/sy/sw/sh through the bridge.
272 // Source rect is stored in `floats[0..3]` (sx, sy, sw, sh); dst rect
273 // stays in f[0..3] for backward-compat with the 5-arg test path.
274 bool draw_image_from_file_rect(const std::string& path,
275 float sx, float sy, float sw, float sh,
276 float dx, float dy, float dw, float dh) override;
277 bool draw_image_from_data_rect(const uint8_t* data, size_t size,
278 float sx, float sy, float sw, float sh,
279 float dx, float dy, float dw, float dh) override;
280 bool write_pixels(const uint8_t* data, int width, int height,
281 int dx, int dy) override;
282 void save_backdrop_filter(float x, float y, float w, float h,
283 float blur_radius) override;
284
285 // ── Compositing layer saves (save_layer family) ──────────────────────
286 // Record the layer intent as a distinct command (see the DrawCommand::Type
287 // comments) instead of the base-class collapse to a bare save(). Each
288 // increments the save stack by exactly one, so a save_layer / restore pair
289 // stays balanced against save_count() just like the base backends.
290 void save_layer(float x, float y, float w, float h,
291 float opacity = 1.0f, float blur_radius = 0.0f) override;
292 void save_layer_with_blend(float x, float y, float w, float h,
293 float opacity, float blur_radius,
294 BlendMode mode) override;
295 void save_layer_with_filters(float x, float y, float w, float h,
296 float opacity,
297 const FilterChainEntry* chain,
298 int count) override;
299 void save_layer_with_mask(float x, float y, float w, float h,
300 float opacity,
301 const std::string& mask_image,
302 const std::string& mask_size) override;
303 void save_layer_with_bloom(float x, float y, float w, float h,
304 float intensity, float threshold,
305 float radius) override;
306
307 // Record a custom SkSL draw as intent and return true — the recorder
308 // accepted and captured the draw (the success path). This lets a headless
309 // test assert that an effect / widget routed a shader draw through the
310 // canvas without a GPU, and keeps shader widgets on the shader path rather
311 // than recording their C++ fallback body (see draw_custom_shader_body).
312 bool draw_with_sksl(const std::string& sksl, float x, float y,
313 float w, float h,
314 const ShaderUniforms& uniforms) override;
315
316 // Capture a single box-shadow command so JS-driven tests
317 // can assert on inset / color / offsets without having to walk the
318 // CPU-fallback rectangle stack.
319 void draw_box_shadow(float x, float y, float w, float h,
320 float dx, float dy, float blur, float spread,
321 Color color, bool inset, float corner_radius) override;
322
323 // ── FILL gradients ───────────────────────────────────────────────────
324 // Previously unrecorded: the base-class no-ops swallowed these, so a
325 // headless fill-gradient test was really asserting on the last solid
326 // fill color. See the DrawCommand::Type comment.
327 void set_fill_gradient_linear(float x0, float y0, float x1, float y1,
328 const Color* colors, const float* positions,
329 int count) override;
330 void set_fill_gradient_radial(float cx, float cy, float radius,
331 const Color* colors, const float* positions,
332 int count) override;
334 float x0, float y0, float r0, float x1, float y1, float r1,
335 const Color* colors, const float* positions, int count) override;
336 void set_fill_gradient_conic(float cx, float cy, float start_angle,
337 const Color* colors, const float* positions,
338 int count) override;
339 void clear_fill_gradient() override;
341
342 // ── Retained paths ───────────────────────────────────────────────────
343 // `using` re-exposes the base-class polygon overloads: declaring
344 // fill_path(const Path&) here would otherwise HIDE
345 // fill_path(const Point2D*, size_t) for anyone holding a RecordingCanvas&.
346 using Canvas::fill_path;
348 void fill_path(const Path& path, FillRule rule = FillRule::nonzero) override;
349 void stroke_path(const Path& path, const StrokeStyle& style) override;
350 void clip_path(const Path& path, FillRule rule = FillRule::nonzero) override;
351 void draw_path_shadow(const Path& path, float dx, float dy,
352 float blur, float spread, Color color) override;
353
354 // ── Retained layers ──────────────────────────────────────────────────
355 // The recording target models layer lifetime for real (it hands out ids,
356 // tracks which are sealed, and honours invalidate), so a test can assert
357 // that a cacheable layer SURVIVES ACROSS FRAMES without needing a GPU.
358 LayerHandle begin_layer(Rect2D bounds, bool cacheable = false) override;
360 void draw_layer(LayerHandle layer, float alpha = 1.0f,
361 BlendMode mode = BlendMode::normal) override;
362 void draw_layer_fitted(LayerHandle layer, Rect2D dest) override;
363 void draw_layer_rotated(LayerHandle layer, float angle_rad) override;
364 bool layer_valid(LayerHandle layer) const override;
365 void invalidate_layer(LayerHandle layer) override;
366
367 // Capture sticky Canvas2D shadow state setters
368 // so tests can assert that JS `ctx.shadowColor = ...; ctx.shadowBlur =
369 // ...; ctx.fillRect(...)` flushes the shadow state through to the
370 // canvas before the geometry is recorded.
372 void set_shadow_blur(float blur) override;
373 void set_shadow_offset_x(float dx) override;
374 void set_shadow_offset_y(float dy) override;
375
376 // Capture sticky stroke / image
377 // state so tests can assert that JS `ctx.miterLimit = ...` and
378 // `ctx.imageSmoothingEnabled = ...` flush through to the canvas
379 // before the next geometry is recorded.
380 void set_miter_limit(float limit) override;
381 void set_image_smoothing(bool enabled,
382 ImageSmoothingQuality quality) override;
383 void set_font_smoothing(FontSmoothing smoothing) override;
384
385 // Canvas2D ctx.direction / ctx.filter capture.
386 void set_direction(TextDirection direction) override;
387 void set_filter(const std::string& filter) override;
388
389 // Capture pattern setter intents
390 // so canvas2d harness tests can assert flush order without needing
391 // a real raster surface or decoded image.
392 void set_fill_pattern(const std::string& image_src,
393 PatternTileMode tile_x,
394 PatternTileMode tile_y) override;
395 void set_stroke_pattern(const std::string& image_src,
396 PatternTileMode tile_x,
397 PatternTileMode tile_y) override;
398
399 // Capture stroke-gradient setter intents so the
400 // canvas2d harness can assert the bridge plumbed `ctx.strokeStyle =
401 // createLinearGradient(...)` (etc.) end-to-end. Stops are flattened
402 // into `floats` as [pos0, r0, g0, b0, a0, pos1, r1, g1, b1, a1, ...]
403 // — same shape as set_line_dash but per-stop instead of per-interval.
404 void set_stroke_gradient_linear(float x0, float y0, float x1, float y1,
405 const Color* colors, const float* positions,
406 int count) override;
407 void set_stroke_gradient_radial(float cx, float cy, float radius,
408 const Color* colors, const float* positions,
409 int count) override;
411 float x0, float y0, float r0,
412 float x1, float y1, float r1,
413 const Color* colors, const float* positions, int count) override;
414 void set_stroke_gradient_conic(float cx, float cy, float start_angle,
415 const Color* colors, const float* positions,
416 int count) override;
417 void clear_stroke_gradient() override;
418
419 // Canvas2D path API recording. Each call appends one
420 // DrawCommand so widget tests can assert on emit order and shape
421 // without needing a real raster surface. Pure capture; no geometry
422 // is computed.
423 void begin_path() override;
424 void move_to(float x, float y) override;
425 void line_to(float x, float y) override;
426 void quad_to(float cpx, float cpy, float x, float y) override;
427 void cubic_to(float cp1x, float cp1y, float cp2x, float cp2y,
428 float x, float y) override;
429 void close_path() override;
431 void stroke_current_path() override;
432
433 // Native arc subpaths (recorded as DrawCommands so
434 // widget tests can assert emit order without a raster surface).
435 void arc(float cx, float cy, float radius,
436 float start_angle, float end_angle,
437 bool anticlockwise) override;
438 void arc_to(float x1, float y1, float x2, float y2,
439 float radius) override;
440 void ellipse(float cx, float cy, float rx, float ry,
441 float rotation,
442 float start_angle, float end_angle,
443 bool anticlockwise) override;
444 void round_rect(float x, float y, float w, float h,
445 float tl_x, float tl_y,
446 float tr_x, float tr_y,
447 float br_x, float br_y,
448 float bl_x, float bl_y) override;
449
450private:
451 std::vector<DrawCommand> commands_;
452 size_t baseline_capture_count_ = 0;
453 // Track save/restore depth so RecordingCanvas can model
454 // the same save_count() / restore_to_count() contract as the live
455 // backends. This lets CanvasWidget::paint() unit tests assert that the
456 // outer save/restore wrapper drops any leftover saves emitted by an
457 // unbalanced JS draw script.
458 int save_depth_ = 0;
459 // Track the current device matrix so
460 // current_transform() returns a faithful CTM in unit tests. The matrix
461 // is saved/restored alongside save_depth_, and translate/scale/rotate/
462 // set_transform/concat_transform mutate it. Layout in column-major
463 // CanvasRenderingContext2D order: [a, b, c, d, e, f].
464 AffineTransform2x3 ctm_{};
465 std::vector<AffineTransform2x3> ctm_stack_;
466
467 // ── Layer bookkeeping ────────────────────────────────────────────────
468 // Modeled faithfully (not stubbed) so that "does this layer survive to
469 // the next frame?" is testable headlessly. A cacheable layer stays valid
470 // until it is explicitly invalidated; a non-cacheable one is dropped as
471 // soon as it is drawn, which is exactly the contract the GPU backends
472 // implement with real textures.
473 struct LayerRecord {
474 Rect2D bounds;
475 bool cacheable = false;
476 bool sealed = false;
477 };
478 std::vector<std::pair<uint64_t, LayerRecord>> layers_;
479 std::vector<uint64_t> open_layers_;
480 uint64_t next_layer_id_ = 1;
481
482 LayerRecord* find_layer(uint64_t id);
483 const LayerRecord* find_layer(uint64_t id) const;
484};
485
486} // namespace pulp::canvas
Definition canvas.hpp:240
TextDirection
Canvas2D ctx.direction.
Definition canvas.hpp:1571
BlendMode
Indices 0..15 match the existing W3C "advanced" composite ops and must stay stable — set_blend_mode i...
Definition canvas.hpp:527
@ color
Definition canvas.hpp:531
@ normal
Definition canvas.hpp:529
virtual void stroke_path(const Point2D *points, size_t count)
Stroke a continuous polyline — much smoother than individual stroke_line calls.
Definition canvas.hpp:685
ImageSmoothingQuality
Canvas2D image-smoothing quality enum.
Definition canvas.hpp:382
virtual void fill_path(const Point2D *points, size_t count, FillRule rule=FillRule::nonzero)
Fill a closed polygon defined by points, honoring rule.
Definition canvas.hpp:712
PatternTileMode
Canvas2D ctx.createPattern.
Definition canvas.hpp:497
Definition path.hpp:87
Definition recording_canvas.hpp:192
void set_shadow_color(Color color) override
Sticky drop-shadow state that wraps subsequent draw operations, matching the CanvasRenderingContext2D...
void set_stroke_gradient_radial(float cx, float cy, float radius, const Color *colors, const float *positions, int count) override
void restore_to_count(int target) override
Pop the save stack down to target (typically captured earlier via save_count()).
void close_path() override
Close the current path subpath.
void set_stroke_gradient_linear(float x0, float y0, float x1, float y1, const Color *colors, const float *positions, int count) override
LayerHandle end_layer() override
Seal the layer opened by the last begin_layer() and return its handle.
LayerHandle begin_layer(Rect2D bounds, bool cacheable=false) override
Begin recording into an offscreen layer covering bounds (in current user space).
void cubic_to(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) override
Add a cubic bezier curve.
void stroke_current_path() override
Stroke the current path.
void set_image_smoothing(bool enabled, ImageSmoothingQuality quality) override
Canvas2D ctx.imageSmoothingEnabled + imageSmoothingQuality.
void concat_transform(float a, float b, float c, float d, float e, float f) override
Concat (multiply) the supplied affine matrix onto the current transform — does NOT replace it.
void draw_path_shadow(const Path &path, float dx, float dy, float blur, float spread, Color color) override
Draw ONLY the drop shadow cast by path — not the path itself.
void set_line_dash(const float *intervals, int count, float phase) override
Set the line dash pattern for stroke operations.
void set_fill_gradient_linear(float x0, float y0, float x1, float y1, const Color *colors, const float *positions, int count) override
Set a linear gradient as the fill paint.
void set_gradient_interpolation(GradientInterpolation method) override
Colour space every LATER gradient setter blends its stops in (CSS <color-interpolation-method>),...
const std::vector< DrawCommand > & commands() const
Definition recording_canvas.hpp:197
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) override
void set_line_width(float w) override
void stroke_text(const std::string &text, float x, float y, float max_width=0.0f) override
Canvas2D strokeText(text, x, y, maxWidth) spec form.
void set_shadow_offset_x(float dx) override
void begin_path() override
Begin a new path.
void set_transform(float a, float b, float c, float d, float e, float f) override
Replace the current transform with the affine matrix [ a c e ] [ b d f ] [ 0 0 1 ] Mirrors CanvasRend...
void set_blend_mode(BlendMode mode) override
Set the compositing blend mode for subsequent draw operations.
int save_count() const override
Return the current save-stack depth.
Definition recording_canvas.hpp:211
void set_direction(TextDirection direction) override
RendererBackend renderer_backend() const noexcept override
Identity of the renderer this canvas actually wraps.
Definition recording_canvas.hpp:194
void draw_box_shadow(float x, float y, float w, float h, float dx, float dy, float blur, float spread, Color color, bool inset, float corner_radius) override
Draw a CSS-style box shadow around (or inside, when inset) a rounded rectangle anchored at (x,...
void rotate(float radians) override
void line_to(float x, float y) override
Add a line segment to (x, y).
void fill_circle(float cx, float cy, float radius) override
void set_stroke_color(Color c) override
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) override
bool write_pixels(const uint8_t *data, int width, int height, int dx, int dy) override
Write RGBA pixels (data size = width*height*4) to the current surface at destination (dx,...
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) override
Canvas2D ctx.createRadialGradient(x0,y0,r0,x1,y1,r1) two-circle form.
void set_text_align(TextAlign align) override
void clear_stroke_gradient() override
Clear stroke gradient/pattern shader, restore solid stroke color.
void fill_rounded_rect(float x, float y, float w, float h, float radius) override
void stroke_rounded_rect(float x, float y, float w, float h, float radius) override
void set_fill_gradient_conic(float cx, float cy, float start_angle, const Color *colors, const float *positions, int count) override
Set a conic (sweep) gradient as the fill paint.
void set_line_cap(LineCap cap) override
void set_shadow_offset_y(float dy) override
void clip(FillRule rule=FillRule::nonzero) override
Intersect the current clip region with the current path.
bool draw_image_from_file(const std::string &path, float x, float y, float w, float h) override
Draw an image from a file path at the given rect.
void clear_rect(float x, float y, float w, float h) override
Clear a rectangular region to transparent black (rgba 0,0,0,0).
void quad_to(float cpx, float cpy, float x, float y) override
Add a quadratic bezier curve to (x, y) with control point (cpx, cpy).
void fill_current_path(FillRule rule=FillRule::nonzero) override
Fill the current path.
void stroke_circle(float cx, float cy, float radius) override
void ellipse(float cx, float cy, float rx, float ry, float rotation, float start_angle, float end_angle, bool anticlockwise) override
Native ellipse subpath.
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) override
Two-circle radial gradient on stroke (mirrors fill counterpart).
void draw_layer_rotated(LayerHandle layer, float angle_rad) override
Composite a sealed layer rotated about its own center.
void stroke_line(float x0, float y0, float x1, float y1) override
void save_layer(float x, float y, float w, float h, float opacity=1.0f, float blur_radius=0.0f) override
Save a compositing layer.
bool draw_with_sksl(const std::string &sksl, float x, float y, float w, float h, const ShaderUniforms &uniforms) override
Draw a rectangle filled by a custom SkSL shader.
void scale(float sx, float sy) override
void arc_to(float x1, float y1, float x2, float y2, float radius) override
Native arcTo.
void set_fill_gradient_radial(float cx, float cy, float radius, const Color *colors, const float *positions, int count) override
Set a radial gradient as the fill paint.
void arc(float cx, float cy, float radius, float start_angle, float end_angle, bool anticlockwise) override
Native arc subpath.
size_t command_count() const
Definition recording_canvas.hpp:199
void draw_layer(LayerHandle layer, float alpha=1.0f, BlendMode mode=BlendMode::normal) override
Composite a sealed layer at its recorded position.
size_t baseline_capture_count() const
Definition recording_canvas.hpp:207
void save_backdrop_filter(float x, float y, float w, float h, float blur_radius) override
CSS backdrop-filter: blur(Npx) — push a compositing layer whose initial contents are the parent surfa...
void save_layer_with_filters(float x, float y, float w, float h, float opacity, const FilterChainEntry *chain, int count) override
size_t count(DrawCommand::Type type) const
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) override
CSS mask-image + mask-size paint slice.
void save_layer_with_blend(float x, float y, float w, float h, float opacity, float blur_radius, BlendMode mode) override
Save a compositing layer with an explicit blend mode.
void draw_image(void *native_handle, float x, float y, float w, float h) override
Draw an image identified by an opaque, platform-specific handle into the rectangle (x,...
void stroke_rect(float x, float y, float w, float h) override
bool draw_image_from_data(const uint8_t *data, size_t size, float x, float y, float w, float h) override
Draw an image from encoded data (PNG, JPEG, WebP) at the given rect.
void translate(float x, float y) override
void set_stroke_pattern(const std::string &image_src, PatternTileMode tile_x, PatternTileMode tile_y) override
Stroke counterpart.
void draw_layer_fitted(LayerHandle layer, Rect2D dest) override
Composite a sealed layer scaled into dest.
void fill_path(const Path &path, FillRule rule=FillRule::nonzero) override
Fill path under rule.
void clip_rect(float x, float y, float w, float h) override
void set_fill_pattern(const std::string &image_src, PatternTileMode tile_x, PatternTileMode tile_y) override
Set an image pattern as the fill paint.
void save_layer_with_bloom(float x, float y, float w, float h, float intensity, float threshold, float radius) override
Save a compositing layer that applies a real bloom/glow post-effect to the subtree painted into it.
bool layer_valid(LayerHandle layer) const override
Is layer still backed by a live texture that can be drawn WITHOUT re-recording it?
void set_font_full(const std::string &family, float size, int weight, int slant, float letter_spacing) override
Richer font setter that propagates CSS font-weight (100..900), font-slant (0=upright,...
void stroke_path(const Path &path, const StrokeStyle &style) override
Stroke path with style.
void stroke_arc(float cx, float cy, float radius, float start_angle, float end_angle) override
void set_font_smoothing(FontSmoothing smoothing) override
CSS -webkit-font-smoothing for the text drawn and measured after it.
float measure_text(const std::string &text) override
void invalidate_layer(LayerHandle layer) override
Drop layer's texture.
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) override
Native rounded-rectangle subpath with per-corner radii.
void clear()
Definition recording_canvas.hpp:198
void set_font(const std::string &family, float size) override
void set_fill_color(Color c) override
void clear_fill_gradient() override
Clear gradient, return to solid fill color.
void set_shadow_blur(float blur) override
void set_stroke_gradient_conic(float cx, float cy, float start_angle, const Color *colors, const float *positions, int count) override
void set_miter_limit(float limit) override
Canvas2D ctx.miterLimit.
void move_to(float x, float y) override
Move the pen to (x, y) without drawing.
void fill_text(const std::string &text, float x, float y) override
void set_filter(const std::string &filter) override
Canvas2D ctx.filter.
void set_line_join(LineJoin join) override
AffineTransform2x3 current_transform() const override
Snapshot the current device matrix (CTM) without mutating canvas state.
void clip_path(const Path &path, FillRule rule=FillRule::nonzero) override
Intersect the current clip with path. Caller owns save()/restore().
void clip_path_svg(const std::string &svg_path_d) override
CSS clip-path: path("...") — intersect the current clip with an SVG-path-d string.
void capture_paint_baseline_transform() override
Snapshot the current device matrix as the baseline for subsequent set_transform() calls.
void fill_text_with_max_width(const std::string &text, float x, float y, float max_width) override
Canvas2D fillText(text, x, y, maxWidth) spec form.
void fill_rect(float x, float y, float w, float h) override
Definition affine_transform.hpp:24
TextAlign
Definition canvas.hpp:221
FontSmoothing
CSS -webkit-font-smoothing as it affects glyph rasterization on macOS.
Definition text_raster_policy.hpp:40
RendererBackend
Runtime identity of the concrete renderer receiving draw calls.
Definition canvas.hpp:29
@ recording
Definition canvas.hpp:31
FillRule
Winding rule used to decide what counts as "inside" a path.
Definition path.hpp:54
@ nonzero
Definition path.hpp:54
LineJoin
Join applied where two segments meet when stroking.
Definition path.hpp:60
@ text
Definition scene_node.hpp:96
@ path
Definition scene_node.hpp:93
LineCap
Line cap applied to the ends of open subpaths when stroking.
Definition path.hpp:57
Affine 2x3 transform snapshot, six floats laid out as CanvasRenderingContext2D.setTransform / DOMMatr...
Definition canvas.hpp:322
Full CSS filter-chain layer save.
Definition canvas.hpp:974
An opaque reference to a compositing layer owned by the canvas.
Definition canvas.hpp:849
Uniforms passed to custom widget shaders.
Definition canvas.hpp:1635
Definition canvas.hpp:52
Definition recording_canvas.hpp:16
float f[6]
Definition recording_canvas.hpp:182
Type type
Definition recording_canvas.hpp:180
Color color
Definition recording_canvas.hpp:183
std::string text
Definition recording_canvas.hpp:184
Type
Definition recording_canvas.hpp:19
@ stroke_circle
Definition recording_canvas.hpp:27
@ fill_path_object
path d in text; fill rule in f[0] (0=nonzero, 1=evenodd)
Definition recording_canvas.hpp:109
@ concat_transform
Definition recording_canvas.hpp:23
@ arc_to
(x1, y1, x2, y2, radius) in f[0..4]
Definition recording_canvas.hpp:153
@ scale
Definition recording_canvas.hpp:21
@ set_shadow_blur
blur (px) in f[0]
Definition recording_canvas.hpp:51
@ set_stroke_gradient_radial
Definition recording_canvas.hpp:85
@ round_rect
(x, y, w, h, tl_x, tl_y) in f[0..5]; tr/br/bl x/y in floats[0..5]
Definition recording_canvas.hpp:155
@ cubic_to
(cp1x, cp1y, cp2x, cp2y, x, y) in f[0..5]
Definition recording_canvas.hpp:143
@ set_stroke_gradient_linear
Definition recording_canvas.hpp:84
@ set_stroke_pattern
Definition recording_canvas.hpp:72
@ draw_path_shadow
path d in text; dx/dy/blur/spread in f[0..3]; shadow color in color
Definition recording_canvas.hpp:112
@ save_backdrop_filter
x/y/w/h in f[0..3], blur_radius in f[4]
Definition recording_canvas.hpp:125
@ invalidate_layer
id f[0]
Definition recording_canvas.hpp:123
@ set_fill_gradient_radial
Definition recording_canvas.hpp:101
@ stroke_arc
Definition recording_canvas.hpp:27
@ draw_layer_rotated
id f[0]; angle (radians) in f[1]
Definition recording_canvas.hpp:122
@ set_fill_color
Definition recording_canvas.hpp:24
@ ellipse
(cx, cy, rx, ry, rotation, start) in f[0..5]; (end, anticlockwise as 0/1) extras tracked in floats[0....
Definition recording_canvas.hpp:154
@ set_direction
Definition recording_canvas.hpp:66
@ fill_rect
Definition recording_canvas.hpp:26
@ clear_stroke_gradient
Definition recording_canvas.hpp:88
@ draw_layer_fitted
id f[0]; dest x/y/w/h in f[1..4]
Definition recording_canvas.hpp:121
@ fill_text
Definition recording_canvas.hpp:28
@ draw_sksl
rect x/y/w/h in f[0..3]; value f[4]; time f[5]; SkSL source in text
Definition recording_canvas.hpp:175
@ set_line_cap
Definition recording_canvas.hpp:25
@ stroke_line
Definition recording_canvas.hpp:27
@ stroke_rounded_rect
Definition recording_canvas.hpp:26
@ set_text_align
Definition recording_canvas.hpp:28
@ draw_box_shadow
x/y/w/h in f[0..3], blur in f[4], spread/offsets via floats payload
Definition recording_canvas.hpp:46
@ set_miter_limit
limit in f[0]
Definition recording_canvas.hpp:57
@ save
Definition recording_canvas.hpp:20
@ set_font_smoothing
f[0]: 0 = auto, 1 = antialiased
Definition recording_canvas.hpp:59
@ set_line_join
Definition recording_canvas.hpp:25
@ save_layer
bounds x/y/w/h in f[0..3]; opacity f[4]; blur f[5]
Definition recording_canvas.hpp:165
@ set_blend_mode
Definition recording_canvas.hpp:22
@ set_shadow_color
color in color
Definition recording_canvas.hpp:50
@ set_fill_pattern
Definition recording_canvas.hpp:71
@ draw_layer
id f[0], alpha f[1], blend mode f[2]
Definition recording_canvas.hpp:120
@ fill_current_path
no payload — uses last set_fill_color
Definition recording_canvas.hpp:145
@ set_gradient_interpolation
GradientColorSpace in f[0], GradientHueMethod in f[1].
Definition recording_canvas.hpp:176
@ rotate
Definition recording_canvas.hpp:21
@ set_filter
Definition recording_canvas.hpp:67
@ clip_rect
Definition recording_canvas.hpp:21
@ save_layer_filters
bounds f[0..3]; effective opacity f[4]; summed blur f[5]; filter count in floats[0]
Definition recording_canvas.hpp:167
@ save_layer_bloom
bounds f[0..3]; intensity f[4]; threshold f[5]; blur radius in floats[0]
Definition recording_canvas.hpp:169
@ line_to
(x, y) in f[0..1]
Definition recording_canvas.hpp:141
@ save_layer_mask
bounds f[0..3]; opacity f[4]; mask-image CSS value in text (mask-size not captured)
Definition recording_canvas.hpp:168
@ arc
(cx, cy, r, start, end, anticlockwise as 0/1) in f[0..5]
Definition recording_canvas.hpp:152
@ set_stroke_color
Definition recording_canvas.hpp:24
@ set_font
Definition recording_canvas.hpp:28
@ clear_rect
clear rect, x/y/w/h in f[0..3]
Definition recording_canvas.hpp:134
@ stroke_text
Definition recording_canvas.hpp:35
@ set_fill_gradient_radial_two_circles
Definition recording_canvas.hpp:102
@ stroke_path_object
path d in text; width f[0], cap f[1], join f[2], miter f[3], dash phase f[4]; dash intervals in float...
Definition recording_canvas.hpp:110
@ begin_path
no payload
Definition recording_canvas.hpp:139
@ draw_image
source path/url in text, dst rect in f[0..3]
Definition recording_canvas.hpp:43
@ set_shadow_offset_x
dx (px) in f[0]
Definition recording_canvas.hpp:52
@ write_pixels
RGBA bytes in text (binary), w/h in f[0..1], dst in f[2..3].
Definition recording_canvas.hpp:44
@ set_transform
Definition recording_canvas.hpp:22
@ clear_fill_gradient
Definition recording_canvas.hpp:104
@ fill_rounded_rect
Definition recording_canvas.hpp:26
@ restore
Definition recording_canvas.hpp:20
@ set_font_full
Definition recording_canvas.hpp:40
@ clip_path_object
path d in text; fill rule in f[0]
Definition recording_canvas.hpp:111
@ set_shadow_offset_y
dy (px) in f[0]
Definition recording_canvas.hpp:53
@ begin_layer
bounds x/y/w/h in f[0..3]; cacheable in f[4]; id in f[5]
Definition recording_canvas.hpp:118
@ set_stroke_gradient_conic
Definition recording_canvas.hpp:87
@ save_layer_blend
bounds f[0..3]; opacity f[4]; blur f[5]; blend mode (int) in floats[0]
Definition recording_canvas.hpp:166
@ move_to
(x, y) in f[0..1]
Definition recording_canvas.hpp:140
@ set_fill_gradient_linear
Definition recording_canvas.hpp:100
@ close_path
no payload
Definition recording_canvas.hpp:144
@ stroke_current_path
no payload — uses last set_stroke_color + set_line_width
Definition recording_canvas.hpp:146
@ set_fill_gradient_conic
Definition recording_canvas.hpp:103
@ end_layer
sealed handle id in f[0]
Definition recording_canvas.hpp:119
@ clip_path_svg
SVG path data in text.
Definition recording_canvas.hpp:132
@ quad_to
(cpx, cpy, x, y) in f[0..3]
Definition recording_canvas.hpp:142
@ set_line_width
Definition recording_canvas.hpp:24
@ clip
Definition recording_canvas.hpp:22
@ fill_circle
Definition recording_canvas.hpp:27
@ set_image_smoothing
enabled in f[0] (0/1), quality in f[1] (0=low,1=med,2=high)
Definition recording_canvas.hpp:58
@ set_line_dash
intervals stored in floats, phase in f[0]
Definition recording_canvas.hpp:42
@ translate
Definition recording_canvas.hpp:21
@ set_stroke_gradient_radial_two_circles
Definition recording_canvas.hpp:86
@ stroke_rect
Definition recording_canvas.hpp:26
std::vector< float > floats
Definition recording_canvas.hpp:189
Definition gradient_interpolation.hpp:43
Axis-aligned rectangle in canvas coordinates.
Definition rectangle_list.hpp:28
Everything needed to stroke a path, as one value.
Definition path.hpp:67