WindowTypes (cursor shapes, clipboard image, window identity and edges) and
PlatformInfo move from the backend contract into a WindowTypes library that
needs only Math. Code that names a cursor or reads platform facts no longer
links the GPU device and the backend contract.
KeyModifiers (shift, control, alt, super; either side of the keyboard counts)
and a ModifierTracker that follows modifier presses in event order. InputState
keeps one, so consumers read the modifiers held at the end of the frame, and
walk events() with their own tracker when they need per-event modifiers.
Losing keyboard focus releases them.
Canvas keeps the drawing API and its state (origin, clip stack, composite
operation) and draws through a CanvasBackend. The backends mirror how the
platform windows are organised: the contract (canvas/backends/contract) is
the interface, implementations live beside it, and the facade in src/canvas
stays portable with no Vulkan.
- NanoVgCanvasBackend (canvas/backends/nanovg) draws on a window surface.
The canvas's window-surface constructor and beginFrame(frame, windowFrame)/
endFrame() are defined there, next to the backend, so the portable facade
never names a GPU frame; the application uses Canvas directly.
- RecordingCanvasBackend (canvas/backends/recording) records commands with
their surface rect and clip, and measures text with a fixed advance, so
layout and painting are testable headless.
- Canvas::Clip is a public clip scope; clips intersect and restore with the
scope. SavedState now also restores the composite operation.
- gradientRect takes an Axis; polyline/polygon take vectors; text takes a
string. frame() and debugCross() had no users and are gone.
- TextMetrics is an interface Canvas implements, so layout can measure text
without a frame. setClip takes an optional clip instead of a null pointer.