Skip to content

gg.canvas #

gg.canvas

gg.canvas draws 2D shapes with exactly the same pixels as Skia. It is meant for programs that must match a Skia-based renderer bit for bit (for example a browser engine compared against Chromium screenshots), while using gg/sokol instead of linking Skia.

Exactness is achieved by reproducing what Skia does, not by approximating its output:

  • The GPU backend (GpuContext, GpuSurface) issues the same Metal work as Skia Graphite: the Graphite-generated MSL shaders are embedded unchanged (shaders/), compiled with Graphite's MSL version and fast-math mode, and fed byte-identical instance and uniform data through sokol.gfx.
  • Draws are ordered, sorted (with a port of libc++'s std::sort) and batched into instanced draw calls exactly like Graphite's Device, DrawList and DrawBufferManager. Splitting or reordering a batch changes antialiased and MSAA pixels on Apple GPUs.
  • Geometry is normalized with the same floating-point operations as Skia (SkRRect, Graphite's Rect and Transform). Skia is compiled with -ffp-contract=off, so the code here avoids expressions that the C compiler could fuse into FMAs: products feeding a sum are separate statements.

Supported so far: filled, stroked and hairline rects, rounded rects and ovals (the analytic rrect and non-AA bounds renderers, including Graphite's inner fills), single-sampled and 4x MSAA surfaces, uploaded backdrops (loaded into MSAA passes with Graphite's LoadMSAAFromResolve draw), BGRA8 premultiplied readback, filled and stroked double rounded rects (draw_drrect), and clips: save/restore, intersect and difference clip_rect, clip_rrect and clip_path under scales, flips, 90-degree rotations and other affine transforms (a port of Graphite's ClipStack: element simplification, geometric intersection of draws with clips, scissors, the analytic clip shaders, and depth-only draws in a 4x MSAA pass for further elements: convex wedges for convex difference elements, stencil wedges with an inverse cover of the scissor for intersect elements, and stencil wedges with a regular cover for non-convex difference paths). Filled paths (Path, built with PathBuilder like SkPathBuilder, including its rect, oval and rrect contours) are drawn like Graphite's drawPath: rect, oval and nested-rect paths use those renderers, convex paths the shaded convex wedges and other paths the MSAA stencil-and-cover wedges (winding and even-odd), including Skia's path convexity, rect detection and Wang's formula for lines, quads, conics and cubics. Strokes of paths, and of rrects the analytic renderer cannot stroke (elliptical corners), use Graphite's tessellated stroke renderer: deferred first patches joined to closing patches, miter, round and bevel joins, butt, round and square caps, cubic, quad and conic cusps, hairlines and cubic convex-180 chops. Convex path fills and strokes apply the analytic clip in their fragment shaders. Curves that need more than 32 parametric segments are chopped like Graphite's PatchWriter, in fills and strokes. Inverse fills use the stencil wedges with an inverse cover of the clip. Draws that need other renderers (curved path clips under rotations, ...) return an error instead of rendering differently. Lines (draw_line, and paths that are a single line) are stroked by the analytic renderer with caps, like Graphite's drawPoints. Shapes, path fills and strokes can also be painted with dithered linear and radial gradients (Paint.gradient, like SkShaders::LinearGradient and RadialGradient with up to 8 stops, every tile mode, premultiplied or unpremultiplied interpolation, a local matrix and the paint's alpha), with or without analytic clips. Their shaders combine each renderer's solid-color shaders with pieces of Graphite's gradient MSL (shaders/paint_snippets.metal), and the uniforms follow SkGradientBaseShader's stop normalization and Graphite's gradient, local matrix, color space and dither blocks. Gradient pipelines are compiled on first use. save_layer mirrors SkCanvas::saveLayer() without a paint: later draws go to an approximately sized offscreen texture covering the clip bounds, which the matching restore renders in its own pass and draws back through the clip with Graphite's image shader (on the bounds, analytic rrect or per-edge AA quad renderer, with the analytic clip or stencil clip elements). save/restore also restore the matrix, like SkCanvas. Fractional rectangular layer bounds use PerEdgeAAQuad's 16 template vertices, 29 indices, 80-byte instances and coverage shader.

Only Metal is supported: the reproduced output is Graphite's Metal output on the same GPU. Geometry and recording code can be imported on other platforms; typeface creation and raster text return unsupported-platform errors there. CoreText implementation files are compiled only on macOS.

RasterSurface reproduces Skia's CPU raster text on macOS (draw_glyphs, like SkCanvas::drawTextBlob with one positioned run): the scaler record, CoreGraphics glyph masks with Skia's linearization and SkMaskGamma pre-blend, subpixel glyph positioning, and the lowp SkRasterPipeline mask blit into BGRA8 premultiplied pixels. Synthetic bold, color glyphs, aliased text and glyphs that Skia draws as paths (over 256px) return an error.

Text drawing and cleanup run serially on the drawing thread. The process-wide strike cache retains at most 32 scaler contexts in least-recently-used order. Each strike caches at most 256 glyphs and 256 KiB of masks; larger individual glyph masks (over 512 pixels in either dimension) return an error. Eviction releases masks, the copied font, and the native bitmap/context. Call canvas.clear_text_cache() to release all strikes while keeping typefaces usable, and typeface.free() when the caller finishes with a face. The latter also evicts that face's strikes and releases its retained native font.

import gg.canvas

mut ctx := canvas.new_gpu_context()!
mut surface := ctx.new_surface(width: 64, height: 48)!
surface.clear(canvas.Color4f{})
r := canvas.Point{6, 6}
surface.draw_rrect(canvas.RRect.rect_radii(canvas.Rect.ltrb(4.5, 4, 60, 44), [r, r, r, r]!),
    canvas.Paint.rgba8(35, 167, 79, 255))!
mut pixels := []u8{len: 64 * 48 * 4}
surface.read_pixels(pixels.data, 64 * 4)! // BGRA, premultiplied

The shaders in shaders/ are generated by Skia Graphite and distributed under Skia's BSD license (shaders/LICENSE-skia); the ported algorithms follow the same Skia sources.

fn clear_text_cache #

fn clear_text_cache()

clear_text_cache releases cached glyph masks, sized fonts and native contexts. Call serially with text drawing; live typefaces remain usable afterwards.

fn new_gpu_context #

fn new_gpu_context() !&GpuContext

new_gpu_context creates a context for exact GPU rendering. Only Metal is supported; the shaders reproduce Skia Graphite's Metal output.

fn new_raster_surface #

fn new_raster_surface(cfg RasterSurfaceConfig) !RasterSurface

fn ClipOp.from #

fn ClipOp.from[W](input W) !ClipOp

from returns the ClipOp value of an integer or of a field name, or an error if there is none.

fn Color4f.from_rgba8 #

fn Color4f.from_rgba8(r u8, g u8, b u8, a u8) Color4f

Color4f.from_rgba8 converts 8-bit components exactly like SkColor4f::FromColor().

fn Corner.from #

fn Corner.from[W](input W) !Corner

from returns the Corner value of an integer or of a field name, or an error if there is none.

fn FontEdging.from #

fn FontEdging.from[W](input W) !FontEdging

from returns the FontEdging value of an integer or of a field name, or an error if there is none.

fn FontHinting.from #

fn FontHinting.from[W](input W) !FontHinting

from returns the FontHinting value of an integer or of a field name, or an error if there is none.

fn Gradient.two_point_conical #

fn Gradient.two_point_conical(start Point, start_radius f32, end Point, end_radius f32, g Gradient) !Gradient

Gradient.two_point_conical mirrors the shader that SkShaders::TwoPointConicalGradient() makes for g's colors: concentric gradients that start at a point are radial gradients. Other two-point conical gradients are not supported yet.

fn GradientKind.from #

fn GradientKind.from[W](input W) !GradientKind

from returns the GradientKind value of an integer or of a field name, or an error if there is none.

fn Matrix.identity #

fn Matrix.identity() Matrix

fn Matrix.scale #

fn Matrix.scale(sx f32, sy f32) Matrix

fn Matrix.translate #

fn Matrix.translate(dx f32, dy f32) Matrix

fn Matrix.values #

fn Matrix.values(values [9]f32) Matrix

Matrix.values creates a matrix from nine row-major values, like SkMatrix::set9().

fn Paint.rgba8 #

fn Paint.rgba8(r u8, g u8, b u8, a u8) Paint

Paint.rgba8 creates a fill paint from 8-bit components, like SkPaint::setColor().

fn PaintStyle.from #

fn PaintStyle.from[W](input W) !PaintStyle

from returns the PaintStyle value of an integer or of a field name, or an error if there is none.

fn PathConvexity.from #

fn PathConvexity.from[W](input W) !PathConvexity

from returns the PathConvexity value of an integer or of a field name, or an error if there is none.

fn PathDirection.from #

fn PathDirection.from[W](input W) !PathDirection

from returns the PathDirection value of an integer or of a field name, or an error if there is none.

fn PathFillType.from #

fn PathFillType.from[W](input W) !PathFillType

from returns the PathFillType value of an integer or of a field name, or an error if there is none.

fn PathVerb.from #

fn PathVerb.from[W](input W) !PathVerb

from returns the PathVerb value of an integer or of a field name, or an error if there is none.

fn RRect.from_rect #

fn RRect.from_rect(rect Rect) RRect

RRect.from_rect returns a rectangle without rounded corners.

fn RRect.oval #

fn RRect.oval(rect Rect) RRect

RRect.oval returns the ellipse inscribed in rect, like SkRRect::setOval().

fn RRect.rect_radii #

fn RRect.rect_radii(rect Rect, radii [4]Point) RRect

RRect.rect_radii mirrors SkRRect::setRectRadii(). radii lists the x/y radius pairs of the four corners in clockwise order from the top left.

fn RRectType.from #

fn RRectType.from[W](input W) !RRectType

from returns the RRectType value of an integer or of a field name, or an error if there is none.

fn Rect.infinite_inverted #

fn Rect.infinite_inverted() Rect

Rect.infinite_inverted returns [inf, inf, -inf, -inf], the identity for join.

fn Rect.ltrb #

fn Rect.ltrb(left f32, top f32, right f32, bottom f32) Rect

Rect.ltrb creates a rectangle from its edges.

fn Rect.xywh #

fn Rect.xywh(x f32, y f32, width f32, height f32) Rect

Rect.xywh creates a rectangle from its origin and size.

fn StrokeCap.from #

fn StrokeCap.from[W](input W) !StrokeCap

from returns the StrokeCap value of an integer or of a field name, or an error if there is none.

fn StrokeJoin.from #

fn StrokeJoin.from[W](input W) !StrokeJoin

from returns the StrokeJoin value of an integer or of a field name, or an error if there is none.

fn TileMode.from #

fn TileMode.from[W](input W) !TileMode

from returns the TileMode value of an integer or of a field name, or an error if there is none.

fn Transform.new #

fn Transform.new(matrix Matrix) Transform

fn TransformType.from #

fn TransformType.from[W](input W) !TransformType

from returns the TransformType value of an integer or of a field name, or an error if there is none.

fn Typeface.from_ct_font #

fn Typeface.from_ct_font(ct_font voidptr) !&Typeface

Typeface.from_ct_font wraps (and retains) an existing CTFontRef, like SkMakeTypefaceFromCTFont(). Glyphs are sized from copies of this font.

fn Typeface.from_data #

fn Typeface.from_data(data []u8) !&Typeface

Typeface.from_data loads the first face of TrueType/OpenType font data.

fn Typeface.from_file #

fn Typeface.from_file(path string) !&Typeface

Typeface.from_file loads the first face of a font file.

enum ClipOp #

enum ClipOp {
	intersect
	difference
}

ClipOp combines a clip shape with the current clip, like SkClipOp.

enum Corner #

enum Corner {
	upper_left
	upper_right
	lower_right
	lower_left
}

Corner indexes radii in clockwise order, starting at the top-left corner.

enum FontEdging #

enum FontEdging {
	alias
	antialias
	subpixel_antialias
}

enum FontHinting #

enum FontHinting {
	none
	slight
	normal
	full
}

enum GradientKind #

enum GradientKind {
	linear
	radial
}

enum PaintStyle #

enum PaintStyle {
	fill
	stroke
	stroke_and_fill
}

enum PathConvexity #

enum PathConvexity {
	unknown
	convex_cw
	convex_ccw
	convex_degenerate
	concave
}

enum PathDirection #

enum PathDirection {
	cw
	ccw
}

enum PathFillType #

enum PathFillType {
	winding
	even_odd
	inverse_winding
	inverse_even_odd
}

enum PathVerb #

enum PathVerb {
	move
	line
	quad
	conic
	cubic
	close
}

enum RRectType #

enum RRectType {
	empty
	rect
	oval
	simple
	nine_patch
	complex
}

RRectType classifies a rounded rectangle exactly like SkRRect::Type.

enum StrokeCap #

enum StrokeCap {
	butt
	round
	square
}

enum StrokeJoin #

enum StrokeJoin {
	miter
	round
	bevel
}

enum TileMode #

enum TileMode {
	clamp
	repeat
	mirror
	decal
}

enum TransformType #

enum TransformType {
	identity
	simple_rect_stays_rect // positive scale and translation
	rect_stays_rect        // also axis flips and 90-degree rotations
	affine
	perspective
	invalid
}

TransformType classifies a transform like skgpu::graphite::Transform::Type.

struct Color4f #

struct Color4f {
pub:
	r f32
	g f32
	b f32
	a f32
}

Color4f is an sRGB color with float components, not premultiplied unless stated otherwise.

fn (Color4f) premul #

fn (c Color4f) premul() Color4f

premul returns the premultiplied color, {r * a, g * a, b * a, a}.

fn (Color4f) is_opaque #

fn (c Color4f) is_opaque() bool

fn (Color4f) to_rgba8 #

fn (c Color4f) to_rgba8() [4]u8

to_rgba8 converts to 8-bit components like Sk4f_toL32: scale, add 0.5, pin and truncate.

fn (Color4f) to_sk_color #

fn (c Color4f) to_sk_color() !u32

to_sk_color converts to an 0xAARRGGBB SkColor like SkColor4f::toSkColor(). Components outside [0, 1] do not fit the 8-bit blitters and are rejected.

struct Font #

struct Font {
pub mut:
	typeface         &Typeface = unsafe { nil }
	size             f32       = 12
	scale_x          f32       = 1
	skew_x           f32
	edging           FontEdging  = .antialias
	hinting          FontHinting = .normal
	subpixel         bool
	linear_metrics   bool
	embolden         bool
	baseline_snap    bool = true
	embedded_bitmaps bool
}

Font holds the settings of an SkFont. The defaults are SkFont's.

struct GpuContext #

@[heap]
struct GpuContext {
mut:
	owns_gfx           bool
	shaders            []GpuShaderEntry
	pipelines          []GpuPipelineEntry
	rrect_vertices     gfx.Buffer
	rrect_indices      gfx.Buffer
	quad_vertices      gfx.Buffer
	quad_indices       gfx.Buffer
	wedge_vertices     gfx.Buffer
	wedge_indices      gfx.Buffer
	instances          gfx.Buffer
	instance_capacity  int
	msaa_load_shader   gfx.Shader
	msaa_load_pipeline gfx.Pipeline
	msaa_load_sampler  gfx.Sampler
	// The dither LUT of gradient paints and its nearest, repeating sampler.
	dither_lut     gfx.Image
	dither_sampler gfx.Sampler
	// The nearest, clamping sampler of layer images.
	image_sampler gfx.Sampler
}

GpuContext owns the GPU resources shared by all surfaces: shaders, pipelines and the static vertex data of the render steps. It uses the application's sokol.gfx context, or sets up a headless Metal one when sokol.gfx is not initialized yet.

fn (GpuContext) free #

fn (mut ctx GpuContext) free()

free releases the context's GPU resources, and shuts sokol.gfx down if the context set it up.

fn (GpuContext) precompile #

fn (mut ctx GpuContext) precompile()

precompile creates every shader and pipeline that solid-color draws may use, so later draws compile nothing. Embedders whose allocations are scoped can call it where long-lived allocations belong. Gradient pipelines, of which a program usually needs few, are created on first use; the caches have room for every pipeline, so that never reallocates them.

fn (GpuContext) new_surface #

fn (mut ctx GpuContext) new_surface(cfg GpuSurfaceConfig) !&GpuSurface

new_surface creates an offscreen surface, initially transparent black.

struct GpuSurface #

@[heap]
struct GpuSurface {
pub:
	width        int
	height       int
	sample_count int
mut:
	ctx         &GpuContext = unsafe { nil }
	color       gfx.Image
	msaa        gfx.Image
	depth       gfx.Image
	attachments gfx.Attachments
	draws       []GpuDraw
	// The pass clears to this color unless the contents were written.
	clear_color Color4f
	load        bool
	depth_index u16
	transform   Transform
	bounds      BoundsManager
	pipelines   []PipelineKey
	uniforms    []PaintUniforms
	clip        ClipStack
	// Device's IntersectionTreeSet: per paint order, the bounds of the
	// stencil draws in each disjoint stencil set.
	disjoint map[u16][][]Rect
	// The MSAA attachments of a single-sampled surface whose pass contains a
	// draw that requires MSAA, like Graphite's discardable MSAA texture.
	dynamic_msaa        gfx.Image
	dynamic_depth       gfx.Image
	dynamic_attachments gfx.Attachments
	// The render target's size: the device size, except for layers, whose
	// textures are approximately sized (SkBackingFit::kApprox).
	texture_width  int
	texture_height int
	// The draw list's texture bindings, in insertion order.
	textures []TextureBinding
	// The canvas matrix (the global CTM) and this device's mapping from the
	// global coordinates (a translation for layers).
	ctm              Matrix = Matrix.identity()
	global_to_device Matrix = Matrix.identity()
	// The active layer, which receives the draws, clips and saves until the
	// save that created it is restored, and the restored layers this device
	// samples until it flushes.
	layer    &GpuSurface = unsafe { nil }
	retired  []&GpuSurface
	is_layer bool
	origin_x int
	origin_y int
	// The saves made on this device, and the canvas matrix of each.
	save_count     int
	saved_matrices []Matrix
	// An error of a layer's restore(), reported by the next flush().
	deferred_error string
}

GpuSurface records draws into a BGRA8 premultiplied render target and renders them like Skia Graphite does, so the pixels read back match a Graphite SkSurface with the same draws exactly.

fn (GpuSurface) save #

fn (mut s GpuSurface) save()

save mirrors SkCanvas::save(): the matrix and the clip can be restored later.

fn (GpuSurface) restore #

fn (mut s GpuSurface) restore()

restore mirrors SkCanvas::restore(): it restores the matrix and the clip of the matching save, recording the depth-only draws of the removed elements. Restoring the save of save_layer() draws the layer.

fn (GpuSurface) clip_rect #

fn (mut s GpuSurface) clip_rect(r Rect, op ClipOp, anti_alias bool) !

clip_rect clips later draws to r in local coordinates, like SkCanvas::clipRect() on a Graphite device.

fn (GpuSurface) clip_rrect #

fn (mut s GpuSurface) clip_rrect(rr RRect, op ClipOp, anti_alias bool) !

clip_rrect clips later draws to a rounded rectangle, like SkCanvas::clipRRect() on a Graphite device.

fn (GpuSurface) clip_path #

fn (mut s GpuSurface) clip_path(path Path, op ClipOp, anti_alias bool) !

clip_path clips later draws to a path, like SkCanvas::clipPath() on a Graphite device: rect and oval paths under axis-aligned transforms clip as rects and rrects; other paths become path elements, which Graphite draws into the depth attachment regardless of anti_alias. Paths of 50 or more verbs are not supported yet.

fn (GpuSurface) save_layer #

fn (mut s GpuSurface) save_layer(bounds ?Rect) !

save_layer mirrors SkCanvas::saveLayer() without a paint: later draws go to a transparent layer covering the device clip bounds (intersected with bounds, in local coordinates), which the matching restore() draws onto the device through the clip of the save.

fn (GpuSurface) draw_path #

fn (mut s GpuSurface) draw_path(path Path, paint Paint) !

draw_path draws a path like SkCanvas::drawPath() on a Graphite device. Paths that Graphite draws as rects, ovals or double rects use those renderers; other filled paths use the MSAA tessellation renderers (convex wedges, or stencil-and-cover wedges, with an inverse cover for inverse fills). It returns an error for draws that need renderers which are not ported yet (inverse strokes, large complex paths).

fn (GpuSurface) free #

fn (mut s GpuSurface) free()

fn (GpuSurface) clear #

fn (mut s GpuSurface) clear(color Color4f)

clear discards pending draws and fills the surface with color.

fn (GpuSurface) write_pixels #

fn (mut s GpuSurface) write_pixels(pixels voidptr, pitch int) !

write_pixels replaces the surface contents with BGRA8 premultiplied pixels, discarding pending draws.

fn (GpuSurface) set_matrix #

fn (mut s GpuSurface) set_matrix(m Matrix)

set_matrix replaces the local to device transform of later draws.

fn (GpuSurface) concat #

fn (mut s GpuSurface) concat(m Matrix)

concat multiplies the current matrix by the affine matrix m, like SkCanvas::concat(SkM44): the product is rounded like SkM44::setConcat().

fn (GpuSurface) draw_rect #

fn (mut s GpuSurface) draw_rect(r Rect, paint Paint) !

draw_rect draws a rectangle like SkCanvas::drawRect() on a Graphite device. It returns an error for draws that need renderers which are not ported yet.

fn (GpuSurface) draw_line #

fn (mut s GpuSurface) draw_line(x0 f32, y0 f32, x1 f32, y1 f32, paint Paint) !

draw_line strokes a line like SkCanvas::drawLine(): drawPoints() in lines mode with the paint as a stroke (or hairline) style.

fn (GpuSurface) draw_oval #

fn (mut s GpuSurface) draw_oval(r Rect, paint Paint) !

draw_oval draws an ellipse inscribed in r, like SkCanvas::drawOval().

fn (GpuSurface) draw_rrect #

fn (mut s GpuSurface) draw_rrect(rr RRect, paint Paint) !

draw_rrect draws a rounded rectangle like SkCanvas::drawRRect() on a Graphite device.

fn (GpuSurface) draw_drrect #

fn (mut s GpuSurface) draw_drrect(outer RRect, inner RRect, paint Paint) !

draw_drrect fills the area between two rounded rectangles, like SkCanvas::drawDRRect() on a Graphite device.

fn (GpuSurface) draw_msaa_trigger #

fn (mut s GpuSurface) draw_msaa_trigger()

draw_msaa_trigger records the effects of the draw that makes Graphite render a pass with 4x MSAA: a tiny transparent path at the origin, drawn with the stencil-and-cover path renderer, like force_msaa_render_pass() in Vox's native Graphite backend. It covers no samples, so it is not rendered, but it takes the next depth, an order, cache entries and bounds that change how the later draws are sorted and batched. Use it on 4x MSAA surfaces where the reproduced renderer drew that path.

fn (GpuSurface) read_pixels #

fn (mut s GpuSurface) read_pixels(pixels voidptr, pitch int) !

read_pixels renders the pending draws and copies the surface into BGRA8 premultiplied pixels with a row stride of pitch bytes.

fn (GpuSurface) flush #

fn (mut s GpuSurface) flush() !

flush renders the pending draws.

struct GpuSurfaceConfig #

@[params]
struct GpuSurfaceConfig {
pub:
	width  int
	height int
	// 4 renders with 4x MSAA like a Graphite pass that contains an MSAA draw;
	// 1 renders single-sampled.
	sample_count int = 1
}

GpuSurfaceConfig selects the size and sample count of a surface.

struct Gradient #

struct Gradient {
pub:
	kind GradientKind
	// The start and end points of a linear gradient, or the center of a
	// radial gradient in `p0`.
	p0     Point
	p1     Point
	radius f32
	// Unpremultiplied colors, and their positions in [0, 1]; without
	// positions the colors are evenly spaced.
	colors    []Color4f
	positions []f32
	tile_mode TileMode
	// Interpolates premultiplied colors, like
	// SkGradient::Interpolation::InPremul::kYes.
	premul       bool
	local_matrix Matrix = Matrix.identity()
}

Gradient is a linear or radial gradient shader, like SkShaders::LinearGradient() and SkShaders::RadialGradient() with colors in sRGB, interpolated in the destination color space.

struct Matrix #

struct Matrix {
pub:
	m [9]f32
}

Matrix is a 3x3 transform in SkMatrix's row-major order: [scale_x, skew_x, trans_x, skew_y, scale_y, trans_y, persp_0, persp_1, persp_2].

Create matrices with the constructors; the zero value Matrix{} is not a valid transform.

struct Paint #

struct Paint {
pub mut:
	color        Color4f = Color4f{0, 0, 0, 1}
	anti_alias   bool
	style        PaintStyle
	stroke_width f32
	miter_limit  f32 = 4
	join         StrokeJoin
	cap          StrokeCap
	// A gradient shades the draw instead of the color, whose alpha would
	// modulate it (only opaque colors are supported).
	gradient ?Gradient
	// Dither the shading, like SkPaint::setDither(); gradients require it.
	dither bool
mut:
	// The layer drawn by restore() (Graphite's image shader for drawSpecial).
	layer_image ?LayerImage
}

Paint holds the color, shader and style of a draw, like SkPaint.

struct Path #

struct Path {
pub:
	verbs     []PathVerb
	points    []Point
	weights   []f32
	fill_type PathFillType
mut:
	is_a PathIsA
}

Path is an immutable SkPath.

fn (Path) is_inverse_fill #

fn (p Path) is_inverse_fill() bool

fn (Path) is_empty #

fn (p Path) is_empty() bool

fn (Path) bounds #

fn (p Path) bounds() Rect

bounds mirrors SkPath::getBounds(): the bounds of the points, ignoring a trailing move unless it is the only verb.

fn (Path) is_finite #

fn (p Path) is_finite() bool

fn (Path) is_line #

fn (p Path) is_line() ?(Point, Point)

is_line mirrors SkPath::isLine().

fn (Path) is_oval #

fn (p Path) is_oval() ?Rect

is_oval mirrors SkPath::isOval(): only paths made by addOval alone.

fn (Path) is_last_contour_closed #

fn (p Path) is_last_contour_closed() bool

fn (Path) is_rect #

fn (p Path) is_rect() ?(Rect, bool)

is_rect mirrors SkPath::isRect(): the rectangle and whether it is closed.

fn (Path) convexity #

fn (p Path) convexity() PathConvexity

convexity mirrors SkPathPriv::ComputeConvexity().

fn (Path) is_convex #

fn (p Path) is_convex() bool

fn (Path) is_even_odd #

fn (p Path) is_even_odd() bool

is_even_odd reports whether the fill rule, ignoring inversion, is even-odd.

struct PathBuilder #

struct PathBuilder {
mut:
	verbs     []PathVerb
	points    []Point
	weights   []f32
	fill_type PathFillType
	last_move int = -1
	is_a      PathIsA
}

PathBuilder mirrors SkPathBuilder for the verbs gg.canvas supports.

fn (PathBuilder) set_fill_type #

fn (mut b PathBuilder) set_fill_type(ft PathFillType)

fn (PathBuilder) move_to #

fn (mut b PathBuilder) move_to(x f32, y f32)

fn (PathBuilder) line_to #

fn (mut b PathBuilder) line_to(x f32, y f32)

fn (PathBuilder) quad_to #

fn (mut b PathBuilder) quad_to(x1 f32, y1 f32, x2 f32, y2 f32)

fn (PathBuilder) conic_to #

fn (mut b PathBuilder) conic_to(x1 f32, y1 f32, x2 f32, y2 f32, w f32)

fn (PathBuilder) cubic_to #

fn (mut b PathBuilder) cubic_to(x1 f32, y1 f32, x2 f32, y2 f32, x3 f32, y3 f32)

fn (PathBuilder) close #

fn (mut b PathBuilder) close()

fn (PathBuilder) add_oval #

fn (mut b PathBuilder) add_oval(r Rect, dir PathDirection, start int)

add_oval mirrors SkPathBuilder::addOval(oval, dir, index).

fn (PathBuilder) add_rect #

fn (mut b PathBuilder) add_rect(r Rect, dir PathDirection, start int)

add_rect mirrors SkPathBuilder::addRect(rect, dir, index); SkPathBuilder's default start index is 0.

fn (PathBuilder) add_rrect #

fn (mut b PathBuilder) add_rrect(rr RRect, dir PathDirection, start int)

add_rrect mirrors SkPathBuilder::addRRect(rrect, dir, index): rects and ovals become those contours. SkPathBuilder's default start index is 6 for clockwise and 7 for counter-clockwise contours.

fn (PathBuilder) detach #

fn (mut b PathBuilder) detach() Path

detach returns the path and resets the builder, like SkPathBuilder::detach().

fn (PathBuilder) arc_to_svg #

fn (mut b PathBuilder) arc_to_svg(rad_x f32, rad_y f32, angle f32, large bool, sweep PathDirection, x f32, y f32)

arc_to_svg mirrors SkPathBuilder::arcTo(SkPoint rad, angle, arcLarge, arcSweep, endPt): an SVG elliptical arc from the last point, added as conics.

struct Point #

struct Point {
pub mut:
	x f32
	y f32
}

Point is a 2D point or vector.

struct RRect #

struct RRect {
pub:
	rect  Rect
	radii [4]Point
	typ   RRectType
}

RRect is a rectangle with elliptical corners. Construction normalizes the radii exactly like SkRRect (clamping, proportional scaling and type classification), because renderers depend on the resulting values.

fn (RRect) is_rect #

fn (rr RRect) is_rect() bool

fn (RRect) is_empty #

fn (rr RRect) is_empty() bool

fn (RRect) is_oval #

fn (rr RRect) is_oval() bool

fn (RRect) bounds #

fn (rr RRect) bounds() Rect

fn (RRect) radius #

fn (rr RRect) radius(corner Corner) Point

fn (RRect) inset #

fn (rr RRect) inset(dx f32, dy f32) RRect

inset mirrors SkRRect::inset(): the rectangle is inset by (dx, dy) and every non-zero radius shrinks by the same amount. Negative amounts outset.

fn (RRect) outset #

fn (rr RRect) outset(dx f32, dy f32) RRect

outset mirrors SkRRect::outset().

fn (RRect) is_simple #

fn (rr RRect) is_simple() bool

is_simple reports SkRRect::isSimple(): all corners share one radius pair.

struct RasterSurface #

struct RasterSurface {
pub:
	width  int
	height int
pub mut:
	pixels []u32
	props  SurfaceProps
	matrix Matrix = Matrix.identity()
}

RasterSurface is a CPU pixel buffer in BGRA8 premultiplied order (each u32 is 0xAARRGGBB, Skia's kN32 SkPMColor on little-endian Apple platforms) that draws like an SkCanvas over SkSurfaces::WrapPixels() with an sRGB color space.

fn (RasterSurface) clear #

fn (mut s RasterSurface) clear(pm_color u32)

clear fills the surface with a premultiplied 0xAARRGGBB value.

fn (RasterSurface) set_matrix #

fn (mut s RasterSurface) set_matrix(m Matrix)

fn (RasterSurface) draw_glyphs #

fn (mut s RasterSurface) draw_glyphs(font Font, glyphs []u16, positions []Point, origin Point, paint Paint) !

draw_glyphs draws positioned glyphs like SkCanvas::drawTextBlob() with a single positioned run: glyph i is placed at origin + positions[i].

struct RasterSurfaceConfig #

@[params]
struct RasterSurfaceConfig {
pub:
	width  int
	height int
	props  SurfaceProps
}

struct Rect #

struct Rect {
pub:
	vals [4]f32
}

Rect is an axis-aligned rectangle. Like Skia Graphite's geometry Rect it stores [left, top, -right, -bottom], so that the derived values (width, center, intersections, ...) are computed with the same floating-point operations and therefore round identically.

fn (Rect) left #

@[inline]
fn (r Rect) left() f32

fn (Rect) top #

@[inline]
fn (r Rect) top() f32

fn (Rect) right #

@[inline]
fn (r Rect) right() f32

fn (Rect) bottom #

@[inline]
fn (r Rect) bottom() f32

fn (Rect) width #

@[inline]
fn (r Rect) width() f32

width returns -(left + -right), which equals Skia's right - left.

fn (Rect) height #

@[inline]
fn (r Rect) height() f32

fn (Rect) center #

fn (r Rect) center() Point

center returns (left * 0.5 + right * 0.5, top * 0.5 + bottom * 0.5).

fn (Rect) area #

fn (r Rect) area() f32

fn (Rect) is_empty_negative_or_nan #

fn (r Rect) is_empty_negative_or_nan() bool

is_empty_negative_or_nan reports a non-positive width or height, or NaN.

fn (Rect) inset #

fn (r Rect) inset(d f32) Rect

fn (Rect) outset #

fn (r Rect) outset(d f32) Rect

fn (Rect) intersect #

fn (r Rect) intersect(o Rect) Rect

fn (Rect) join #

fn (r Rect) join(o Rect) Rect

fn (Rect) round #

fn (r Rect) round() Rect

round rounds each edge with floor(x + 0.5), like SkRect::round().

fn (Rect) round_out #

fn (r Rect) round_out() Rect

round_out returns the smallest integer rectangle containing r.

fn (Rect) sorted #

fn (r Rect) sorted() Rect

sorted swaps inverted edges.

fn (Rect) nearly_equals #

fn (r Rect) nearly_equals(o Rect, epsilon f32) bool

fn (Rect) intersects #

fn (r Rect) intersects(o Rect) bool

intersects reports a positive-area overlap, like Graphite's Rect::intersects().

fn (Rect) contains #

fn (r Rect) contains(o Rect) bool

fn (Rect) is_finite #

fn (r Rect) is_finite() bool

struct SurfaceProps #

struct SurfaceProps {
pub:
	text_contrast f32 = 0.5
	text_gamma    f32
}

SurfaceProps mirrors the text-related parts of SkSurfaceProps. Only an unknown pixel geometry is supported (no LCD masks).

struct Transform #

struct Transform {
pub:
	matrix Matrix
	typ    TransformType
	// The inverse, for types up to `.affine`.
	inverse   Matrix
	min_scale f32
	max_scale f32
}

Transform caches the classification, inverse and scale factors of a local to device matrix, like Graphite's Transform for an SkM44 created from an SkMatrix.

fn (Transform) valid #

fn (t Transform) valid() bool

fn (Transform) local_aa_radius #

fn (t Transform) local_aa_radius() f32

local_aa_radius returns the local-space distance that maps to at least one device pixel, like Transform::localAARadius() for non-perspective matrices.

fn (Transform) map_rect #

fn (t Transform) map_rect(r Rect) Rect

map_rect maps a rectangle to device space.

fn (Transform) inverse_map_rect #

fn (t Transform) inverse_map_rect(r Rect) Rect

inverse_map_rect maps a device-space rectangle back to local space. Like Graphite it classifies the inverse with the forward transform's type.

struct Typeface #

@[heap]
struct Typeface {
pub:
	id u32
mut:
	ct_font          voidptr
	has_color_glyphs bool
}

Typeface is a font face loaded from font data through CoreText, like SkTypeface_Mac created by SkFontMgr_New_CoreText()->makeFromStream().

fn (Typeface) free #

fn (mut t Typeface) free()

free releases this face's retained font and cached strikes. It is idempotent; do not draw with the face afterwards. Text drawing and cleanup must be serial.