[whatwg] Canvas in workers
Kyle Huey
me at kylehuey.com
Sat Oct 12 21:12:46 PDT 2013
I talked at length with Robert O'Callahan about what the DOM API for
supporting <canvas> in web workers should look like and we came up with the
following modifications to the spec.
1. Rename CanvasProxy to WorkerCanvas and only allow it to be
transferred to workers. I don't think we're interested in supporting
cross-origin <canvas> via CanvasProxy (I would be curious to hear more
about what the use cases are).
2. Add a worker-only WorkerCanvas constructor that takes the desired
width/height of the drawing surface.
3. Remove the rendering context constructors and the setContext method
on WorkerCanvas (née CanvasProxy).
4. Copy all of the sensible non-node related things from
HTMLCanvasElement to WorkerCanvas. This would include
- width and height as readonly attributes
- getContext (to replace what we removed in step 3). roc prefers to
have getContext2D and getContextWebGL, and dispense with the string
argument version entirely, but I don't have strong feelings.
- toBlob. We do not intend to implement toDataURL here.
5. Add a "commit" method to WorkerCanvas. For a WorkerCanvas obtained
from a main thread <canvas> element, this would cause the buffer displayed
on screen to swap. For a WorkerCanvas created *de novo* on a worker
thread, it would do nothing. This commit method would also commit a minor
violation of run-to-completion semantics, described below.
6. We would rely on extracting ImageBitmaps from the WorkerCanvas and
shipping them to the main thread via postMessage to allow synchronizing
canvas updates with DOM updates. We explored a couple other options but we
didn't come up with anything else that allows synchronizing updates to
multiple canvases from a worker. This isn't really sketched out here.
So the IDL would look something like:
> [Constructor(unsigned long width, unsigned long height)]
>
> interface WorkerCanvas {
>
> readonly attribute unsigned long width;
>
> readonly attribute unsigned long height;
>
>
> CanvasRenderingContext2D? getContext2D(any... args);
>
> WebGLRenderingContext? getContextWebGL(any... args);
>
>
> void toBlob(FileCallback? _callback, optional DOMString type, any...
> arguments);
>
>
> bool commit();
>
> };
>
> WorkerCanvas implements Transferable;
>
Everything would be behave pretty much as one would expect, except perhaps
for the commit method. The width and height of the canvas can be modified
on the main thread while the worker is drawing. This would fire an event
off to the worker to update the WorkerCanvas's dimensions that would be
scheduled as if the main thread had postMessage()d something to the
worker. But it's possible that the worker would attempt to draw to the
<canvas> before that update runs. It's also possible that the worker would
simply draw in a loop without yielding. To solve this, if commit is called
and the current dimensions on the main thread don't match the dimensions of
the WorkerCanvas it would fail (return false) and update the dimensions of
the WorkerCanvas before returning. This is technically a violation of
run-to-completion semantics, but is needed to support workers that do not
yield.
Thoughts?
- Kyle
More information about the whatwg
mailing list