[whatwg] Canvas - Somewhat inconsistent rules in the spec for drawImage

Simon Sarris simon.sarris at gmail.com
Fri Sep 20 11:16:30 PDT 2013


Summary: You can draw zero-sized Images and objects with zero-sized source
rects to the canvas context. You cannot draw zero-sized Canvases, you get
an InvalidStateError. According to the spec this is right, but I think
there should be more consistency in handling these cases.

drawImage can be called with an Image, a Canvas, or a Video element, so you
typically see calls like:

ctx.drawImage(imageReference, 0, 0);
ctx.drawImage(canvasReference, 0, 0);

99% of the time you can think of them as interchangeable. Let's talk about
our 1%ers.

I came across an interesting (and none-too-useful, but we can blame the
browser for that) error when drawing a canvas with zero width and height:

inMemoryCanvas.width = 0;
// Uncaught InvalidStateError: An attempt was made to use an object that is
not, or is no longer, usable.
ctx.drawImage(inMemoryCanvas, 0, 0);

According to the specification, this is the right error to throw:

> If the image argument is an HTMLCanvasElement object with either a
horizontal dimension or a vertical dimension equal to zero, then throw an
InvalidStateError exception, return aborted, and abort these steps.

The bothersome thing is that:

1. Zero-sized Images do not have any such error
2. calling drawImage with a source rectangle, using
context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh), when the source
rectangle has zero width or height, does not give an error. Per the spec:

> If one of the sw or sh arguments is zero, abort these steps. Nothing is
painted.

So zero-sized sources are fine if they are an HTMLImageElement or a source
rectangle, but not fine if they are HTMLCanvasElement.

This seems inconsistent, and the error given seems odd too. It's not very
descriptive and not immediately clear what is wrong. This issue came to my
attention because a friend asked for help, who was drawing randomly-sized
canvases onto a main context. He suspected InvalidStateError was some
bizarre closure bug where part of the canvas state was being lost, but of
course the truth was more mundane - some but not all zero-sized objects
cannot be drawn to the canvas context.

Anywho, I recommend either considering all zero-sized sources as invalid,
and perhaps giving a more descriptive error, or simply allowing a
zero-sized canvas to be a valid drawImage argument so that it may run its
natural course (draw nothing), just like Image and zero-sized source rect
arguments.

Simon Sarris


~~~

For reference, below is a simple example showing both a zero-sized img
being drawn and a zero-sized canvas:

  // this <img>'s width/height/naturalWidth/naturalHeight are all zero:
  var img = document.createElement('img');
  // Totally fine, no error:
  ctx.drawImage(img, 0, 0);

  var inMemoryCanvas = document.createElement('canvas');
  inMemoryCanvas.width = 0;
  inMemoryCanvas.height = 0;
  // Uncaught InvalidStateError: An attempt was made to use an object that
is not, or is no longer, usable.
  ctx.drawImage(inMemoryCanvas, 0, 0);


More information about the whatwg mailing list