WebCanvasVideoRenderer
Draws frames onto an HTML canvas.
The two canvases, and why there are two
The frame is written into an offscreen canvas at its own stored size with putImageData, and that canvas is then drawn onto the visible one with drawImage. putImageData alone would be one step shorter and cannot do the job: it writes raw pixels and ignores every transform, so letterboxing, zoom, pan and rotation would all be impossible and the picture would only ever appear at its stored size in the top-left corner. drawImage respects the context transform, which is what makes the geometry law below apply at all.
What it does not do
This is the first web renderer tier: a canvas under the Compose controls, not the single Compose surface where clip, alpha and rotation apply to the video pixels themselves. That is tier two and is not this. There is also no hardware path: the wasm decoder is software by construction, so supportedHardwareSurfaces is empty and always will be on this renderer. The picture controls in io.github.yuroyami.kiteplayer.VideoAdjustments are not applied either.
Not thread-safe, and on the web that is not a constraint: there are no threads. present is already suspend and runs on the event loop with no worker, no dispatcher and no runBlocking.
Parameters
whether the page's screen stays awake while pictures are drawn, and for two seconds after the last one (#238), through WebDisplayAwake. In a worker it does nothing, because a worker has no screen; the page's KitePlayerWorker holds it there.
Constructors
Properties
The canvas's backing store, in device pixels: the size setViewport set, or the canvas's own size before that. The engine lays subtitles out for it, so text lands in the bars and at the canvas's own pixel size (docs/subtitle-placement.md, rule 2).
Diagnostics, in the same three counts the Android renderer keeps.
Functions
Takes the picture off (#530): the canvas shows its background, transparent as between the bars, with the cues over it, until the next picture. The stage keeps its storage for that picture, but nothing draws from it again.
The canvas's BACKING STORE is sized here, which is the only place that can be right.
Software only. A browser's own hardware decoder is WebCodecs' path and does not arrive here.
Any software format, because the painter converts rather than this class. PlayerPixelFormat.Opaque is refused: it means a hardware frame, nothing on the web produces one for this renderer, and answering true would let a mis-wired decoder fail per frame instead of at attach.
Null, honestly. requestAnimationFrame follows the display and a page can read screen.refreshRate nowhere portable, so a guess here would be a number the schedule trusts. Rule 4 says the cost of null is smoothness on a high refresh display and nothing else.