# SkiaSharp Compatibility Log This document records the implemented SkiaSharp 4.148 compatibility surface, retained rendering behavior, algorithm choices, and complexity guarantees for `ProGPU.SkiaSharp`. The concise package overview remains in the [repository README](../README.md#skiasharp-compatibility-shim). Update this record when compatibility behavior, supported formats, algorithms, or complexity guarantees change. ## Implementation Record Encoded images are decoded on the CPU before their pixels enter the GPU texture path. PNG-backed ICO/CUR frames use the common image decoder; bitmap-backed frames support legacy core and modern information headers, indexed 1/4/8-bit color, RLE4/RLE8 streams, RGB555, RGB565 and other validated 16/32-bit channel masks, 24-bit BGR, 32-bit BGRA, and Windows AND-mask transparency. Keeping decode and upload separate preserves deterministic pixel semantics and avoids initializing a WebGPU device for metadata or bitmap-only workflows. CPU bitmap resizing follows Skia's pixel-center mapping and alpha representation. Nearest and linear modes use fixed one- and four-sample footprints; cubic mode evaluates the requested Mitchell-Netravali B/C kernel over a fixed 4x4 footprint, preserving the distinction between Mitchell and Catmull-Rom. Source rows are read with their actual stride and color order, and output is converted to RGBA8888, BGRA8888, RGB888x, or RGB565 without forcing a WebGPU upload. Nearest sampling is a direct `O(destination pixels)` pass with no source-sized temporary allocation, and same-format texels stay as raw copies. Linear and cubic sampling normalize source pixels once, then run in `O(source pixels + destination pixels)` and `O(source pixels + 16 * destination pixels)` time with `O(source pixels)` temporary storage. `SKPathBuilder` implements the complete SkiaSharp 4.148 builder surface directly over retained `PathGeometry`. Snapshot and transformed/offset path insertion clone `N` segments in `O(N)` time and storage, while detach transfers the current path and restores an empty winding builder in `O(1)`. Relative commands preserve Skia's current point after close; extend mode merges the first source contour, and reverse insertion reverses contour order, segment order, cubic controls, and arc sweep without flattening. Endpoint, oval, round-rectangle, circle, and tangent arcs remain analytic `ArcSegment` values. A rational conic is represented by 16 midpoint-matched quadratic spans, giving bounded `O(1)` work and storage per conic with a sampled error below `0.001`; native rectangle and round-rectangle direction/start-index rules retain their original contour topology. Primitive construction and metadata-only builder use never initialize WebGPU. Legacy `SKPath` exposes the complete SkiaSharp 4.148 path, primitive-query, conversion, iterator, and operation-builder surface while retaining ProGPU's public `PathGeometry` bridge. Raw and force-close iterators construct a CPU operation view in `O(N + Q)` time and storage for `N` retained segments and `Q` emitted quarter arcs. Consecutive compatible analytic arcs are coalesced before that view is split at exact 90-degree boundaries, so a retained two-segment oval reports Skia's four rational conics and a 200-degree arc reports 90/90/20-degree conics without increasing render-time geometry. Rational conics keep one internal marker over their 16 midpoint-matched render spans, preserving one conic verb and its weight across clone, transform, offset, extend, and reversal. Point, verb, segment-mask, convexity, and primitive recognition are `O(N)` CPU queries; recursive `ConvertConicToQuads` with subdivision power `p` uses `O(2^p)` time and output storage. Path construction, topology queries, SVG serialization, iterator creation, and fill-rule conversion do not initialize WebGPU. `SKRoundRect` keeps normalized bounds, four corner radii, and the derived empty/rectangle/oval/simple/nine-patch/complex classification as retained CPU geometry. Construction applies Skia's CSS corner-overlap rule: it finds the minimum side-to-radius ratio in double precision, scales every radius by that common factor, and makes bounded ULP corrections so adjacent float radii never exceed a side. Containment evaluates at most four ellipse equations. Axis-preserving transforms map the eight tangent points and four corner controls, then reconstruct radii from the mapped contour; this preserves corner ordering, mirrors, quarter turns, and native floating-point subtraction while rejecting skew, arbitrary rotation, and perspective. Setters, classification, validation, containment, inset/outset, offset, and transform use fixed `O(1)` work and storage without WebGPU initialization. The public `Radii` ownership boundary returns one four-point copy, while renderer access, `GetRadii`, classification, validation, and transform use the retained array or stack spans and allocate nothing. `SKPoint`, `SKSize`, `SKSizeI`, `SKRect`, and `SKRectI` implement the complete SkiaSharp 4.148 value surfaces as CPU-only `O(1)` operations with no heap or GPU state. Point normalization, distance, reflection, arithmetic, mutation, equality, and formatting preserve native float behavior, including NaN normalization of the zero vector. Size conversion uses checked truncation, and integer rectangle floor/ceiling modes round each edge inward or outward according to contour direction. Float and integer rectangles retain SkiaSharp's half-open point containment, inclusive versus strict intersection distinction, degenerate edge intersections, standardized coordinates, centered aspect fit/fill, and exact empty/union semantics. Point-based `SKCanvas.DrawLine` and `DrawCircle` overloads add no adaptation allocation or duplicate rendering path; they forward directly to the established scalar implementations. `SKColor` and `SKColorF` are immutable CPU value types with the complete SkiaSharp 4.148 packed-channel, parsing, mutation-copy, equality, clamp, HSL, and HSV surfaces. Conversion uses the native `0.001` chroma epsilon, the precomputed float `1 / 255` byte scale, and clamped nearest-byte rounding, preserving native one-ULP float results and packed ARGB output. Every operation has fixed `O(1)` time and storage, allocates no render resources, and does not initialize WebGPU. `SKColors.Empty` aliases the packed zero value while the named color table remains static immutable data. `SKCubicResampler` and `SKSamplingOptions` are immutable `O(1)` sampling descriptors. Filter, mipmap, cubic, and anisotropic constructors initialize only their native mode fields; `default` keeps anisotropy disabled at zero, while the integer constructor clamps its maximum to at least one. Mitchell, Catmull-Rom, and custom B/C coefficients retain exact value identity and flow through the existing renderer without a second translation or allocation. Descriptor creation performs no image sampling, texture upload, shader compilation, or WebGPU initialization. Color-space transfer functions retain Skia's named sRGB, gamma 2.2, linear, Rec.2020, PQ, and HLG parameter sets. Scalar evaluation reproduces skcms's bounded `O(1)` bit-level log2/exp2 approximation, signed sRGB-like branch, and dedicated HDR equations; inversion preserves the native continuity check and returns empty for non-invertible PQ/HLG markers. XYZ matrices keep nine floats inline rather than an array reference. Equality, indexing, inversion, and concatenation are allocation-free `O(1)` operations; inversion uses Skia's double-precision cofactor path and concatenation uses row-major `A * B` order. Only the public `Values` ownership boundary allocates or copies its fixed nine elements. These CPU operations do not initialize WebGPU. Font outline APIs preserve Skia's separation between glyph-local geometry and placement metrics. `GetGlyphPath` and `GetTextPath` materialize the font transform as `x' = x * ScaleX + y * SkewX`; horizontal advances use `ScaleX` but not `SkewX`. Path fallbacks, text-blob intercepts, and the canonical 64-unit `GetGlyphPaths` callback therefore consume already transformed outlines and never apply shear twice. Retained fill-text recording bypasses those path APIs and carries `ScaleX` and `SkewX` into a glyph run without rescaling its already-shaped positions. The compositor applies that transform only to glyph-local geometry: vector outlines reuse transform-aware path-cache entries, while atlas text reuses the existing constant-cost vertex shear and scaled quad bounds. `Embolden` follows Skia's `Size / 32` mitered stroke-and-fill rule; generated stroke contours are normalized to the glyph's dominant winding before they are appended, so overlapping segments cannot erase original coverage. Emboldened blobs record that widened path once, while ordinary fonts retain the unchanged glyph-run fast path. `SKFont` exposes the complete SkiaSharp 4.148 text/glyph surface for UTF-8, native-endian UTF-16, native-endian UTF-32, and glyph-ID buffers. Encoded APIs first validate and count the complete run, then perform a second allocation-free pass to map glyphs, measure, or write caller spans. This preserves one glyph per Unicode scalar, rejects a malformed encoded run without partial output, and lets `BreakText` report consumed UTF-16 code units or encoded bytes exactly as Skia does. Span-returning work is `O(N)` time and `O(1)` auxiliary space for `N` encoded units; array-returning overloads allocate one exact `O(G)` result for `G` glyphs. Text-on-path construction caches repeated glyph outlines and morphs each line, quadratic, conic, and cubic point through a high-resolution contour measure. For `P` baseline samples and `S` glyph path segments, setup is `O(P)`, morphing is `O(G * S * log P)`, and cached glyph-path storage is `O(U * S)` for `U` unique glyphs in the call. Legacy `SKPaint` text APIs are compatibility adapters over one paint-owned `SKFont` snapshot. Constructing from a font copies its typeface, metrics, scale, skew, hinting, and emboldening state; cloning and `ToFont` also return independent snapshots. `IsAntialias` and `LcdRenderText` derive alias, grayscale-antialias, or subpixel font edging exactly as Skia does. Every string, span, encoded byte, pointer, glyph, measurement, break, position, width, path, and intercept overload delegates to the validated `SKFont`/`SKTextBlob` engines instead of maintaining another decoder or glyph loop. State reads and copies are `O(1)`; encoded adapters retain `O(N)` time and `O(1)` auxiliary parsing space, array-returning APIs allocate `O(G)`, and intercept adapters retain `O(G * S)` path analysis for `G` glyphs with `S` segments. No legacy paint text operation initializes WebGPU. `SKPaint.GetFillPath` exposes the complete path, builder, cull-hint, resolution-scale, and matrix overload family over one CPU stroker. Fill-only conversion preserves the source fill rule; stroke and stroke-and-fill results use winding coverage. Cull rectangles remain optimization hints and never clip output, while scalar and matrix overloads choose a bounded curve schedule `Q = clamp(ceil(24 * sqrt(max(1, resScale))), 24, 192)`. For `S` retained segments, conversion is `O(S * Q)` time and output storage. Successful calls transactionally replace either destination, failed legacy path calls preserve their destination, and failed builder calls expose the native source-snapshot fallback. Source/destination aliasing is safe. A positive-width stroke succeeds even when an empty path or butt-capped degenerate contour produces no coverage; only a zero-width device hairline has no device-independent fill path. No overload initializes WebGPU. `SKPathEffect` is an immutable, paint-retained `SKObject` graph with the complete dash, trim, corner, discrete, one-dimensional stamp, two-dimensional line/path lattice, sum, and compose factory surface. Factories snapshot mutable paths and interval arrays once; composition evaluates `outer(inner(path))`, while sum applies both children to the original path. Ordinary dash strokes retain the analytic pen fast path. Other effects materialize one bounded CPU path before retained GPU recording: measured dash/trim/stamp work is `O(S + G)`, line-corner rounding is `O(S)`, discrete output is `O(L / d)`, line lattices are `O(R * E log E)`, and path lattices are `O(C * V)` for source complexity `S`, generated elements `G`, contour length `L`, discrete spacing `d`, lattice rows `R`, flattened edges `E`, candidate cells `C`, and stamp verbs `V`. Line lattices update the retained stroke width; path lattices switch to fill exactly once. Generated geometry is capped at one million elements, invalid or perspective lattices fall back without partial commands, and factories/materialization never initialize WebGPU or perform readback. `SKBlender` and `SKPaint.Blender` preserve Skia's shared paint state in `O(1)`: mode factories validate every `SKBlendMode`, explicit `SrcOver` paint assignment uses the native null fast path, custom blender assignment survives cloning, and reset clears it. Built-in blenders reuse the retained compositor blend scope. `Modulate` is a fixed-function GPU blend with `C = Cs * Cd` and `A = As * Ad`; no destination copy or custom shader is needed. Arithmetic factories retain finite coefficients and premultiplication policy, but drawing currently throws before recording because the required general destination-sampling compositor path is not yet implemented. This explicit boundary prevents a custom arithmetic formula from silently rendering as `SrcOver`. `SKShader` exposes the complete SkiaSharp 4.148 factory surface as an immutable retained `SKObject` graph. Color, gradient, sweep, noise, picture, and image leaves snapshot caller state; `WithLocalMatrix` and `WithColorFilter` return new nodes and keep their source alive after public disposal. Nested local matrices retain Skia's parent-before-child order, while nested filters execute child-first. Gradient colors and positions are converted once at factory time, so later caller mutation cannot alter output and repeated brush creation only copies the compact stop transport. Up to four nested color filters are carried through drawing in inline state without a heap allocation. Ordinary leaves and source-over conical composition stay on the direct vector or tiled-texture path. General blend-mode and arithmetic composition evaluates destination and source over device coverage, combines them with the existing image-blend compute pipeline, applies filters, and clips target geometry exactly once; this preserves Porter-Duff alpha and antialiased edge coverage instead of blending already-clipped children. A composed full-frame shader uses `O(P)` texel work and temporary storage for `P` device pixels, and `F` post-filters add `O(F * P)` work without CPU readback. Sweep gradients retain arbitrary finite start/end angles in picture archives and map angle to `t` in `O(1)` fragment work before clamp, repeat, mirror, or decal handling; equal-angle repeat/mirror resolves once to the average color and equal-angle decal resolves to empty coverage. `SKImage` is a GPU-backed `SKObject` with SkiaSharp-shaped ownership and API visibility; its ProGPU texture and construction seams remain internal. Metadata, validity, and unique-ID queries are allocation-free `O(1)`. Bitmap construction uploads `P` pixels in `O(P)` time and GPU storage, while shader creation snapshots the texture once in `O(P)` GPU copy bandwidth and then records `T` visible tiles in `O(T)`. Sampling options, cubic coefficients, tile modes, and local matrices remain retained state. Raw image shaders bypass color-space conversion; ordinary image shaders preserve the existing sRGB conversion path. Pixel reads perform one full `O(P)` texture readback and an `O(D)` stride-aware conversion into `D` destination pixels; scaling adds the selected CPU kernel cost and `O(D)` destination storage. Invalid pointers, strides, and empty destinations return `false` without partial writes, and `PeekPixels` reports unavailable storage because a GPU image cannot expose a stable CPU pointer. `SKColorFilter` exposes the complete SkiaSharp 4.148 factory surface as an immutable `SKObject` graph. RGBA and HSLA matrices copy exactly 20 finite coefficients, table filters copy exactly 256 entries per channel, and later caller mutation cannot affect a filter. Blend factories canonicalize Clear and opaque/transparent SrcOver and return null for Skia's no-op combinations. Gamma conversion uses stable disposal-protected singletons, lighting ignores argument alpha, compose evaluates `outer(inner(color))`, and lerp mixes child results in premultiplied space. Luma-to-alpha writes black RGB and scales luminance by source alpha. High contrast converts sRGB to linear light, then applies optional grayscale, brightness/lightness inversion, and the pinned `(1 + c) / (1 - c)` contrast scale before converting back. Ordinary blend, RGBA matrix, luma, gamma-table, and channel-table leaves keep their existing direct or single-pass GPU paths. HSLA and high-contrast leaves lazily compile one cached resource-backed compute pipeline; compose chains child-first and lerp reuses the arithmetic compositor, with no CPU readback. Construction is `O(1)` except bounded `O(20)` matrix and `O(256)` table snapshots. For `F` evaluated leaves over `P` texels, GPU work is `O(F * P)` and live temporary storage is `O(D * P)` for graph depth `D`; every leaf performs fixed `O(1)` arithmetic per texel. `SKImageFilter` is a SkiaSharp-shaped `SKObject` whose complete SkiaSharp 4.148 factory surface builds an immutable retained DAG without touching WebGPU. Blur, shadow, color, arithmetic and blender composites, morphology, displacement, convolution, merge, offset, image, shader, picture, lighting, tile, compose, matrix-transform, and magnifier overloads normalize into shared node representations. Null graph inputs retain Skia's source-graphic fallback, blur defaults to Decal tiling, default image sampling is Mitchell, kernels and merge spans are copied once, and crop rectangles remain node metadata until evaluation. Ordinary node construction is `O(1)` time/storage; a `K`-coefficient convolution and `N`-input merge use `O(K)` and `O(N)` time/storage. Layer evaluation memoizes by `(source texture, node, color-space policy)`, so shared nodes remain `O(V + E)` per source context and compose can safely rebind the outer graph's source to the inner result. Matrix filters conjugate the local matrix through the layer transform and reuse the sampled texture render path. Magnifier crops and fits its child input first, restricts output to the lens/child intersection, lazily creates one compute pipeline, and applies Skia's squared inset-distance lens weighting with circular `2 * inset` corner transitions; nearest, bilinear, and bicubic modes use one, four, and sixteen reads per output texel with `O(1)` local storage. Built-in and arithmetic `SKBlender` image filters reuse the existing blend and arithmetic compute passes rather than silently changing formulas. `SKTypeface` exposes glyph counts, PostScript names, fixed-pitch metadata, and exact SFNT table access directly from the parsed font. Table tags preserve directory order; table payloads remain borrowed `ReadOnlyMemory` internally and are copied only when the SkiaSharp API transfers ownership to a caller. Metadata queries are `O(1)`, tag enumeration is `O(T)` time and storage for `T` tables, and a table read is `O(B)` for `B` copied bytes. Legacy glyph APIs delegate to the same validated `SKFont` encoding engine instead of maintaining a second character-map implementation. `SKTypeface.Empty` short-circuits glyph, metric, and table surfaces without initializing any rendering pipeline. Variable-font clone and design-position APIs remain intentionally absent until the parsed `fvar` axes can be applied to outlines and metrics rather than reported as unsupported no-ops. `SKPath` metadata is derived directly from the retained figure/segment representation. Point and verb enumeration preserves Skia's move/line/quad/conic/cubic contract, rectangle queries recover closure and winding, oval and rounded-rectangle queries recover their original bounds and corner radii, and linear contour convexity uses consistent cross-product signs. Retained elliptical arcs stay analytic for rendering quality; metadata enumeration alone splits an arc into rational conics spanning at most 90 degrees, including a tolerance at exact quadrant boundaries so a native half-oval remains two conics. Metadata scans are `O(S)` time and `O(1)` auxiliary storage for `S` retained segments. Caller-owned point snapshots are `O(P)` storage for `P` returned points, while single-point lookup remains `O(S)` without initializing WebGPU or flattening the rendered path. Path iteration exposes Skia's nested raw and cooked iterator identities. Iterator construction snapshots `O(V)` compact operations for `V` path verbs, after expanding each analytic arc to at most four rational-conic operations; each `Next`, `Peek`, and state query is then `O(1)`. Raw iteration preserves untouched output slots and exact conic weights, while cooked iteration inserts one closing line and close verb for closed or force-closed contours. Explicit conic identity and weight use weak segment metadata that follows copies, path appends, and in-place transforms without extending segment lifetime. Cardinal trigonometric values are snapped only within epsilon of `-1`, `0`, or `1`, matching Skia's exact oval controls without changing general rotated arcs. Iteration is CPU-only and never flattens arcs to line lists, initializes WebGPU, submits rendering, or reads pixels. Relative path commands resolve one current point per verb, including the origin for an empty path and the contour start after `Close`; control points and endpoints are all offset from that same point. In-place offset and transform preserve the active contour and conic metadata, so subsequent commands append without an artificial move. Destination transforms replace the target transactionally from a transformed deep copy, preserve source fill/conic state, and special-case source/target aliasing to transform exactly once. Relative commands are allocation-free `O(1)` mutations; offset and in-place transform are `O(S)` for `S` segments; destination transform is `O(S)` time and storage. `Rewind` follows native Skia by clearing geometry and restoring winding fill. Rational-conic conversion emits `2^P` ordinary quadratics and `2^(P+1)+1` points for subdivision exponent `P`. Each half split normalizes the two child conics and updates their shared weight to `sqrt((1+w)/2)`, matching Skia's deeper control points rather than recursively interpolating unnormalized homogeneous triples. Conversion is `O(2^P)` time/output storage with `O(P)` recursion depth; managed overloads validate exponent and destination capacity so malformed requests cannot reproduce native buffer overruns. SVG path serialization walks the cooked iterator in `O(V)` time and `O(V)` output for `V` verbs, preserves invariant round-trip float formatting, expands every conic to Skia's fixed 32 ordinary quadratic commands so its rational shape survives SVG, and includes the cooked closing line before `Z`. Both operations are CPU-only. `SKPathBuilder` owns one retained path and forwards mutations directly into analytic line, quadratic, conic, cubic, arc, and shape storage. Snapshot copies `O(S)` retained segments, detach transfers the current path in `O(1)` and installs an empty winding path, while reset and fill state follow native ownership semantics. `SKPathMeasure` walks raw verbs once and builds a cumulative contour table with `Q = min(64, 1 + ceil(4 * sqrt(resScale)))` samples per curve, matching Skia's sublinear precision growth instead of multiplying every text-on-path curve by a large linear factor. Setup is `O(S * Q)` time/storage for `S` segments; position, tangent, and matrix queries use `O(log(S * Q))` distance lookup followed by exact analytic evaluation. Segment extraction retains original verb kinds: ordinary curves use De Casteljau slicing and rational conics use homogeneous slicing with normalized endpoint weights. This preserves output quality while avoiding per-query flattening, GPU initialization, submission, or readback. Degree-based oval arcs remain analytic retained segments and expand only through the shared rational-conic iterator. Partial sweeps preserve sign and start angle; `AddArc` maps a full sweep to two half arcs plus close, while rectangle `ArcTo` preserves Skia's distinct full-sweep connector-only behavior. Tangent arcs compute normalized corner vectors, `radius / tan(angle/2)` tangent points, and one signed small circular arc, with degenerate/radius-zero cases reduced to one line. Indexed rectangles rotate four corners; indexed rounded rectangles rotate eight line/arc boundary positions and omit a final straight edge because `Close` supplies it. Consecutive empty moves collapse to the latest move. Reverse append visits contours and segments in reverse order, swaps cubic controls, preserves quadratic/conic controls and weights, and reverses arc sweep. Arc and indexed-shape construction are bounded `O(1)` work; reverse append is `O(S)` time/storage for `S` segments. No construction helper flattens curves or initializes WebGPU. Path simplify and winding conversion use a CPU planar arrangement for closed linear contours. It computes all segment intersections, splits edges, classifies each fragment by original fill on both sides, discards internal fragments, orients surviving boundaries with fill on the right, deduplicates quantized directed edges, and stitches adjacency-indexed loops. For `E` source edges, `I` intersections, and `F = O(E + I)` fragments, work is `O(E^2 + E*F)` and storage is `O(E + I)`; hash deduplication and contour stitching are expected `O(F)`. Bowties split into faces, overlaps lose interior edges, and even-odd holes reverse for winding fill without GPU work. Curved paths use the existing exact GPU union solver only when a WebGPU context is already active; without one they preserve every analytic curve/conic and normalize only the requested fill rule, never flattening or initializing a device. Result overloads are alias-safe, and the instance boolean-op overload shares the established solver. `SKRegion` stores canonical, disjoint horizontal rectangle bands. Union, intersection, difference, reverse-difference, XOR, bulk rect assignment, and translation normalize y edges and merged x intervals, so bounds, rectangle/complex classification, containment, and region operations share one coverage model. Normalizing `R` input rectangles costs `O(R^2 log R)` time and `O(R)` storage in the worst case. Arbitrary path assignment clips to another region and samples pixel centers; raw path contours are flattened once with rational conic weights retained, then each pixel performs an allocation-free winding/even-odd scan. For `L` flattened edges and `A` candidate pixels, rasterization is `O(L + A*L)` time and `O(L + R)` storage with no per-pixel geometry allocation or GPU initialization. Rect/clip iterators snapshot `O(R)` bands and advance in `O(1)`; span iterators merge exclusive x-runs in `O(R log R)` setup and `O(1)` per span. Boundary paths preserve canonical coverage through retained rectangles. Canvas state follows Skia's one-based save-count contract while retaining a zero-based stack internally: `Save` and `SaveLayer` return the prior public count, `RestoreToCount` clamps at one, and `SKAutoCanvasRestore` unwinds all nested state exactly once. The read-stream hierarchy follows SkiaSharp ownership: `SKStream` is an `SKObject`, memory/file assets retain stable storage, and `SKAbstractManagedStream` dispatches reads, peeks, cursor queries, seeks, forks, and disposal through the managed callback contract. `SKManagedStream` reads directly into caller memory without an intermediate copy; seekable skips only advance the cursor in `O(1)`, while forward-only skips perform `O(N)` reads with one pooled buffer capped at 80 KiB. Unknown-length streams report EOF only after a short or zero read. `SKFileStream` reads a file once into immutable memory, so later codec reads are deterministic and `GetMemoryBase` exposes a stable pinned address. Opening, snapshots, and memory conversion are `O(B)` time and owned output for `B` bytes; ordinary reads are `O(N)` time with `O(1)` auxiliary space, cursor operations are `O(1)`, and none of these paths initializes WebGPU. Canvas clip metadata is cached beside matrix/opacity state rather than reconstructed from retained commands. Axis-aligned rectangle clips use Skia's nearest-device-pixel bounds, arbitrary path clips round outward, and rectangle differences simplify full-edge subtraction while interior holes retain conservative bounds and non-rectangular classification. Device queries are direct `O(1)` reads; local queries outset the device bounds by one raster pixel and inverse-map once through the current matrix in `O(1)`. Save/restore copies the fixed clip state, and `QuickReject` tests these active device bounds without allocating or walking clip history. Canvas annotations preserve Skia's raster contract: arbitrary, URL, named-destination, and link-destination metadata do not create pixels or retained GPU commands. Data overloads are allocation-free `O(1)` no-ops on raster canvases; string overloads return the caller-owned null-terminated ASCII `SKData` payload required by Skia's annotation API in `O(N)` time and storage for N characters. Document-specific annotation serialization remains isolated from ordinary scene compilation, so SVG raster rendering and annotation-heavy callers pay no GPU or command-list cost. Advanced `SKCanvasSaveLayerRec` layers reuse the existing offscreen compositor while preserving Skia's record contract. Ordinary layers retain the zero-snapshot path. A backdrop or `InitializeWithPrevious` request copies the pending parent command/buffer state once in `O(C + B)` time/storage for C commands and B pooled values, then renders already-flushed surface pixels and pending commands together into one previous-content texture. Backdrop filters run on that texture before child commands; active clips and layer bounds are replayed once. `F16ColorType` selects an RGBA16F target and matching format-specific compositor, while restore samples the result through the normal texture path. The feature adds a bounded two-pass GPU cost only when previous content is explicitly requested and releases cloned resource leases on restore, failure, or canvas disposal. Canvas ownership follows Skia's raster/GPU distinction. `Surface` returns the exact owning `SKSurface` while attached; standalone, bitmap, and picture canvases return null. `Context` returns the caller's `GRRecordingContext` for direct GPU surfaces and null for raster semantics. `GRContext` now derives from the Skia-compatible `GRRecordingContext` base and reports the Dawn backend, abandonment state, texture/render-target limits, and sample support without probing or initializing another device. Both canvas properties are identity-preserving allocation-free `O(1)` reads; the retained ProGPU command context remains an internal `DrawingContext` and cannot collide with the public Skia API. Writable streams expose the complete SkiaSharp primitive, text, packed-integer, managed, file, and dynamic-memory contracts. Fixed-width and packed writes use constant stack storage and `O(1)` work; UTF-8 text writes use `O(N)` time and owned encoding storage for `N` bytes. `WriteStream` copies `L` requested bytes in `O(L)` time with a pooled `O(min(L, 81920))` buffer, and deterministically zero-fills a short source instead of exposing native Skia's uninitialized tail bytes. `SKManagedWStream` leaves its managed stream open by default and transfers disposal only when requested. Dynamic copy and detach operations are `O(B)` time and output storage for `B` buffered bytes; detach atomically resets the writer to zero bytes, while span and pointer copies preserve the source. Invalid file writers remain queryable and reject writes without creating a partial output file. Document export implements the complete SkiaSharp PDF/XPS creation surface, including path, managed-stream and `SKWStream` ownership, PDF metadata, XPS options, content clipping, close, and abort. Empty and aborted documents preserve native Skia's zero-byte output contract, caller-owned streams remain open, and path overloads own their file writers. Each populated page is captured once and reused by the writer; the raster target and retained command transform both scale by `dpi / 72`, preserving logical page geometry while increasing physical output detail. PDF generation builds a deterministic catalog/page/image graph with escaped metadata, Flate-compressed RGB payloads, and a byte-accurate cross-reference table; XPS generation writes an OPC package with one fixed-page and PNG resource per page. For `P` captured pixels and `B` encoded bytes, either path is `O(P + B)` time and `O(P + B)` owned output storage, while metadata/options and empty-document operations are `O(1)`. `SKData` uses a reference-counted storage owner for pinned managed bytes or caller-owned external memory. Its `Data` pointer remains stable for the object's lifetime, mutable `Span` and read-only `AsSpan` views are allocation-free, and valid subsets share storage in `O(1)` time and space while remaining alive independently of the parent view. Copy/file/stream factories and `ToArray` remain explicit `O(B)` ownership boundaries for `B` bytes; exact-length stream factories return null on a short read, and an external release delegate runs exactly once after the final shared view is disposed. `SKBitmap` and `SKPixmap` preserve native metadata-only, owned, and externally installed pixel states. Row-stride-aware bitmap byte counts and spans include inter-row padding but exclude padding after the final logical row; pixmap `BytesSize` remains the packed logical size while its span exposes the complete stride footprint. Allocation, reset, pointer, and immutable-state queries are `O(1)`; zero-initialization and byte snapshots are `O(B)` for the exposed storage size. Installed release delegates run exactly once on replacement, reset, disposal, or finalization, including delegates without a context object. Pixmap operations stay entirely on CPU memory. Pixel reads normalize premultiplied alpha, read/copy paths convert the common RGBA, BGRA, RGBx, RGB565, ARGB4444, alpha, gray, R8 and RG8 layouts, and erase clips to the destination rectangle. Subset extraction intersects bounds and creates an `O(1)` zero-copy view that retains the original pixel owner. Scaling delegates to the same stride-aware nearest, linear and cubic bitmap kernels, then converts into the destination pixmap. PNG and JPEG encoding convert one straight-alpha RGBA buffer and write directly to managed or Skia streams without creating a texture or WebGPU context; generic WebP and typed WebP entry points currently return false/null until a portable encoder with compatible licensing is available. Pixel queries and view creation are `O(1)`; read/erase are `O(P)` for affected pixels, scaling retains its documented kernel complexity, and encoding is `O(P + B)` time with `O(P + B)` owned storage for `P` pixels and `B` encoded bytes. Bitmap pixel arrays, color-type copies, shared subsets, alpha extraction, and size/legacy sampling overloads reuse those CPU primitives. Copy conversion builds a complete temporary bitmap and swaps storage only after success, so an invalid format or failed conversion leaves the destination unchanged. Bitmap subsets keep the original allocation alive and share its row stride in `O(1)` time and space. Alpha extraction writes one byte per source pixel into Skia's four-byte-aligned mask rows and reports the zero origin; it is `O(P)` time and `O(P)` storage. Pixel-array get/set and successful color copies are also `O(P)`, while failed format validation remains `O(1)`. Bitmap PNG/JPEG encoding now goes through `PeekPixels` and never performs the previous texture upload/readback. Bitmap shader creation has the complete Skia overload set. It uploads the current CPU bitmap once into an owned texture, retains independent X/Y tile modes and the local matrix, and carries the requested nearest, linear, mipmapped, or cubic sampling mode into every tiled draw command. Custom cubic shaders preserve their B/C coefficients through `ImageShaderData` and `RenderCommand`, sharing the same coefficient-aware texture shader as direct image draws. Creation is `O(P)` upload time and texture storage for `P` pixels; recording is `O(T)` time and commands for `T` visible tiles, with `O(1)` sampling metadata per command. Bitmap decoding routes file, byte/span, managed-stream, Skia-stream, data, and codec entry points through one cached CPU decode result. Invalid stream/data/file factories return null and bounds queries return `SKImageInfo.Empty`; the direct byte/span wrappers preserve native SkiaSharp's `ArgumentNullException` when codec creation fails. No metadata or invalid-input path initializes WebGPU. Default bitmaps convert unpremultiplied codec pixels to premultiplied RGBA8888; requested supported storage formats reuse the same stride-aware conversion and nearest scaled sampling. Parsing and conversion are `O(B + P)` time for `B` encoded bytes and `P` output pixels, with `O(B + P)` owned decode/output storage and no duplicate parse per codec. `SKCodec` exposes the complete SkiaSharp 4.148 single-frame decode surface over that cached CPU image. Factories distinguish missing files (`InternalError`), unknown encodings (`Unimplemented`), and recognized truncated inputs (`IncompleteInput`) without starting WebGPU. Static images retain Skia's zero animation-frame metadata; incremental decode stores only the caller target and performs one full-frame decode, while unavailable scanline and subset paths report `Unimplemented`. PNG and other non-JPEG codecs accept only native dimensions, while JPEG dimensions quantize to the nearest supported eighth-resolution step and clamp to `[1/8, 1]`. The common RGBA/unpremultiplied path copies decoded rows directly into the caller stride with no intermediate bitmap; other supported color/alpha layouts reuse the CPU bitmap converter. Header classification and scaling queries are `O(1)` time and space, stream acquisition is `O(B)`, and decode/copy is `O(B + P)` time with `O(B + P)` codec storage plus only caller-owned output storage for `B` encoded bytes and `P` pixels. Image metadata uses the complete `SKImageInfo` value contract and SkiaSharp 4.148 color-type inventory. Platform RGBA shifts, exact byte/bit depth for all 29 native color types, checked 32-bit and wide 64-bit row/image sizes, emptiness, opacity, rectangles, equality, and immutable-style `With*` copies are derived without touching pixel storage or initializing WebGPU. Encoded-format metadata includes AVIF and JPEG XL, while the obsolete filter-quality and bitmap-allocation enums retain their native values and attributes for binary/source compatibility. Every query is `O(1)` time and space; overflow remains explicit on the native 32-bit size properties instead of wrapping into an undersized allocation. Integer rectangle metadata implements the complete SkiaSharp 4.148 `SKRectI` value contract. Edge properties, location/size mutation, standardization, aspect fit/fill, inflation, offset, union, intersection, containment, checked ceiling/floor/round/truncate conversion, equality, hashing, and formatting are all allocation-free. Point containment and ordinary intersection are half-open; inclusive intersection preserves a boundary-touch result, and native `IsEmpty` means exact equality with `SKRectI.Empty` rather than any zero-area rectangle. Aspect resizing computes in floating point around the original center and floors final edges like Skia. Every operation is `O(1)` time and space and cannot initialize WebGPU. Floating-point rectangle metadata implements the matching complete SkiaSharp 4.148 `SKRect` value contract. Mutable edge, location, and size properties share one four-scalar representation; standardization and aspect fit/fill preserve native reversed-extent and zero-size behavior. Point containment and ordinary overlap are half-open, inclusive overlap retains boundary-touch intersections, and `IsEmpty` means exact equality with `SKRect.Empty`. Union always computes the coordinate envelope, including the empty rectangle's origin, so callers accumulating optional bounds must track whether a first bound exists separately. Creation, conversion, inflation, offset, union, intersection, equality, hashing, and formatting are allocation-free `O(1)` CPU operations and never initialize WebGPU. Rounded rectangles implement the complete SkiaSharp 4.148 `SKRoundRect` contract with native corner order, specialization types, validation, containment, mutation, and axis-preserving transforms. Per-corner radii use the CSS/W3C overlapping-curves rule: the minimum side-to-radius-sum ratio scales all eight values together, with Skia's double-precision pair adjustment and float-ULP trimming. A zero radius on either axis makes that corner square; inset/outset preserves square corners and collapses over-inset bounds to their center. Transform radii are reconstructed from mapped absolute corner anchors and ellipse centers, preserving SkiaSharp's position-dependent float rounding across translation, reflection, scale, and quarter turns. Construction, normalization, containment, inset/outset, offset, validation, and transform are fixed four-corner `O(1)` CPU work with `O(1)` storage. Public `Radii` allocates its required independent four-point snapshot, while internal path and canvas consumers use a borrowed read-only span and allocate nothing. Floating-point point metadata implements the complete SkiaSharp 4.148 `SKPoint` value contract. Mutable coordinates, length, squared length, offset, normalization, distance, all point/size arithmetic overloads, `Vector2` conversion, equality, hashing, and formatting are allocation-free. Compatibility includes native zero-vector normalization and SkiaSharp's historical reflection formula, which scales the supplied normal by the point's squared length; the integer point implementation uses the same rule. Every operation is `O(1)` time and space and cannot initialize WebGPU. Float and integer size metadata implements the complete SkiaSharp 4.148 `SKSize` and `SKSizeI` value contracts. Mutable dimensions, point constructors and conversions, float/integer widening and narrowing, arithmetic, equality, hashing, emptiness, and formatting share allocation-free scalar operations. Float-to-integer narrowing truncates in a checked context, preserving native overflow behavior for out-of-range, infinite, and NaN dimensions. Every operation is `O(1)` time and space and cannot initialize WebGPU. Matrix metadata implements the complete SkiaSharp 4.148 `SKMatrix` 3x3 projective value contract. Factory methods preserve native identity shortcuts and pivot equations; pre/post concat use direct row-major multiplication in native order; inversion uses double-precision cofactors, the native near-singular threshold, finite-result validation, and specialized tiny-scale handling. Point mapping divides by homogeneous `w`, zero `w` maps to zero, and perspective vector mapping subtracts the mapped origin. Rectangle mapping clips its four homogeneous corners against Skia's `w >= 1/16384` near plane in fixed stack storage before projection, preventing horizon-crossing coordinates from becoming infinite while preserving native bounds. Scalar matrix operations, inversion, and rectangle clipping are allocation-free `O(1)` time and space. Span mapping is `O(N)` time and `O(1)` auxiliary space; array-returning overloads allocate only their documented `O(N)` result. Internal `Matrix4x4` conversion carries both perspective coefficients and `Persp2`, so retained GPU commands do not silently flatten projective transforms. Rotation-scale text positioning implements the complete SkiaSharp 4.148 `SKRotationScaleMatrix` contract used by Svg.Skia's per-glyph transforms. Identity, translation, uniform scale, radian/degree rotation, anchored scale-rotation-translation, mutable scalar properties, 3x3 matrix conversion, equality, and hashing retain native single-precision evaluation order and float semantics. Every operation is allocation-free fixed-work `O(1)` CPU work; RSXform arrays remain caller-owned and scale linearly only with glyph count. Four-dimensional matrix metadata implements the complete SkiaSharp 4.148 `SKMatrix44` value contract as a contiguous 16-scalar struct. Construction from `SKMatrix` preserves 2D translation and perspective placement; row/column indexing, major-order conversion, translation, pivoted scale, axis rotation, determinant, inversion, transpose, point mapping, arithmetic, and native pre/post concat order delegate to the same `System.Numerics.Matrix4x4` semantics used by SkiaSharp. Singular inversion returns `Empty`, while span-based major-order copies require exactly 16 entries and remain allocation-free. Every scalar, factory, mapping, algebra, determinant, inversion, and span-copy operation is fixed-work `O(1)` time and space; only the array-returning major-order overloads allocate their documented 16-float result. Color metadata implements the complete SkiaSharp 4.148 `SKColor` and `SKColorF` value contracts. Integer colors retain native packed AARRGGBB storage, while float colors preserve independent RGBA channels and clamp each channel without rewriting NaN. Conversion to bytes clamps to `[0, 1]` and rounds with Skia's `value * 255 + 0.5` rule; conversion from bytes divides by 255. HSL and HSV conversion uses the native 0.001 chroma epsilon, hue wrapping, and achromatic branches, while byte-returning `FromHsl` and `FromHsv` preserve Skia's truncation after their float conversion. Construction, channel replacement, packing, parsing, conversion, equality, hashing, and color-space arithmetic are allocation-free `O(1)` CPU operations and never initialize WebGPU. The `SKColors` palette retains SkiaSharp's one-byte struct shape, mutable named static fields, exact CSS packed values, transparent-white `Transparent`, and computed zero `Empty` property. Every palette lookup is allocation-free `O(1)` static metadata access and never initializes WebGPU. Color-space objects implement the complete SkiaSharp 4.148 `SKColorSpace`, CICP, and ICC-profile contracts without initializing WebGPU. sRGB and linear-sRGB use stable singleton objects; gamma, numerical-transfer, D50 matrix, equality, and gamma-conversion queries are `O(1)` and allocation-free. CICP creation selects the exact Skia D50 matrix and seven-parameter transfer definition in `O(1)`, including PQ/HLG marker semantics and the SMPTE ST 428 degenerate-primary matrix. ICC construction validates the header and bounded tag table, copies the caller profile once into stable pinned ownership, reads RGB XYZ and equal channel TRCs, and canonicalizes native sRGB/linear results. Parametric and single-gamma curves are `O(1)`; sampled curves are compared once against sRGB in `O(S)` time and `O(1)` auxiliary space for `S` samples, matching native rejection of arbitrary table curves. Profile parsing is `O(T + B)` time and `O(B)` owned storage for `T` tags and `B` bytes, while every subsequent renderer query remains `O(1)` with no profile I/O or curve comparison. Color-space metadata implements the complete SkiaSharp 4.148 `SKColorSpaceXyz` and `SKColorSpaceTransferFn` value contracts. Named D50 matrices preserve Skia's exact sRGB, Adobe RGB, Display P3, Rec. 2020, and XYZ coefficients. Matrix concatenation is direct row-major multiplication; inversion uses double-precision cofactors, rejects zero or non-finite determinants, and returns the native empty value for a singular matrix. Transfer functions preserve Skia's seven scalar parameters, named sRGB, gamma 2.2, linear, Rec. 2020, PQ, and HLG definitions, signed-domain evaluation, PQ/HLG markers, and inverse rejection rules. The evaluator ports `skcms` bounded logarithm/exponent approximations so finite, NaN, and infinity results remain native-compatible without platform color-management dependencies. Construction, indexing, concatenation, inversion, evaluation, equality, and hashing are allocation-free `O(1)` CPU operations. `Values` is also `O(1)` and intentionally allocates only its fixed seven- or nine-scalar ownership snapshot. Font style metadata implements the complete SkiaSharp 4.148 `SKFontStyle` object contract used by Svg.Skia typeface resolution. Default, enum, and unrestricted integer constructors preserve weight, width, and slant exactly; Normal, Bold, Italic, and BoldItalic are stable singleton properties whose public disposal is protected like native SkiaSharp. Ordinary owned styles release their compatibility handle on disposal. Construction and every metadata query are allocation-bounded `O(1)` CPU operations and never parse a font or initialize WebGPU. Surface properties implement the complete SkiaSharp 4.148 `SKSurfaceProperties` metadata contract. Pixel geometry, raw 32-bit flags, the typed `SKSurfacePropsFlags` overload, unknown flag bits, device-independent-font detection, and owned-object disposal are retained without creating a surface or GPU context. Construction and queries are allocation-bounded fixed-work `O(1)` CPU operations. Managed drawables implement the SkiaSharp 4.148 `SKDrawable` hook and canvas contract. Bounds and approximate memory metadata delegate to overridable hooks, drawing composes a supplied matrix inside save/restore isolation, point overloads use translation, generation invalidation is atomic, and the default snapshot records the drawable into a retained `SKPicture`. Metadata and invalidation are `O(1)`; drawing and snapshot are `O(C)` time and storage for `C` recorded commands, with no additional GPU submission or readback. Retained pictures expose nonzero process-unique IDs, cull bounds, direct operation counts, recursive nested-picture counts, and estimated command/buffer ownership without replaying content. Direct counts are `O(1)`; recursive counts and byte estimates are `O(C + N)` for `C` local commands and `N` nested commands. Recorder overloads share one immutable command-array transfer, clear their active canvas on completion, and can transfer the result into a drawable whose bounds, metadata, drawing, and snapshots retain picture ownership independently. Picture-shader overloads retain tile modes, tile bounds, local matrices, and nearest/linear filtering through the raster-tile texture command instead of silently forcing nearest sampling. Recording and metadata remain CPU-only; shader rasterization is still deferred until the shader is actually drawn. Picture serialization uses a versioned, process-independent ProGPU archive rather than a process-local object token. It recursively preserves scalar command state, pooled point/double/line/float buffers, analytic paths, built-in vector brushes, pens and dash state, embedded font bytes, texture-patch metadata, vertex meshes, glyph arrays, and nested pictures. Every count, string, archive size, and nesting depth is validated before allocation; serialization and deserialization are `O(B + C)` time and `O(B + C)` owned storage for `B` encoded bytes and `C` commands. GPU textures, static buffers, cache-key objects, and custom extension payloads fail explicitly because they require a separate portable codec or readback contract. The archive round-trips every `SKPicture` stream/data/pointer overload but intentionally is not a native Skia `.skp` interchange format. Point primitives implement SkiaSharp's `SKPointMode` and `SKCanvas.DrawPoint(s)` contracts through the existing stroke geometry pipeline. Point mode batches zero-length segments, line mode consumes disjoint pairs and ignores an unmatched tail, and polygon mode connects adjacent points without closing the contour. Paint style is ignored as in Skia while stroke width, cap, color, blend, antialiasing, and canvas transforms remain intact. Recording is `O(N)` time and path storage for `N` points, emits one retained draw command, and adds no shader or per-point GPU submission. Canvas transform convenience APIs preserve SkiaSharp's post-concatenation order across scalar, point, pivot, radians, degrees, skew, 3x3, and 4x4 inputs. Identity scales, empty point transforms, zero skews, and complete degree turns are skipped before matrix arithmetic; pivot operations use the native translate-transform-translate sequence. Every transform is allocation-free `O(1)` CPU work, updates only retained canvas state, and performs no command recording, GPU submission, or readback. Canvas point/size shape overloads normalize directly into the existing line, rounded-rectangle, ellipse, and circle primitives. Conversion is allocation-free `O(1)` work before the normal retained command or path is created, so an overload never adds a second draw, changes tessellation, or introduces a GPU synchronization boundary. Picture playback overloads normalize scalar and point positions into a local matrix and compose it with the current canvas transform for exactly one nested retained-picture command. Optional paint blend and opacity scopes wrap that command, while local matrix state is restored in `finally`. Playback setup is `O(1)` and allocation-free apart from color-space conversion caches already required by the nested picture; playback itself remains `O(C)` for `C` nested commands without flattening or GPU readback. Image draw overloads normalize point, scalar, destination-only, and source/destination inputs into one sampling-aware texture command. Legacy paint filter quality maps once to nearest, linear, linear-mipmap, or Mitchell sampling before the shared path; explicit cubic and anisotropic settings remain intact. Overload setup is allocation-free `O(1)`, recording remains one retained texture command plus required clip/blend/opacity scopes, and no overload performs a readback. Bitmap draw overloads follow SkiaSharp's adapter model: create one short-lived image view, normalize legacy or explicit sampling, and enter the same image command path. The adapter is `O(1)` metadata work around the bitmap-backed texture, retains no duplicate canvas implementation, and preserves the one texture draw plus required scopes without readback. Surface draw overloads snapshot once, preserve legacy or explicit sampling, and route through the same image command path. Point overloads are scalar adapters; canvas and surface APIs share one implementation. Setup is `O(1)` around the required snapshot, recording remains one retained texture draw plus scopes, and no additional readback or duplicated renderer path is introduced. `SKTextBlob` intercept queries use the same path-boundary algorithm as Skia for underline and strike-through avoidance. Each positioned glyph independently tests line, quadratic, and cubic crossings at both horizontal band boundaries, expands the interval with path points strictly inside the band, and returns at most one ordered pair without merging overlaps from neighboring glyphs. `ScaleX`, `SkewX`, vertical placement, and synthetic emboldening are included; rotation-scale runs are intentionally ignored like native Skia. Array, span, and count overloads share the CPU-only engine, with short spans receiving the available prefix. For `G` glyphs and `S` path segments, time is `O(G * S)`, root-solving workspace is `O(1)`, and returned storage is at most `O(G)`. `SKRotationScaleMatrix` provides the complete SkiaSharp 4.148 identity, translation, uniform-scale, radian rotation, degree rotation, anchored rotation-scale, and matrix-conversion factories used by RSXform text and atlas placement. Every factory is allocation-free `O(1)` CPU math. Combined transforms preserve native operation order: degree conversion multiplies by the pre-divided float radians-per-degree constant, sine and cosine are evaluated in double precision and then cast to float, and anchor compensation is applied in the original float expression order. This keeps all four stored components bit-identical to native without initializing WebGPU. `SKSurfaceProperties` retains SkiaSharp 4.148 surface metadata as an `O(1)` managed value holder over the normal `SKObject` lifetime. `SKPixelGeometry` uses the native five-value numbering (`Unknown`, RGB/BGR horizontal, RGB/BGR vertical), and `SKSurfacePropsFlags` preserves both the device-independent-font bit and unknown caller bits supplied through the `uint` constructor. Construction and property queries allocate no GPU resource and do not initialize WebGPU; consumers may use the metadata when selecting text rasterization behavior without remapping enum values. `SKFontStyle` mirrors SkiaSharp 4.148 as an `SKObject`-owned immutable style descriptor. The default constructor produces normal weight/width with upright slant, integer constructors retain caller values without normalization, and the `Normal`, `Bold`, `Italic`, and `BoldItalic` properties return stable process-wide instances. Public disposal is protected for those shared instances while ordinary constructed styles release their managed compatibility handle. Construction, property access, and singleton lookup are `O(1)` and do not initialize WebGPU or inspect font files. Path-positioned text blobs reproduce SkiaSharp's non-warped text-on-path algorithm. Glyph midpoint distances are aligned over a measured contour, clipped to its half-open length, sampled for position/tangent, shifted back by half advance, and offset along the path normal before becoming rotation-scale matrices. For `G` glyphs and path-measure setup cost `P`, time is `O(G + P)`, storage is `O(G)`, and drawing stays on the retained glyph-run path without per-glyph GPU submission or readback. Canvas text overloads preserve SkiaSharp's legacy alignment metadata while normalizing point and scalar coordinates into the canonical shaped-text path. Text-on-path selects outline morphing when `warpGlyphs` is true and tangent-positioned rotation-scale blobs otherwise. Wrapper cost is `O(1)`; shaping and path placement remain `O(G + P)` for G glyphs and path-measure setup P, and compositor glyph instances continue to batch without readback or quality reduction. Core canvas color operations draw a device-space rectangle through the requested blend mode, independent of the current matrix but inside retained clip scopes; float colors are clamped before recording. Arc drawing converts the Skia angle convention into one elliptical path, clamps full turns to one oval, and closes center wedges only when requested. Color/discard/state work is `O(1)`; arc path creation is bounded `O(1)`, emits one retained path command, and performs no readback.