I think we should revisit or maybe just clarify the spec with regards to what happens when you call a function that uses the contents of a canvas.
The specific functions are
The current text of the spec says
WebGL presents its drawing buffer to the HTML page compositor immediately before a compositing operation, but only if clear, drawArrays or drawElements have been called since the last compositing operation, while the drawing buffer is the currently bound framebuffer. Before the drawing buffer is presented for compositing the implementation shall ensure that all rendering operations have been flushed to the drawing buffer. By default, after compositing the contents of the drawing buffer shall be cleared to their default values, as shown in the table above.
This default behavior can be changed by setting the preserveDrawingBuffer attribute of the WebGLContextAttributes object. If this flag is true, the contents of the drawing buffer shall be preserved until the author either clears or overwrites them. If this flag is false, attempting to perform operations using this context as a source image after the rendering function has returned can lead to undefined behavior. This includes readPixels or toDataURL calls, or using this context as the source image of another context's texImage2D or drawImage call.
I'd like to suggest it does not make a lot of scene to have this undefined. Specifically I think toDataURL, drawImage and texImage2D should change so that until drawing commands are issued after a composite the pixels being composited will be used.
It seems strange that I can fill a canvas with pixels. Once filled with pixels I can transform it, rotate it, move it around in the DOM. I can even print it. But if I ask what's in it with one of those 4 functions it will tell me "0,0,0,0"
To be more specific I'm suggesting every canvas effectively has a "drawing_buffer_to_copy_from" reference to a DrawingBuffer. When a draw command is issued "drawing_buffer_to_copy_from" is set to the DrawingBuffer being drawn to. (the back buffer)
If preserveDrawingBuffer = false then when compositing happens conceptually DrawingBuffers are swapped. "drawing_buffer_to_copy_from" is NOT updated to point to the new buffer (it's only updated by calling a drawing function).
This means until a drawing function is called, toDataURL/drawImage/texImage2D would give the contents of the canvas.
readPixels on the other hand always gives data from the current DrawingBuffer so its behavior would not change. The DrawingBuffers are swapped at composite time. readPixels always reads from the current DrawingBuffer (backbuffer).
It seems like this would make more intuitive sense. If I see a canvas on the screen with an image in and I use it with one of those 4 functions I'll get what I see.