import { type DrawCounters, IRenderer } from './IRenderer'; export declare class CanvasRenderer implements IRenderer { private ctx; private width; private height; private canvas; /** True between a `contextlost` and its `contextrestored` — the 2D context is * unusable, so draw calls are skipped until it comes back. Canvas2D context * loss is rare (GPU reset / memory pressure) but a real browser event. */ private contextLost; /** Invoked after the context is restored + re-initialized, so the owner * (`Scene`) can repaint the now-blank canvas. Set via {@link onContextRestored}. */ private contextRestoredCb; /** * Cap on the effective device pixel ratio applied by the constructor and * {@link resize}. `undefined` (default) uses the real, uncapped * `devicePixelRatio` — unchanged from prior versions. Set directly, or via * the constructor's third argument; `Scene` (see `SceneOptions.maxDPR`) * keeps this in sync on every {@link resize} call, since the real DPR can * change at runtime (e.g. a window dragged between displays). */ maxDPR?: number; /** * The ratio the context is actually scaled by, i.e. the last value the * constructor or {@link resize} applied. Backs {@link pixelRatio}; see there * for why this is recorded rather than recomputed on read. */ private appliedDPR; /** * Max circles per batched `fill()`. A single Canvas 2D `fill()` over a path is * superlinear in sub-path count, so an unbounded batch is *slower* than many * small fills at high entity counts. Capping bounds each fill's path * complexity while still amortizing per-draw overhead. Tuned via the benchmark. */ static readonly MAX_BATCH = 64; private batchActive; private batchColor; private batchAlpha; private batchCount; private _cachedFont; private _cachedFill; /** Backend discriminator; see {@link IRenderer.kind}. */ readonly kind = "canvas2d"; /** * Draw counters, allocated only once counting is enabled. * * Null when off, so the guard on every op is a single null test and an inactive * renderer carries no counter object at all. */ private counters; /** Accumulated primitive area, kept separately so the ratio is derived on read. */ private drawnArea; /** * @param canvas - The target canvas. Its backing store is resized to the * logical size × devicePixelRatio. * @param size - Explicit logical size. Without it the renderer assumes a * fullscreen canvas and sizes to the window — pass this for embedded / * custom-container canvases (the Scene does when `disableWindowResize` is * set) so the canvas's own dimensions aren't clobbered by the window's. * @param maxDPR - See {@link maxDPR}. */ constructor(canvas: HTMLCanvasElement, size?: { width: number; height: number; }, maxDPR?: number); /** Register a callback fired after a lost 2D context is restored + re-scaled, * so the owner can repaint (the restored canvas comes back cleared). */ onContextRestored(cb: () => void): void; /** * Handle Canvas2D context loss/restore (GPU reset, memory pressure). The * `contextlost` handler MUST call `preventDefault()` or the browser never * fires `contextrestored`; while lost, draw calls are skipped. On restore we * re-acquire the 2D context, re-apply the DPR scale, drop cached style, and * notify the owner to repaint. */ private setupContextLossRecovery; /** * Expose the underlying `CanvasRenderingContext2D` for operations not * covered by the {@link IRenderer} interface. * * @returns The raw 2D rendering context. */ getContext(): CanvasRenderingContext2D; /** Real `devicePixelRatio`, clamped to {@link maxDPR} when set. */ private effectiveDPR; /** * @inheritdoc * * The ratio the context is **currently scaled by**, recorded by the constructor * and {@link resize} — deliberately not a live `effectiveDPR()` call. * * The distinction is load-bearing rather than pedantic. `devicePixelRatio` * changes the instant a zoom lands, but the backing store is only reallocated * when something calls {@link resize} (in a `Scene`, the `(resolution: Ndppx)` * media query). A live getter therefore reports the *future* ratio during that * window, and a caller rasterizing pixels from it produces a texture that the * still-old context scale resamples — the same defect this property exists to * let callers avoid, merely inverted. Reporting the applied ratio means a * cache keyed on it is always consistent with the pixels it is blitted into, * and it simply re-keys on the next `resize`. */ get pixelRatio(): number; /** * Resize the backing canvas buffer and re-apply DPR scaling. * * Called automatically by {@link Scene} on `window.resize` events. * * @param width - New logical width in CSS pixels. * @param height - New logical height in CSS pixels. */ resize(width: number, height: number): void; /** Whether the 2D context is currently lost (drawing is a no-op until it is * restored). The owner skips its render pass while this is true. */ isContextLost(): boolean; /** @inheritdoc */ /** @inheritdoc */ setDrawCounters(enabled: boolean): void; /** @inheritdoc */ getDrawCounters(): DrawCounters | null; /** @inheritdoc */ clearDrawCounters(): void; clear(): void; /** @inheritdoc */ save(): void; /** @inheritdoc */ restore(): void; /** @inheritdoc */ translate(x: number, y: number): void; /** @inheritdoc */ scale(x: number, y: number): void; /** @inheritdoc */ rotate(angle: number): void; /** @inheritdoc */ setGlobalAlpha(alpha: number): void; /** @inheritdoc */ clip(x: number, y: number, width: number, height: number, radii?: number | number[]): void; /** @inheritdoc */ beginPath(): void; /** @inheritdoc */ moveTo(x: number, y: number): void; /** @inheritdoc */ lineTo(x: number, y: number): void; /** @inheritdoc */ bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void; /** @inheritdoc */ closePath(): void; /** @inheritdoc */ arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void; /** @inheritdoc */ roundRect(x: number, y: number, width: number, height: number, radii: number | number[]): void; /** @inheritdoc */ drawImage(source: CanvasImageSource, dx: number, dy: number, dw: number, dh: number): void; /** @inheritdoc */ drawImageRect(source: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void; /** @inheritdoc */ fillCircle(cx: number, cy: number, radius: number, color: string, alpha?: number): void; /** @inheritdoc */ flush(): void; /** @inheritdoc */ fill(color: string | any): void; /** @inheritdoc */ stroke(color: string | any, lineWidth?: number): void; /** @inheritdoc */ fillText(text: string, x: number, y: number, font: string, color: string | any): void; /** @inheritdoc */ createLinearGradient(x0: number, y0: number, x1: number, y1: number, colorStops: { stop: number; color: string; }[]): any; /** * Canvas2D drawing contexts are automatically released when their * `` element is GC'd, so there's no explicit GPU handle to free. * This method clears our internal batch state and is idempotent. */ dispose(): void; }