Pulp 1.88.0
Cross-platform audio plugin framework
Loading...
Searching...
No Matches
cg_canvas.hpp
Go to the documentation of this file.
1#pragma once
2
4
5#include <vector>
6
7#ifdef __APPLE__
8
9// Forward declare CG types
10typedef struct CGContext* CGContextRef;
11typedef struct CGPath* CGMutablePathRef;
12typedef struct CGImage* CGImageRef;
13typedef struct CGPattern* CGPatternRef;
14
15namespace pulp::canvas {
16
17// CoreGraphics-backed Canvas implementation for macOS
18// Renders directly into a CGContext (from NSView drawRect: or CGBitmapContext)
19class CoreGraphicsCanvas : public Canvas {
20public:
21 RendererBackend renderer_backend() const noexcept override {
23 }
24 float backing_scale() const noexcept override;
25 explicit CoreGraphicsCanvas(CGContextRef ctx, float width, float height);
26 ~CoreGraphicsCanvas() override;
27
28 void save() override;
29 void restore() override;
30 int save_count() const override { return save_depth_; }
31 void restore_to_count(int target) override;
32 void translate(float x, float y) override;
33 void scale(float sx, float sy) override;
34 void rotate(float radians) override;
35 void concat_transform(float a, float b, float c,
36 float d, float e, float f) override;
37 void set_transform(float a, float b, float c,
38 float d, float e, float f) override;
41 void clip_rect(float x, float y, float w, float h) override;
42 void clip(FillRule rule = FillRule::nonzero) override;
43
44 void set_fill_color(Color c) override;
45 void set_stroke_color(Color c) override;
46 void set_line_width(float w) override;
47 void set_line_cap(LineCap cap) override;
48 void set_line_join(LineJoin join) override;
49
50 // Canvas2D ctx.setLineDash() / lineDashOffset on the CG backend. The base
51 // Canvas default is a no-op, so without this override dashed strokes draw
52 // solid on the macOS CPU paint path. Mirrors SkiaCanvas::set_line_dash; the
53 // actual CG state mutation happens via CGContextSetLineDash inside
54 // apply_line_dash_to_ctx() immediately before each stroke draw, then is
55 // reset to solid afterwards so the dash pattern doesn't leak into
56 // untracked CG callers.
57 void set_line_dash(const float* intervals, int count, float phase) override;
58
59 // Canvas2D ctx.miterLimit and imageSmoothingEnabled / Quality. Stored on the
60 // canvas; CGContextSetMiterLimit / CGContextSetInterpolationQuality apply
61 // immediately (no per-draw re-push needed since they hang off the
62 // current GState).
63 void set_miter_limit(float limit) override;
66 void set_font_smoothing(FontSmoothing smoothing) override;
67 void set_image_smoothing(bool enabled,
68 ImageSmoothingQuality quality) override;
69
70 void set_fill_gradient_linear(float x0, float y0, float x1, float y1,
71 const Color* colors, const float* positions,
72 int count) override;
73 void set_fill_gradient_radial(float cx, float cy, float radius,
74 const Color* colors, const float* positions,
75 int count) override;
80 float x0, float y0, float r0,
81 float x1, float y1, float r1,
82 const Color* colors, const float* positions, int count) override;
83 void set_fill_gradient_conic_repeating(float cx, float cy, float start_angle,
84 float sweep_turns,
85 const Color* colors, const float* positions,
86 int count) override;
87 void set_fill_gradient_conic(float cx, float cy, float start_angle,
88 const Color* colors, const float* positions,
89 int count) override;
90 void clear_fill_gradient() override;
91
92 // Stroke-side gradient overrides. Parallel to fill-side GradientKind state
93 // so stroke calls can route through stroke_with_active_paint() when a
94 // gradient is active. Without these overrides the base no-op makes stroke
95 // draws collapse to first-stop color even when the JS shim sets
96 // createLinearGradient() as strokeStyle.
97 void set_stroke_gradient_linear(float x0, float y0, float x1, float y1,
98 const Color* colors, const float* positions,
99 int count) override;
100 void set_stroke_gradient_radial(float cx, float cy, float radius,
101 const Color* colors, const float* positions,
102 int count) override;
104 float x0, float y0, float r0,
105 float x1, float y1, float r1,
106 const Color* colors, const float* positions, int count) override;
107 void set_stroke_gradient_conic(float cx, float cy, float start_angle,
108 const Color* colors, const float* positions,
109 int count) override;
110 void clear_stroke_gradient() override;
111
112 // Canvas2D ctx.createPattern. CG fill patterns use a CGPatternRef +
113 // tiling callback; stroke patterns remain a graceful fallback to the
114 // active stroke color.
115 void set_fill_pattern(const std::string& image_src,
116 PatternTileMode tile_x,
117 PatternTileMode tile_y) override;
118 void set_stroke_pattern(const std::string& image_src,
119 PatternTileMode tile_x,
120 PatternTileMode tile_y) override;
121
122 void fill_rect(float x, float y, float w, float h) override;
123 void clear_rect(float x, float y, float w, float h) override;
124 void stroke_rect(float x, float y, float w, float h) override;
125 void fill_rounded_rect(float x, float y, float w, float h, float radius) override;
126 void stroke_rounded_rect(float x, float y, float w, float h, float radius) override;
127 void fill_circle(float cx, float cy, float radius) override;
128 void stroke_circle(float cx, float cy, float radius) override;
129 void stroke_arc(float cx, float cy, float radius,
130 float start_angle, float end_angle) override;
131 void stroke_line(float x0, float y0, float x1, float y1) override;
132 void stroke_path(const Point2D* points, size_t count) override;
133 // `rule` splits nonzero (CGContextFillPath / CGContextClip) from even-odd
134 // (CGContextEOFillPath / CGContextEOClip), the same split
135 // fill_current_path() honors.
136 void fill_path(const Point2D* points, size_t count,
137 FillRule rule = FillRule::nonzero) override;
138
139 // ── Retained paths (pulp::canvas::Path) ──────────────────────────────
140 // Implemented in cg_canvas_path.mm. Each builds one CGPath and issues a
141 // single draw. The `using` declarations keep the polygon overloads above
142 // visible — a same-named override would otherwise hide them.
143 using Canvas::fill_path;
145 void fill_path(const Path& path, FillRule rule = FillRule::nonzero) override;
146 void stroke_path(const Path& path, const StrokeStyle& style) override;
147 void clip_path(const Path& path, FillRule rule = FillRule::nonzero) override;
148 void draw_path_shadow(const Path& path, float dx, float dy,
149 float blur, float spread, Color color) override;
150
151 // ── Retained compositing layers ──────────────────────────────────────
152 // Offscreen CGBitmapContexts sealed to CGImageRefs that OUTLIVE the frame
153 // when `cacheable`.
154 LayerHandle begin_layer(Rect2D bounds, bool cacheable = false) override;
156 void draw_layer(LayerHandle layer, float alpha = 1.0f,
157 BlendMode mode = BlendMode::normal) override;
158 void draw_layer_fitted(LayerHandle layer, Rect2D dest) override;
159 void draw_layer_rotated(LayerHandle layer, float angle_rad) override;
160 bool layer_valid(LayerHandle layer) const override;
161 void invalidate_layer(LayerHandle layer) override;
162
163 // Canvas2D-style path building.
164 void begin_path() override;
165 void move_to(float x, float y) override;
166 void line_to(float x, float y) override;
167 void quad_to(float cpx, float cpy, float x, float y) override;
168 void cubic_to(float cp1x, float cp1y, float cp2x, float cp2y,
169 float x, float y) override;
170 void close_path() override;
172 void stroke_current_path() override;
173
174 // Native arc subpaths via CGPath APIs.
175 void arc(float cx, float cy, float radius,
176 float start_angle, float end_angle,
177 bool anticlockwise) override;
178 void arc_to(float x1, float y1, float x2, float y2,
179 float radius) override;
180 void ellipse(float cx, float cy, float rx, float ry,
181 float rotation,
182 float start_angle, float end_angle,
183 bool anticlockwise) override;
184 void round_rect(float x, float y, float w, float h,
185 float tl_x, float tl_y,
186 float tr_x, float tr_y,
187 float br_x, float br_y,
188 float bl_x, float bl_y) override;
189
190 void set_opacity(float alpha) override;
191 void save_layer(float x, float y, float w, float h,
192 float opacity, float blur_radius) override;
193
194 // Canvas2D globalCompositeOperation parity. Without this override the base
195 // Canvas no-op default drops blend requests on the CPU paint path, so JS
196 // bundles using ctx.globalCompositeOperation = 'lighter'/'multiply'/etc.
197 // draw with the default SrcOver. CG's GState stack matches Canvas2D
198 // save()/restore() blend-mode semantics, so we push the chosen CGBlendMode
199 // into the current GState and let CG carry it across draws + save/restore
200 // frames.
201 void set_blend_mode(BlendMode mode) override;
202
203 void set_font(const std::string& family, float size) override;
204 void set_font_full(const std::string& family, float size, int weight, int slant,
205 float letter_spacing) override;
206 void set_font_features(std::vector<FontFeature> features) override;
207 void clear_font_features() override;
208 void set_text_align(TextAlign align) override;
209 void fill_text(const std::string& text, float x, float y) override;
210 // Canvas2D fillText(text,x,y,maxWidth) + strokeText(text,x,y,maxWidth).
211 void fill_text_with_max_width(const std::string& text,
212 float x, float y, float max_width) override;
213 void stroke_text(const std::string& text, float x, float y,
214 float max_width = 0.0f) override;
215 float measure_text(const std::string& text) override;
216 TextMetrics measure_text_full(const std::string& text) override;
217 float text_x_for_byte(const std::string& text,
218 std::size_t byte_index) override;
219
220 // Canvas2D drop-shadow state. CGContext exposes sticky shadow state
221 // directly via CGContextSetShadowWithColor; we mirror Canvas2D's sticky
222 // `ctx.shadow*` semantics by translating each setter into a CG state
223 // mutation that hangs off the current GState (so save/restore correctly
224 // snapshots and pops the shadow).
226 void set_shadow_blur(float blur) override;
227 void set_shadow_offset_x(float dx) override;
228 void set_shadow_offset_y(float dy) override;
229
230 // ── Capabilities ───────────────────────────────────────────────────
231 // CG overrides ONLY the image verbs (real ImageIO decoder). Every other
232 // effect verb — filter chains, mask/backdrop/bloom layers, SkSL, SVG,
233 // path-clip, Gaussian box-shadow — inherits the base degradation, so it
234 // advertises `images` and nothing else. Honest map of the real CG gaps.
235 bool supports(CanvasCapability cap) const override {
236 return cap == CanvasCapability::images;
237 }
238
239 // ── Images ───────────────────────────────────────────────────────────
240 // CG has a real ImageIO decoder (cg_decode_image_from_path_or_data), so
241 // these verbs decode + CGContextDrawImage instead of leaving the base
242 // no-op that made ImageView render each image's FILENAME as placeholder
243 // text on the macOS CPU paint path (the "filename-placeholder trap").
244 bool draw_image_from_data(const uint8_t* data, size_t size,
245 float x, float y, float w, float h) override;
246 bool draw_image_from_file(const std::string& path,
247 float x, float y, float w, float h) override;
248 bool draw_image_from_data_rect(const uint8_t* data, size_t size,
249 float sx, float sy, float sw, float sh,
250 float dx, float dy, float dw, float dh) override;
251 bool draw_image_from_file_rect(const std::string& path,
252 float sx, float sy, float sw, float sh,
253 float dx, float dy, float dw, float dh) override;
254 bool measure_image_from_data(const uint8_t* data, size_t size, float& out_width,
255 float& out_height) override;
256 bool measure_image_from_file(const std::string& path,
257 float& out_width, float& out_height) override;
258
259private:
260 // Draw a decoded CGImage into [dx,dy,dw,dh] (top-down canvas space),
261 // optionally cropping to the source rect [sx,sy,sw,sh] in image pixels
262 // first. Handles the counter-flip against the construction-time CTM flip
263 // so the bitmap paints right-side-up. Consumes (releases) `img`.
264 bool draw_cg_image_in_rect(CGImageRef img,
265 bool has_src,
266 float sx, float sy, float sw, float sh,
267 float dx, float dy, float dw, float dh);
268
269 CGContextRef ctx_;
270 float width_, height_;
271 // One entry per open save level: true when that level is a transparency
272 // layer (save_layer), so restore() ends a layer only at the level that
273 // opened it, and restore_to_count() closes layers as it pops them.
274 std::vector<bool> save_is_layer_;
275 Color fill_color_ = Color::rgba(1.0f, 1.0f, 1.0f);
276 Color stroke_color_ = Color::rgba(1.0f, 1.0f, 1.0f);
277 std::string font_family_ = "Helvetica";
278 float font_size_ = 14.0f;
279 int font_weight_ = 400;
280 int font_slant_ = 0;
281 std::vector<FontFeature> font_features_;
282 TextAlign text_align_ = TextAlign::left;
283
284 // Canvas2D path-building state. Owned, retained CG mutable path; null until
285 // the first begin_path() call.
286 CGMutablePathRef path_ = nullptr;
287
288 // Linear/radial gradient state used as the fill paint when
289 // has_gradient_ is true. Mirrors the SkiaCanvas split between solid
290 // fill and shader-based fill so JS-driven gradient fills paint instead
291 // of falling back to a single color.
292 //
293 // gradient_kind_ identifies which Draw* call to issue from
294 // fill_with_active_paint(). `radial_two_circles` is the spec-correct
295 // two-circle form (inner + outer centers, inner_r in grad_radius_inner_,
296 // outer_r in grad_radius_); `conic_image` is a software-rasterised CGImage
297 // that we paint via CGContextDrawImage inside the active clip.
298 enum class GradientKind { none, linear, radial, radial_two_circles, conic_image };
299 bool has_gradient_ = false;
300 GradientKind gradient_kind_ = GradientKind::none;
301 bool gradient_is_radial_ = false; // legacy mirror of (kind == radial), kept for older inline checks
302 float grad_x0_ = 0, grad_y0_ = 0, grad_x1_ = 0, grad_y1_ = 0;
303 float grad_radius_ = 0; // outer / single radius
304 float grad_radius_inner_ = 0; // inner radius for two-circle radial
305 std::vector<Color> grad_colors_;
306 std::vector<float> grad_positions_;
307
308 // Parallel stroke-side state. Same shape as the fill gradient slots;
309 // checked by stroke_with_active_paint() at each gradient-aware stroke site.
310 bool has_stroke_gradient_ = false;
311 GradientKind stroke_gradient_kind_ = GradientKind::none;
312 float stroke_grad_x0_ = 0, stroke_grad_y0_ = 0, stroke_grad_x1_ = 0, stroke_grad_y1_ = 0;
313 float stroke_grad_radius_ = 0;
314 float stroke_grad_radius_inner_ = 0;
315 std::vector<Color> stroke_grad_colors_;
316 std::vector<float> stroke_grad_positions_;
317
318 // Software-rasterised conic gradient. CG has no native conic shader, so
319 // set_fill_gradient_conic walks every pixel of a bounding-box bitmap,
320 // computes the angle from the center, interpolates the color stops, and
321 // stores the resulting CGImage here. fill_with_active_paint paints it via
322 // CGContextDrawImage inside the active clip. The image is released in
323 // clear_fill_gradient / dtor / on next gradient set.
324 CGImageRef conic_image_ = nullptr;
325 float conic_image_x_ = 0, conic_image_y_ = 0;
326 float conic_image_w_ = 0, conic_image_h_ = 0;
327 void release_conic_image();
328
329 // Tiled-pattern fill state. CG exposes patterns via CGPatternCreate + a
330 // draw callback; we hold the decoded image (so the callback can render a
331 // tile) and the tile dimensions / repetition mode here. has_pattern_
332 // short-circuits fill_with_active_paint onto CGContextSetFillPattern +
333 // CGContextFillRect/CGContextFillPath.
334 bool has_pattern_ = false;
335 CGImageRef pattern_image_ = nullptr;
338 void release_pattern_image();
339
340 // Paint-baseline transform captured at CanvasWidget::paint() entry,
341 // matching SkiaCanvas so JS-supplied setTransform() composes onto the
342 // inbound View matrix instead of overwriting it.
343 bool has_baseline_ = false;
344 // Storage for CGAffineTransform — declared as raw doubles so the
345 // header doesn't pull <CoreGraphics/CoreGraphics.h>. Six-element layout:
346 // [a, b, c, d, tx, ty] (CGAffineTransform memory layout).
347 double baseline_xform_[6] = {1, 0, 0, 1, 0, 0};
348
349 // Manual GState depth tracking. CG doesn't expose a saveCount() API, so
350 // save() and save_layer() increment and restore() decrements this
351 // counter; restore_to_count() pops repeatedly until depth matches the
352 // requested target. CanvasWidget::paint() snapshots the depth at entry and
353 // pops back to it at exit so an unbalanced JS ctx.save() can't leak
354 // GState into the parent View's paint scope.
355 int save_depth_ = 0;
356
357 // Canvas2D shadow* state. CGContext owns the sticky shadow via its GState
358 // stack, so save()/restore() naturally snapshots both ours and CG's. We
359 // hold the values here so a setter mutation re-pushes the combined state
360 // through CGContextSetShadowWithColor.
361 Color shadow_color_ = Color::rgba(0.0f, 0.0f, 0.0f, 0.0f);
362 float shadow_blur_ = 0.0f;
363 float shadow_offset_x_ = 0.0f;
364 float shadow_offset_y_ = 0.0f;
365 void apply_shadow_to_context();
366
367 // Line-dash state. CG's CGContextSetLineDash mutates the current GState so
368 // we cannot just push it once at setter time and forget; the JS bridge may
369 // toggle dash on/off between strokes within a single GState frame. We
370 // instead store the intervals + phase here and apply via
371 // apply_line_dash_to_ctx() immediately before every stroke call, then reset
372 // to solid afterwards.
373 std::vector<float> line_dash_;
374 float line_dash_phase_ = 0.0f;
375 void apply_line_dash_to_ctx();
376 void reset_line_dash_on_ctx();
377
378 void apply_fill_color();
379 void apply_stroke_color();
380 void add_rounded_rect_path(float x, float y, float w, float h, float radius);
381 // Fills (or clips to) the current path or rect using either the solid
382 // fill_color_ or the active gradient when has_gradient_ is set.
383 void fill_with_active_paint();
384 // Strokes the current path using either apply_stroke_color or, when
385 // has_stroke_gradient_ is set, draws the active stroke gradient
386 // clipped to the stroked-path outline (via CGContextReplacePathWithStrokedPath).
387 // `apply_sticky_dash` is false for stroke_path, whose StrokeStyle has already
388 // set the dash for this draw and must not be overridden by the sticky one.
389 void stroke_with_active_paint(bool apply_sticky_dash = true);
390 void release_path();
391
392 // ── Retained layer state (cg_canvas_path.mm) ─────────────────────────
393 // `image` is the sealed CGImageRef (owned; released on invalidate); `ctx`
394 // is the offscreen CGBitmapContext, live only while recording. A cacheable
395 // layer's image survives until it is explicitly invalidated — across
396 // frames, which is exactly what the scoped save_layer could never do.
397 struct CgLayer {
398 CGImageRef image = nullptr;
399 CGContextRef ctx = nullptr;
400 Rect2D bounds;
401 float scale_x = 1.0f;
402 float scale_y = 1.0f;
403 bool cacheable = false;
404 };
405 std::vector<std::pair<uint64_t, CgLayer>> layers_;
406
407 struct CgOpenLayer {
408 uint64_t id = 0;
409 CGContextRef previous_ctx = nullptr;
410 };
411 std::vector<CgOpenLayer> open_layers_;
412 uint64_t next_layer_id_ = 1;
413
414 CgLayer* find_layer(uint64_t id);
415 const CgLayer* find_layer(uint64_t id) const;
417 void release_layer(CgLayer& layer);
419 CGMutablePathRef make_cg_path(const Path& path) const;
420};
421
422} // namespace pulp::canvas
423
424#endif // __APPLE__
struct CGImage * CGImageRef
Definition cg_canvas.hpp:12
struct CGPath * CGMutablePathRef
Definition cg_canvas.hpp:11
struct CGContext * CGContextRef
Definition cg_canvas.hpp:10
struct CGPattern * CGPatternRef
Definition cg_canvas.hpp:13
Definition canvas.hpp:240
pulp::canvas::Point2D Point2D
Stroke a continuous polyline through an array of points.
Definition canvas.hpp:682
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
@ repeat
Definition canvas.hpp:497
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 clear_rect(float x, float y, float w, float h) override
Clear a rectangular region to transparent black (rgba 0,0,0,0).
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 set_fill_gradient_conic_repeating(float cx, float cy, float start_angle, float sweep_turns, const Color *colors, const float *positions, int count) override
Set a REPEATING conic gradient (CSS repeating-conic-gradient).
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 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 set_shadow_blur(float blur) override
void fill_circle(float cx, float cy, float radius) override
void set_image_smoothing(bool enabled, ImageSmoothingQuality quality) override
Canvas2D ctx.imageSmoothingEnabled + imageSmoothingQuality.
void stroke_rounded_rect(float x, float y, float w, float h, float radius) override
void stroke_rect(float x, float y, float w, float h) override
void stroke_arc(float cx, float cy, float radius, float start_angle, float end_angle) override
void fill_rounded_rect(float x, float y, float w, float h, float radius) override
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,...
float text_x_for_byte(const std::string &text, std::size_t byte_index) override
Caret x (in text-local space, measured from the text's leading edge) for the glyph boundary at byte_i...
float measure_text(const std::string &text) override
void set_shadow_offset_x(float dx) override
void set_line_cap(LineCap cap) override
void invalidate_layer(LayerHandle layer) override
Drop layer's texture.
void capture_paint_baseline_transform() override
Snapshot the current device matrix as the baseline for subsequent set_transform() calls.
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_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 set_line_width(float w) override
void fill_path(const Point2D *points, size_t count, FillRule rule=FillRule::nonzero) override
Fill a closed polygon defined by points, honoring rule.
TextMetrics measure_text_full(const std::string &text) override
Measure text with full font metrics using current font settings.
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 supports(CanvasCapability cap) const override
Report whether this backend renders cap's verb faithfully.
Definition cg_canvas.hpp:235
void set_stroke_gradient_conic(float cx, float cy, float start_angle, const Color *colors, const float *positions, int count) override
void set_opacity(float alpha) override
Set global alpha for subsequent drawing operations (0.0-1.0).
bool layer_valid(LayerHandle layer) const override
Is layer still backed by a live texture that can be drawn WITHOUT re-recording it?
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 restore_to_count(int target) override
Pop the save stack down to target (typically captured earlier via save_count()).
float backing_scale() const noexcept override
Effective device pixels per local canvas unit at the current transform.
void stroke_path(const Path &path, const StrokeStyle &style) override
Stroke path with style.
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 fill_path(const Path &path, FillRule rule=FillRule::nonzero) override
Fill path under rule.
void set_miter_limit(float limit) override
Canvas2D ctx.miterLimit.
void clear_fill_gradient() override
Clear gradient, return to solid fill color.
void set_line_join(LineJoin join) override
void save_layer(float x, float y, float w, float h, float opacity, float blur_radius) override
Save a compositing layer.
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 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 set_stroke_gradient_linear(float x0, float y0, float x1, float y1, const Color *colors, const float *positions, int count) override
void set_blend_mode(BlendMode mode) override
Set the compositing blend mode for subsequent draw operations.
void draw_layer_fitted(LayerHandle layer, Rect2D dest) override
Composite a sealed layer scaled into dest.
bool measure_image_from_file(const std::string &path, float &out_width, float &out_height) override
Decoded-image intrinsic dimensions in pixels.
void arc(float cx, float cy, float radius, float start_angle, float end_angle, bool anticlockwise) override
Native arc subpath.
void clear_stroke_gradient() override
Clear stroke gradient/pattern shader, restore solid stroke color.
void arc_to(float x1, float y1, float x2, float y2, float radius) override
Native arcTo.
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 stroke_line(float x0, float y0, float x1, float y1) override
void fill_text(const std::string &text, float x, float y) override
void stroke_path(const Point2D *points, size_t count) override
Stroke a continuous polyline — much smoother than individual stroke_line calls.
void set_stroke_color(Color c) override
LayerHandle end_layer() override
Seal the layer opened by the last begin_layer() and return its handle.
void set_shadow_color(Color color) override
Sticky drop-shadow state that wraps subsequent draw operations, matching the CanvasRenderingContext2D...
AffineTransform2x3 current_transform() const override
Snapshot the current device matrix (CTM) without mutating canvas state.
void stroke_circle(float cx, float cy, float radius) override
CoreGraphicsCanvas(CGContextRef ctx, float width, float height)
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 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
True two-circle radial gradient via CGContextDrawRadialGradient(inner_center, inner_r,...
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_font(const std::string &family, float size) override
void close_path() override
Close the current path subpath.
void clip(FillRule rule=FillRule::nonzero) override
Intersect the current clip region with the current path.
void set_font_features(std::vector< FontFeature > features) override
void translate(float x, float y) override
RendererBackend renderer_backend() const noexcept override
Identity of the renderer this canvas actually wraps.
Definition cg_canvas.hpp:21
LayerHandle begin_layer(Rect2D bounds, bool cacheable=false) override
Begin recording into an offscreen layer covering bounds (in current user space).
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 set_fill_color(Color c) override
void clip_path(const Path &path, FillRule rule=FillRule::nonzero) override
Intersect the current clip with path. Caller owns save()/restore().
void stroke_current_path() override
Stroke the current path.
void line_to(float x, float y) override
Add a line segment to (x, y).
void clip_rect(float x, float y, float w, float h) override
void move_to(float x, float y) override
Move the pen to (x, y) without drawing.
void fill_rect(float x, float y, float w, float h) override
void rotate(float radians) override
void set_stroke_pattern(const std::string &image_src, PatternTileMode tile_x, PatternTileMode tile_y) override
Stroke counterpart.
void set_text_align(TextAlign align) override
void set_font_smoothing(FontSmoothing smoothing) override
antialiased turns CoreText font smoothing off, the switch Chromium flips on macOS.
void begin_path() override
Begin a new path.
void scale(float sx, float sy) override
void cubic_to(float cp1x, float cp1y, float cp2x, float cp2y, float x, float y) override
Add a cubic bezier curve.
void set_stroke_gradient_radial(float cx, float cy, float radius, const Color *colors, const float *positions, int count) 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 fill_current_path(FillRule rule=FillRule::nonzero) override
Fill the current path.
void draw_layer(LayerHandle layer, float alpha=1.0f, BlendMode mode=BlendMode::normal) override
Composite a sealed layer at its recorded position.
bool measure_image_from_data(const uint8_t *data, size_t size, float &out_width, float &out_height) override
Intrinsic pixel size of encoded image bytes, read from the image header without decoding pixels: the ...
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 set_shadow_offset_y(float dy) override
int save_count() const override
Return the current save-stack depth.
Definition cg_canvas.hpp:30
Definition path.hpp:87
Definition affine_transform.hpp:24
TextAlign
Definition canvas.hpp:221
@ left
Definition canvas.hpp:221
FontSmoothing
CSS -webkit-font-smoothing as it affects glyph rasterization on macOS.
Definition text_raster_policy.hpp:40
CanvasCapability
Queryable backend capabilities.
Definition canvas_capability.hpp:19
@ images
draw_image_from_* really decode + draw
Definition canvas_capability.hpp:20
@ count
sentinel: number of real capabilities (keep LAST)
Definition canvas_capability.hpp:38
RendererBackend
Runtime identity of the concrete renderer receiving draw calls.
Definition canvas.hpp:29
@ core_graphics
Definition canvas.hpp:32
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
An opaque reference to a compositing layer owned by the canvas.
Definition canvas.hpp:849
Full text metrics for layout and intrinsic sizing.
Definition canvas.hpp:1230
Definition canvas.hpp:52
static constexpr Color rgba(float r, float g, float b, float a=1.0f)
Construct from float channels [0,1] (>1.0 allowed for HDR).
Definition canvas.hpp:56
Axis-aligned rectangle in canvas coordinates.
Definition rectangle_list.hpp:28
Everything needed to stroke a path, as one value.
Definition path.hpp:67