whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.17k stars 2.69k forks source link

Detached OffscreenCanvas is underspecified #10026

Open Kaiido opened 10 months ago

Kaiido commented 10 months ago

What is the issue with the HTML Standard?

OffscreenCanvas can have a detached context mode, once the OffscreenCanvas object has been transferred.

The transferring steps say that value (the OffscreenCanvas object)'s bitmap must be unset, but apart from that it doesn't say much of what else happens to said object.
And we have somewhere

The width and height of the bitmap are equal to the values of the width and height attributes of the OffscreenCanvas object.

So it seems fair (and expected for devs) that all browsers do set the width and height attributes to 0, since there is no bitmap anymore, even though the normative text seems to make the reference the other way around.

However it starts being complicated when setting these attributes. The specs only define what the setters do when the context mode is 2d, there is nothing about when it's detached, and browsers don't agree.

APIs that do consume OffscreenCanvas go through check the usability of the image argument which does throw when the image's width or height is zero, so Chrome's behavior looks very surprising.
Between Firefox's and Safari's behavior, I personally do not have any preferences, but I think we should specify one.

Of note,

junov commented 10 months ago

Setting width/height or attempting to read the bitmap of a detached OffscreenCanvas are programming errors IMHO. I am pretty sure throwing an InvalidState exception is the right thing to do in almost all cases.

For the placeholder situation, could you clarify what the problematic use case is? Setting the width or height on a placeholder canvas (i.e. after calling transferControlToOffscreen) is supposed to be a no-op. Spec'ed here: https://html.spec.whatwg.org/multipage/canvas.html#concept-canvas-placeholder As far as the spec is concerned, the placeholder canvas does not store a reference to the OffscreenCanvas that controls it (though implementations may have an internal reference that has no impact on API behavior). The only reference that is prescribed by the spec is in the other direction: the OffscreenCanvas has an optional weak reference to a placeholder canvas. The canvas element knows that it is being controlled by an offscreen canvas via its context mode, which may be set to placeholder, but it does not hold a reference to the actual OffscreenCanvas. There is no data flow from the placeholder to the OffscreenCanvas; data only flows in the other direction. This unidirectionality makes it trivial to ensure that the spec is free of signals that would be vulnerable to deadlocks or feedback loops.

Kaiido commented 10 months ago

Setting width/height or attempting to read the bitmap of a detached OffscreenCanvas are programming errors IMHO. I am pretty sure throwing an InvalidState exception is the right thing to do in almost all cases.

Agreed, I'll take it as a Chrome position and will try to prepare a PR to that effect when I get time.

For the placeholder situation, could you clarify what the problematic use case is?

I was only talking about the relation OffscreenCanvas => placeholder<canvas>. I simply noticed that the OffscreenCanvas's placeholder canvas element isn't unset in the transfer steps and since the width and height setters aren't defined (yet) for when context mode is detached what happens to the placeholder canvas is also unspecced.

But I now see that even the context mode: none has some small interop issues with placeholder canvases, and the specs seem unclear here too. See this fiddle where we can see that Safari does resize the placeholder canvas even when there is no context on the OffscreenCanvas, while Firefox will wait until the context is created and Chrome until there is actual drawings on the context. All the specs say is that commit() was supposed to be updating the placeholder size, which is going to be replaced by "update the rendering".