Re: [whatwg] High-density canvases

On Tue, 10 Sep 2013, Dean Jackson wrote:
> > 
> > So my understanding is that the reason this feature failed is that 
> > there's existing content that assumes a 1:1 ratio, and having an 
> > automatic high-density mode was making some pages end up with canvases 
> > with four canvas pixels per CSS pixel (linearly) -- two from the 
> > browser making a native canvas, times two from the page scaling the 
> > canvas for high DPI displays. This is a factor of sixteen over a 1:1 
> > canvas, a factor of four more than it should be for high DPI, and a 
> > big waste of resources.
> It wasn’t just that. A lot of existing code did something like this:
> var pixels = ctx.getImageData(0, 0, canvas.width, canvas.height);
> for (var i = 0; i < canvas.width; i++) {
>   for (var j = 0; j < canvas.height; j++) {
>     pixels[j * canvas.width + i][0] = newRedValue;
>     pixels[j * canvas.width + i][1] = newGreenValue;
>     pixels[j * canvas.width + i][2] = newBlueValue;
>   }
> }
> ctx.putImageData(…)
> i.e. no one read the spec that says you should check the width and 
> height of the returned ImageData.

Per spec, that should work fine even in the current spec fiction of 
automatic high-density canvases, because getImageData() returns CSS-pixel 
level data (and the putImageData() call scales it up to native res). 
That's why we added the *HD methods.

> Then there is toDataURL(). Should that return a full-sized bitmap?

Per spec, it returns the low-res version, with toDataURLHD() for the full 

> Then you need to be sure what you’re uploading it to will handle the 
> larger size.

Right, hence the two versions.

> Basically, there was pretty unanimous support from Web developers to 
> “just give us the damn pixels we asked for”

Agreed. The proposal {density:'autosize'} seems to do that, while 
avoiding the back-compat issues that prevent the current spec fiction 
from working in practice.

> > While we're talking about annoying things, there's also the annoyance 
> > that canvases tend to not take zoom into account (either 
> > density-affecting zoom like page zoom on desktop, or "transparent" 
> > zoom like pinch-zoom on mobile for non-mobile-optimised sites, which 
> > the site isn't supposed to know about): you have to remember to listen 
> > for onresize, and then manually blow away your canvas and recreate it 
> > at the right density and then squeeze it into place so that the 
> > coordinate space matches what your code is expecting while the 
> > <canvas> is actually sized for the display.
> Yes, but I think the developer is the one who best knows what 
> size/quality her content requires.
> A great developer will do exactly as you suggest: constantly examine the 
> rendered size of the canvas (taking into account pixel density and 
> viewport/zoom).

Only because they have to.

There's basically three cases that I can see:

 1. People dealing only with low-density 96dpi graphics, who just want 
    96dpi canvases (CSS pixel = canvas pixel = coordinate space unit) and 
    that's it.

 2. People who want native resolution graphics.

 3. People doing crazy complicated stuff.

Currently we're supporting #3 and #1, with #1 being the default, and if 
you want #2 you have to actually do #3.

There are authors (e.g. me, but I suspect it's actually a majority of the 
more casual authoring community) who want high-quality native-resolution 
graphics, but who don't want to have to jump through hoops to get them.

> > This would trigger the following behaviour: When the context is 
> > created, and subsequently when the <canvas> changes size (e.g. due to 
> > being sized with CSS relative units and the element they're relative 
> > to changing), or when the display density changes size (e.g. due to 
> > page zoom), then:
> > 
> >   - the width and height of the canvas bitmaps get updated to match the
> >     new native size of the <canvas>, at native density.
> > 
> >   - the coordinate space of the canvas (context.width/context.height) 
> >     gets updated to match the size of the <canvas> in CSS pixel units.
> Note that this would reset the context, which would throw away the 
> contents and context state. This might be exactly what you want though - 
> put this attribute on a full-bleed canvas and resize your window -> 
> everything disappears unless you implement the ‘resize’ event handler.

Right, resetting the context would definitely be part of the deal. This 
mode would be specifically defined as a mode where you had to listen to 
onresize or your canvas would almost certainly get cleared sooner or 
later. In fact, we could go further, and say that canvases that aren't 
getting rendered at all (e.g. display:none, off-screen, background tab) 
can get cleared, with the deal being that next time you need to show the 
canvas you immediately get an onresize.

The more things we have that trigger onresize, the more likely it is that 
authors won't forget to implement it.

> >   - a 'resize' event gets fired at the <canvas>.
> > 
> > We would dump the *HD versions of the methods, and make the regular 
> > ones go back to returning the actual raw pixels, since that would now 
> > work fine and still provide HD-quality content everywhere it's 
> > available.
> > 
> > What do people think?
> This seems ok to me. I still worry we’ll get into a situation where 
> developers will add density:’autosize’ (in order to get the resizing 
> behaviour) and NOT check the results of getImageData - everything will 
> work fine if they never test on a high-dpi screen.

Yeah, my suggestion, if we do this, would be to not do it until high 
density displays are even more widely available than now. This is mostly a 
convenience and performance-improving API, not a critical feature add.

> Maybe there should be two attributes?

What would the two attributes do?

Ian Hickson               U+1047E                )\._.,--....,'``.    fL       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'

Received on Tuesday, 10 September 2013 00:32:10 UTC