Re: [whatwg] Mutation Observer arguments format
On Tue, Mar 12, 2013 at 12:41 AM, Alex Russell slightly...@google.com wrote: Thoughts? My main thought is that it's a pita to change the API at this time now it's unprefixed everywhere and we've been encouraging developers to use it in favor of mutation events. If Adam/Rafael/Olli/Jonas are willing to update WebKit/Gecko though I guess I don't really care. -- http://annevankesteren.nl/
Re: [whatwg] Mutation Observer arguments format
On 03/12/2013 12:34 PM, Anne van Kesteren wrote: On Tue, Mar 12, 2013 at 12:41 AM, Alex Russell slightly...@google.com wrote: Thoughts? My main thought is that it's a pita to change the API at this time now it's unprefixed everywhere and we've been encouraging developers to use it in favor of mutation events. If Adam/Rafael/Olli/Jonas are willing to update WebKit/Gecko though I guess I don't really care. We could keep the old behavior and extend it to support types. But since the change isn't backward compatible (scripts using types wouldn't work in older browsers), I'd like to understand the need for the change. -Olli
Re: [whatwg] Mutation Observer arguments format
On Tue, Mar 12, 2013 at 6:22 AM, Olli Pettay olli.pet...@helsinki.fiwrote: On 03/12/2013 12:34 PM, Anne van Kesteren wrote: On Tue, Mar 12, 2013 at 12:41 AM, Alex Russell slightly...@google.com wrote: Thoughts? My main thought is that it's a pita to change the API at this time now it's unprefixed everywhere and we've been encouraging developers to use it in favor of mutation events. If Adam/Rafael/Olli/Jonas are willing to update WebKit/Gecko though I guess I don't really care. We could keep the old behavior and extend it to support types. I was going to mention this the other day - it works inter-operably today, so it seems like you probably don't want to break that. Simultaneously it does seem to me that the API is more sensible and less confusing - is there any reason not change the proposal such that the intent is to to deprecate the existing way and consider the new/proposed API as merely superceeding the old? Given that one is merely sugar on the other anyway - it should be possible to propose the change and augment/prollyfill the mapping I think and I see no reason you couldn't quickly roll that out natively given its simplicity. But since the change isn't backward compatible (scripts using types wouldn't work in older browsers), I'd like to understand the need for the change. -Olli -- Brian Kardell :: @briankardell :: hitchjs.com
Re: [whatwg] Mutation Observer arguments format
On Tue, Mar 12, 2013 at 3:05 PM, Brian Kardell bkard...@gmail.com wrote: I was going to mention this the other day - it works inter-operably today, so it seems like you probably don't want to break that. Simultaneously it does seem to me that the API is more sensible and less confusing - is there any reason not change the proposal such that the intent is to to deprecate the existing way and consider the new/proposed API as merely superceeding the old? Given that one is merely sugar on the other anyway - it should be possible to propose the change and augment/prollyfill the mapping I think and I see no reason you couldn't quickly roll that out natively given its simplicity. Yes, that is the basic argument made time and again. It neglects the costs. It takes away time from people that should probably work on other stuff, it increases the API surface area and what needs to be tested, and thereby increases the chance for mismatching functionality across user agents. Making changes, even seemingly trivial ones, across multiple independent engines is not something that should be taken lightly. -- http://annevankesteren.nl/
Re: [whatwg] Enabling LCD Text and antialiasing in canvas
On Mon, Mar 11, 2013 at 4:32 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Tue, Mar 12, 2013 at 8:23 AM, Stephen White senorbla...@chromium.orgwrote: On Mon, Mar 11, 2013 at 2:56 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Tue, Mar 12, 2013 at 7:53 AM, Stephen White senorbla...@chromium.org wrote: All other canvas functionality behaves as normal, including operations which modify the alpha values of the backing store. However, any such transparency values will be ignored when compositing the canvas into the page, and the canvas will be treated as if every pixel has an alpha of 1.0. That would mean getImageData can return non-1.0 alpha values, which is probably not what you want to implement. That's what Firefox/Linux does (in fact, it always seems to return 0.0 alpha from getImageData()). We definitely shouldn't spec that! And I'm pretty sure that behavior would vary across Firefox platforms. But we need to have consistent behavior here. I considered three options: 1) Prevent non-1.0 alpha ever getting into the canvas. At a minimum, this would require the following: - For putImageData, apply premultiplication, then write 1.0 alpha into the canvas. - Change initialization and clearRect() to clear to opaque black instead of transparent black. - Modify all canvas compositing modes to leave destination alpha unchanged The latter is easy to do in OpenGL and CoreGraphics, but hard to do in Skia, and hard to do in accelerated CoreGraphics (IOSurfaces don't seem to support any opaque formats, although I could be wrong -- that was just from an hour or so of experimentation). I'm not sure about Cairo. You can always implement it slowly using readback. I think we should just spec this, and maybe note that authors shouldn't use non-over operators on opaque canvases. Over time we'll probably find a way to make it fast everywhere. I'm a little leery of spec'ing something that has negative performance implications. As an example, the darker compositing mode was removed from the spec due to hardware-accelerated performance concerns, IIRC. OTOH, unlike that change, this spec should not have performance implications for OpenGL or Direct3D acceleration, only CoreGraphics via IOSurface and skia (so far). How would you feel about simply mapping the dest-alpha-modifying compositing modes to source-over, as in proposal 2) above? Stephen Rob -- Wrfhf pnyyrq gurz gbtrgure naq fnvq, “Lbh xabj gung gur ehyref bs gur Tragvyrf ybeq vg bire gurz, naq gurve uvtu bssvpvnyf rkrepvfr nhgubevgl bire gurz. Abg fb jvgu lbh. Vafgrnq, jubrire jnagf gb orpbzr terng nzbat lbh zhfg or lbhe freinag, naq jubrire jnagf gb or svefg zhfg or lbhe fynir — whfg nf gur Fba bs Zna qvq abg pbzr gb or freirq, ohg gb freir, naq gb tvir uvf yvsr nf n enafbz sbe znal.” [Znggurj 20:25-28]
Re: [whatwg] Mutation Observer arguments format
On Mar 12, 2013 12:06 PM, Anne van Kesteren ann...@annevk.nl wrote: On Tue, Mar 12, 2013 at 3:05 PM, Brian Kardell bkard...@gmail.com wrote: I was going to mention this the other day - it works inter-operably today, so it seems like you probably don't want to break that. Simultaneously it does seem to me that the API is more sensible and less confusing - is there any reason not change the proposal such that the intent is to to deprecate the existing way and consider the new/proposed API as merely superceeding the old? Given that one is merely sugar on the other anyway - it should be possible to propose the change and augment/prollyfill the mapping I think and I see no reason you couldn't quickly roll that out natively given its simplicity. Yes, that is the basic argument made time and again. It neglects the costs. It takes away time from people that should probably work on other stuff, it increases the API surface area and what needs to be tested, and thereby increases the chance for mismatching functionality across user agents. Making changes, even seemingly trivial ones, across multiple independent engines is not something that should be taken lightly. -- http://annevankesteren.nl/ Anne, I feel like you've misunderstood my comments/observations. Let me clarify and see: 1) I think this API is more sensible - I had the same problem with mutation observers api. 2) we should not be forever stuck with an unintuitive API 3) we have interop now and a mature spec, that sucks in retrospect that we didn't see this earlier, but it is what it is. 4) this adds nothing in the way of features, it is merely sugar/better API so it should be easily prollyfillable. As such, I am suggesting that we draft a proposal to do so, explain in detail how it would work (I gave a high-level suggestion), provide test cases, etc... That's what prollyfills are all about - a way to evolve outside the browser impl itself based on competition and data which makes that part easier and makes sure we don't take turns that users have problems with ... and ... 5) should we reach that point (it is entirely possible we dont) the actual implementation should be *comparatively *low cost. Does it make sense? Do you feel like I am hand-waving away any of your concerns? I hope not because the idea there is precisely to help address concerns like these (as well as many others). -Brian
Re: [whatwg] Enabling LCD Text and antialiasing in canvas
Here's a draft of proposal (1) above: Motivation: Compositing a canvas element into the page can be expensive, due to blending operations, and lack of opportunity for culling. Since arbitrary graphics operations can affect the opacity of the canvas, it is difficult to determine programmatically whether the canvas is opaque. Allowing the developer to explicitly mark a canvas as opaque allows the user agent to optimize blending at page composite time, as well to cull fully-obscured elements behind the canvas. Description: The opaque attribute is a boolean attribute of the canvas element, whose presence indicates that the alpha values in the canvas backing store must be 1.0 at all times. All canvas operations are modified to preserve this invariant. If the opaque attribute is not present, or if parsing its value returns an error, then the default value (false) must be used instead. When a canvas has the opaque attribute, the backing store must be initialized to opaque black (rgba(0, 0, 0, 1.0)), instead of transparent black (rgba(0, 0, 0, 0.0)). Setting, changing, removing or setting the attribute redundantly to its existing value causes the canvas to be cleared to the appropriate value. When a canvas has the opaque attribute, clearRect() clears to opaque black instead of transparent black. The behaviour of putImageData() and putImageDataHD() when a canvas has the opaque attribute is to premultiply the RGB components by the alpha component as usual, but write 1.0 into destination alpha. In other words, if (r, g, b, a) are the component values in a given pixel passed to putImageData[HD](), then r' = ar, g' = ag, b' = ab are the colour components of the resulting canvas pixel, and (r', g', b', 1.0) is written to the canvas backing store. When a canvas has the opaque attribute, all globalCompositeOperation modes behave as normal and the resulting RGB components are written to the canvas backing store, but the alpha component is left unchanged at 1.0. Stephen On Tue, Mar 12, 2013 at 12:53 PM, Stephen White senorbla...@chromium.orgwrote: On Mon, Mar 11, 2013 at 4:32 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Tue, Mar 12, 2013 at 8:23 AM, Stephen White senorbla...@chromium.orgwrote: On Mon, Mar 11, 2013 at 2:56 PM, Robert O'Callahan rob...@ocallahan.org wrote: On Tue, Mar 12, 2013 at 7:53 AM, Stephen White senorbla...@chromium.org wrote: All other canvas functionality behaves as normal, including operations which modify the alpha values of the backing store. However, any such transparency values will be ignored when compositing the canvas into the page, and the canvas will be treated as if every pixel has an alpha of 1.0. That would mean getImageData can return non-1.0 alpha values, which is probably not what you want to implement. That's what Firefox/Linux does (in fact, it always seems to return 0.0 alpha from getImageData()). We definitely shouldn't spec that! And I'm pretty sure that behavior would vary across Firefox platforms. But we need to have consistent behavior here. I considered three options: 1) Prevent non-1.0 alpha ever getting into the canvas. At a minimum, this would require the following: - For putImageData, apply premultiplication, then write 1.0 alpha into the canvas. - Change initialization and clearRect() to clear to opaque black instead of transparent black. - Modify all canvas compositing modes to leave destination alpha unchanged The latter is easy to do in OpenGL and CoreGraphics, but hard to do in Skia, and hard to do in accelerated CoreGraphics (IOSurfaces don't seem to support any opaque formats, although I could be wrong -- that was just from an hour or so of experimentation). I'm not sure about Cairo. You can always implement it slowly using readback. I think we should just spec this, and maybe note that authors shouldn't use non-over operators on opaque canvases. Over time we'll probably find a way to make it fast everywhere. I'm a little leery of spec'ing something that has negative performance implications. As an example, the darker compositing mode was removed from the spec due to hardware-accelerated performance concerns, IIRC. OTOH, unlike that change, this spec should not have performance implications for OpenGL or Direct3D acceleration, only CoreGraphics via IOSurface and skia (so far). How would you feel about simply mapping the dest-alpha-modifying compositing modes to source-over, as in proposal 2) above? Stephen Rob -- Wrfhf pnyyrq gurz gbtrgure naq fnvq, “Lbh xabj gung gur ehyref bs gur Tragvyrf ybeq vg bire gurz, naq gurve uvtu bssvpvnyf rkrepvfr nhgubevgl bire gurz. Abg fb jvgu lbh. Vafgrnq, jubrire jnagf gb orpbzr terng nzbat lbh zhfg or lbhe freinag, naq jubrire jnagf gb or svefg zhfg or lbhe fynir — whfg nf gur Fba bs Zna qvq abg pbzr gb or freirq, ohg gb freir, naq gb tvir uvf yvsr nf n enafbz sbe znal.” [Znggurj 20:25-28]
Re: [whatwg] Mutation Observer arguments format
On Tue, Mar 12, 2013 at 5:02 PM, Brian Kardell bkard...@gmail.com wrote: Does it make sense? Do you feel like I am hand-waving away any of your concerns? I hope not because the idea there is precisely to help address concerns like these (as well as many others). It makes sense and is doable, but given finite resources it's on balance with everything else we work on. E.g. the effort I put into drafting a new API and figure out the details will take away time from improving Fetch and XMLHttpRequest. The effort Adam will put into implementing the change and making sure it's tested will take away time from him working on HTML templates. Etc. And that's not counting that we then have two ways of doing the same thing. That we need to update documentation. That it's not backwards compatible. -- http://annevankesteren.nl/
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
It should simply reference the Uint8ClampedArray, not copy it or do anything else esoteric. The only way to display an ImageData in the 2D canvas context is via the putImageData API. I am not proposing changing those semantics. -Ken On Mon, Mar 11, 2013 at 5:00 PM, Rik Cabanier caban...@gmail.com wrote: Do you expect that createImageData creates an internal copy of the Uint8ClampedArray object or is it live? On Mon, Mar 11, 2013 at 4:28 PM, Kenneth Russell k...@google.com wrote: It would be useful to be able to create an ImageData [1] object with preexisting data. The main use case is to display arbitrary data in the 2D canvas context with no data copies. Proposed IDL: [NoInterfaceObject] interface ImageDataFactories { ImageData createImageData(Uint8ClampedArray data, double sw, double sh); }; Window implements ImageDataFactories; WorkerGlobalScope implements ImageDataFactories; createImageData would throw an exception if the length of the Uint8ClampedArray was not equal to 4 * floor(sw) * floor(sh), or at least, if the length of the array was less than this value. (Similar wording would be used to that of CanvasRenderingContext2D's createImageData.) I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. [1] http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata Comments? Thanks, -Ken
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
I much prefer your suggestion to just add a constructor to ImageData. I was not sure whether that style was preferred nowadays. ImageData is already exposed in the global namespace, so making it a callable constructor function seems like an easy change. As mentioned in another reply, the intent here is to reference the Uint8ClampedArray, not make a copy. -Ken On Mon, Mar 11, 2013 at 7:03 PM, Boris Zbarsky bzbar...@mit.edu wrote: On 3/11/13 7:28 PM, Kenneth Russell wrote: Proposed IDL: [NoInterfaceObject] interface ImageDataFactories { ImageData createImageData(Uint8ClampedArray data, double sw, double sh); }; Window implements ImageDataFactories; WorkerGlobalScope implements ImageDataFactories; How about just: [Constructor(Uint8ClampedArray data, double sw, double sh)] interface ImageData { /* Whatever is currently there */ }; and then you create one with: new ImageData(someData, someWidth, someHeight); Other than needing to specify whether the array is copied or held on to by reference, and specifying that this interface should be exposed in workers, this seems fine to me. -Boris
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
sounds good! I think this is a convenient and useful addition. do you want to keep doubles to define the dimensions instead of integers? If so, the size should probably 4 * ceil(sw) * ceil(sh) On Tue, Mar 12, 2013 at 10:50 AM, Kenneth Russell k...@google.com wrote: It should simply reference the Uint8ClampedArray, not copy it or do anything else esoteric. The only way to display an ImageData in the 2D canvas context is via the putImageData API. I am not proposing changing those semantics. -Ken On Mon, Mar 11, 2013 at 5:00 PM, Rik Cabanier caban...@gmail.com wrote: Do you expect that createImageData creates an internal copy of the Uint8ClampedArray object or is it live? On Mon, Mar 11, 2013 at 4:28 PM, Kenneth Russell k...@google.com wrote: It would be useful to be able to create an ImageData [1] object with preexisting data. The main use case is to display arbitrary data in the 2D canvas context with no data copies. Proposed IDL: [NoInterfaceObject] interface ImageDataFactories { ImageData createImageData(Uint8ClampedArray data, double sw, double sh); }; Window implements ImageDataFactories; WorkerGlobalScope implements ImageDataFactories; createImageData would throw an exception if the length of the Uint8ClampedArray was not equal to 4 * floor(sw) * floor(sh), or at least, if the length of the array was less than this value. (Similar wording would be used to that of CanvasRenderingContext2D's createImageData.) I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. [1] http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata Comments? Thanks, -Ken
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 11:15 AM, Rik Cabanier caban...@gmail.com wrote: sounds good! I think this is a convenient and useful addition. Great. do you want to keep doubles to define the dimensions instead of integers? If so, the size should probably 4 * ceil(sw) * ceil(sh) I would prefer to use integers, and only used doubles to be consistent with the other APIs like getImageData and createImageData. In this case it would make more sense to use integers, since the width and height are simply being used to interpret preexisting data in the Uint8ClampedArray. -Ken On Tue, Mar 12, 2013 at 10:50 AM, Kenneth Russell k...@google.com wrote: It should simply reference the Uint8ClampedArray, not copy it or do anything else esoteric. The only way to display an ImageData in the 2D canvas context is via the putImageData API. I am not proposing changing those semantics. -Ken On Mon, Mar 11, 2013 at 5:00 PM, Rik Cabanier caban...@gmail.com wrote: Do you expect that createImageData creates an internal copy of the Uint8ClampedArray object or is it live? On Mon, Mar 11, 2013 at 4:28 PM, Kenneth Russell k...@google.com wrote: It would be useful to be able to create an ImageData [1] object with preexisting data. The main use case is to display arbitrary data in the 2D canvas context with no data copies. Proposed IDL: [NoInterfaceObject] interface ImageDataFactories { ImageData createImageData(Uint8ClampedArray data, double sw, double sh); }; Window implements ImageDataFactories; WorkerGlobalScope implements ImageDataFactories; createImageData would throw an exception if the length of the Uint8ClampedArray was not equal to 4 * floor(sw) * floor(sh), or at least, if the length of the array was less than this value. (Similar wording would be used to that of CanvasRenderingContext2D's createImageData.) I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. [1] http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata Comments? Thanks, -Ken
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 11:40 AM, Kenneth Russell k...@google.com wrote: On Tue, Mar 12, 2013 at 11:15 AM, Rik Cabanier caban...@gmail.com wrote: sounds good! I think this is a convenient and useful addition. Great. do you want to keep doubles to define the dimensions instead of integers? If so, the size should probably 4 * ceil(sw) * ceil(sh) I would prefer to use integers, and only used doubles to be consistent with the other APIs like getImageData and createImageData. In this case it would make more sense to use integers, since the width and height are simply being used to interpret preexisting data in the Uint8ClampedArray. The current canvas spec doesn't specifically state what happens with partial pixels. What happens today? (Also is there a definition somewhere that states when a pixel is considered filled?) I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. That probably won't work since it results in code that executes differently on devices that are HD. On Tue, Mar 12, 2013 at 10:50 AM, Kenneth Russell k...@google.com wrote: It should simply reference the Uint8ClampedArray, not copy it or do anything else esoteric. The only way to display an ImageData in the 2D canvas context is via the putImageData API. I am not proposing changing those semantics. -Ken On Mon, Mar 11, 2013 at 5:00 PM, Rik Cabanier caban...@gmail.com wrote: Do you expect that createImageData creates an internal copy of the Uint8ClampedArray object or is it live? On Mon, Mar 11, 2013 at 4:28 PM, Kenneth Russell k...@google.com wrote: It would be useful to be able to create an ImageData [1] object with preexisting data. The main use case is to display arbitrary data in the 2D canvas context with no data copies. Proposed IDL: [NoInterfaceObject] interface ImageDataFactories { ImageData createImageData(Uint8ClampedArray data, double sw, double sh); }; Window implements ImageDataFactories; WorkerGlobalScope implements ImageDataFactories; createImageData would throw an exception if the length of the Uint8ClampedArray was not equal to 4 * floor(sw) * floor(sh), or at least, if the length of the array was less than this value. (Similar wording would be used to that of CanvasRenderingContext2D's createImageData.) I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. [1] http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#imagedata Comments? Thanks, -Ken
Re: [whatwg] Enabling LCD Text and antialiasing in canvas
On Wed, Mar 13, 2013 at 5:53 AM, Stephen White senorbla...@chromium.orgwrote: I'm a little leery of spec'ing something that has negative performance implications. So am I, but surely making non-over operators slower is better than making them not work at all --- especially if the former situation is temporary. The latter decision would have to be permanent. Rob -- Wrfhf pnyyrq gurz gbtrgure naq fnvq, “Lbh xabj gung gur ehyref bs gur Tragvyrf ybeq vg bire gurz, naq gurve uvtu bssvpvnyf rkrepvfr nhgubevgl bire gurz. Abg fb jvgu lbh. Vafgrnq, jubrire jnagf gb orpbzr terng nzbat lbh zhfg or lbhe freinag, naq jubrire jnagf gb or svefg zhfg or lbhe fynir — whfg nf gur Fba bs Zna qvq abg pbzr gb or freirq, ohg gb freir, naq gb tvir uvf yvsr nf n enafbz sbe znal.” [Znggurj 20:25-28]
Re: [whatwg] Enabling LCD Text and antialiasing in canvas
On Tue, 12 Mar 2013, Stephen White wrote: As an example, the darker compositing mode was removed from the spec due to hardware-accelerated performance concerns, IIRC. 'darker' was removed because it wasn't defined anywhere so couldn't be implemented interoperably. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Enabling LCD Text and antialiasing in canvas
On Tue, Mar 12, 2013 at 10:03 AM, Stephen White senorbla...@chromium.orgwrote: Here's a draft of proposal (1) above: Motivation: Compositing a canvas element into the page can be expensive, due to blending operations, and lack of opportunity for culling. Since arbitrary graphics operations can affect the opacity of the canvas, it is difficult to determine programmatically whether the canvas is opaque. Allowing the developer to explicitly mark a canvas as opaque allows the user agent to optimize blending at page composite time, as well to cull fully-obscured elements behind the canvas. Description: The opaque attribute is a boolean attribute of the canvas element, whose presence indicates that the alpha values in the canvas backing store must be 1.0 at all times. All canvas operations are modified to preserve this invariant. If the opaque attribute is not present, or if parsing its value returns an error, then the default value (false) must be used instead. When a canvas has the opaque attribute, the backing store must be initialized to opaque black (rgba(0, 0, 0, 1.0)), instead of transparent black (rgba(0, 0, 0, 0.0)). Setting, changing, removing or setting the attribute redundantly to its existing value causes the canvas to be cleared to the appropriate value. When a canvas has the opaque attribute, clearRect() clears to opaque black instead of transparent black. The behaviour of putImageData() and putImageDataHD() when a canvas has the opaque attribute is to premultiply the RGB components by the alpha component as usual, but write 1.0 into destination alpha. In other words, if (r, g, b, a) are the component values in a given pixel passed to putImageData[HD](), then r' = ar, g' = ag, b' = ab are the colour components of the resulting canvas pixel, and (r', g', b', 1.0) is written to the canvas backing store. When a canvas has the opaque attribute, all globalCompositeOperation modes behave as normal and the resulting RGB components are written to the canvas backing store, but the alpha component is left unchanged at 1.0. What does 'normal' mean? Is it 'composite with the usual formula' or 'composite with source-over'? I still think a matteColor can accomplish the same and have the added benefit of flexibility and easy of specification... On Tue, Mar 12, 2013 at 12:53 PM, Stephen White senorbla...@chromium.orgwrote: On Mon, Mar 11, 2013 at 4:32 PM, Robert O'Callahan rob...@ocallahan.orgwrote: On Tue, Mar 12, 2013 at 8:23 AM, Stephen White senorbla...@chromium.org wrote: On Mon, Mar 11, 2013 at 2:56 PM, Robert O'Callahan rob...@ocallahan.org wrote: On Tue, Mar 12, 2013 at 7:53 AM, Stephen White senorbla...@chromium.org wrote: All other canvas functionality behaves as normal, including operations which modify the alpha values of the backing store. However, any such transparency values will be ignored when compositing the canvas into the page, and the canvas will be treated as if every pixel has an alpha of 1.0. That would mean getImageData can return non-1.0 alpha values, which is probably not what you want to implement. That's what Firefox/Linux does (in fact, it always seems to return 0.0 alpha from getImageData()). We definitely shouldn't spec that! And I'm pretty sure that behavior would vary across Firefox platforms. But we need to have consistent behavior here. I considered three options: 1) Prevent non-1.0 alpha ever getting into the canvas. At a minimum, this would require the following: - For putImageData, apply premultiplication, then write 1.0 alpha into the canvas. - Change initialization and clearRect() to clear to opaque black instead of transparent black. - Modify all canvas compositing modes to leave destination alpha unchanged The latter is easy to do in OpenGL and CoreGraphics, but hard to do in Skia, and hard to do in accelerated CoreGraphics (IOSurfaces don't seem to support any opaque formats, although I could be wrong -- that was just from an hour or so of experimentation). I'm not sure about Cairo. You can always implement it slowly using readback. I think we should just spec this, and maybe note that authors shouldn't use non-over operators on opaque canvases. Over time we'll probably find a way to make it fast everywhere. I'm a little leery of spec'ing something that has negative performance implications. As an example, the darker compositing mode was removed from the spec due to hardware-accelerated performance concerns, IIRC. OTOH, unlike that change, this spec should not have performance implications for OpenGL or Direct3D acceleration, only CoreGraphics via IOSurface and skia (so far). How would you feel about simply mapping the dest-alpha-modifying compositing modes to source-over, as in proposal 2) above? Stephen Rob -- Wrfhf pnyyrq gurz gbtrgure naq fnvq, “Lbh xabj gung gur ehyref bs gur Tragvyrf ybeq vg bire gurz,
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 3:03 PM, Kenneth Russell k...@google.com wrote: On Tue, Mar 12, 2013 at 2:04 PM, Rik Cabanier caban...@gmail.com wrote: On Tue, Mar 12, 2013 at 11:40 AM, Kenneth Russell k...@google.com wrote: On Tue, Mar 12, 2013 at 11:15 AM, Rik Cabanier caban...@gmail.com wrote: sounds good! I think this is a convenient and useful addition. Great. do you want to keep doubles to define the dimensions instead of integers? If so, the size should probably 4 * ceil(sw) * ceil(sh) I would prefer to use integers, and only used doubles to be consistent with the other APIs like getImageData and createImageData. In this case it would make more sense to use integers, since the width and height are simply being used to interpret preexisting data in the Uint8ClampedArray. The current canvas spec doesn't specifically state what happens with partial pixels. What happens today? (Also is there a definition somewhere that states when a pixel is considered filled?) Safari, Firefox and Chrome all round the double arguments to putImageData to integers using the truncate rounding mode and then draw the source ImageData pixel-for-pixel. For example, passing 64.5 or 64.99 for the dx or dy arguments is equivalent to passing 64. Here's a test case. canvas id=canvas width=256 height=256/canvas script var canvas = document.getElementById(canvas); var ctx = canvas.getContext(2d); var width = canvas.width; var height = canvas.height; ctx.fillRect(0, 0, width, height); var imageData = ctx.createImageData(width / 2, height / 2); for (var ii = 0; ii imageData.data.length; ii += 4) { imageData.data[ii + 0] = 0; imageData.data[ii + 1] = 255; imageData.data[ii + 2] = 0; imageData.data[ii + 3] = 255; } // Try passing 64.5, 64.99, or 65 for one or both of these arguments and see the results ctx.putImageData(imageData, 64, 64); /script In other words, the source ImageData would not be rendered into the canvas at a half-pixel offset if ctx.putImageData(imageData, 64.5, 64.5) were called. Thanks for investigating this. The fact that 'truncate' is called, should probably go in the spec. Maybe we should change the IDL to integer. I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. That probably won't work since it results in code that executes differently on devices that are HD. I think it works. The application will call the new ImageData constructor and pass it to either putImageData or putImageDataHD. These interpret the incoming ImageData differently depending on the devicePixelRatio. In contrast, CanvasRenderingContext2D's existing createImageDataHD and getImageDataHD methods will create an ImageData that may have a different width and height from those passed in. The reason for this is that these methods are referring to the canvas's backing store. For this new constructor which simply wraps existing pixel data, the application knows exactly how many pixels are contained in the array, so it makes the most sense to take the incoming width and height verbatim. I don't see any advantage to having an alternate high-DPI constructor which would multiply the width and height by the devicePixelRatio behind the scenes. Your proposal is: createImageData would throw an exception if the length of the Uint8ClampedArray was not equal to 4 * floor(sw) * floor(sh), or at least, if the length of the array was less than this value. So, if you create an imageData that is going to be used in putImageDataHD, the bounds checking happens when you pass it into putImageDataHD? It seems the imageData object should know if it was meant for an HD call. There is no real reason why you could use it in both HD and non-HD APIs. On Tue, Mar 12, 2013 at 10:50 AM, Kenneth Russell k...@google.com wrote: It should simply reference the Uint8ClampedArray, not copy it or do anything else esoteric. The only way to display an ImageData in the 2D canvas context is via the putImageData API. I am not proposing changing those semantics. -Ken On Mon, Mar 11, 2013 at 5:00 PM, Rik Cabanier caban...@gmail.com wrote: Do you expect that createImageData creates an internal copy of the Uint8ClampedArray object or is it live? On Mon, Mar 11, 2013 at 4:28 PM, Kenneth Russell k...@google.com wrote: It would be useful to be able to create an ImageData [1] object with preexisting data. The main use case is to display arbitrary data in the 2D canvas context with no data copies. Proposed IDL: [NoInterfaceObject] interface ImageDataFactories { ImageData createImageData(Uint8ClampedArray data, double sw, double sh); }; Window implements ImageDataFactories; WorkerGlobalScope implements ImageDataFactories;
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 12:14 AM, Boris Zbarsky bzbar...@mit.edu wrote: CSE can get rid of the redundant .data gets. Similarly, .data gets can be loop-hoisted in many cases. Doing COW based on page-faults is nicer anyway, but I don't know about the data structures of JS engines to know whether this is feasible. (For example, if an object in JS is preceded by a header that gets written by the engine now and then, it'll probably lie on the same page as the data, which would trigger an expensive fault each time.) I suppose padding the backing store so it doesn't share pages with anything else might be reasonable here: up to about 8k of waste on a system with 4kb pages. The cost of marking the pages read-only would only have to be paid when the copy-on-write action (eg. a call to putImageData) is actually made. Very small buffers could simply disable copy-on-write and always perform a copy, where the waste for padding is more significant and the benefits of avoiding a copy are smaller. (For what it's worth, marking a 128 MB buffer read-only in Linux with mprotect takes on the order of 3 microseconds on my typical desktop-class system. I don't know if Windows's VirtualProtect is slower.) On Tue, Mar 12, 2013 at 4:04 PM, Rik Cabanier caban...@gmail.com wrote: I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. That probably won't work since it results in code that executes differently on devices that are HD. The difference between getImageData(HD) and putImageData(HD) is in the canvas operation, not the ImageData: it determines how pixels are scaled when being read out of and written into the canvas backing store. It doesn't apply to this API; ImageData objects don't know anything beyond their pixel data and dimensions. (Code executing differently on high-DPI devices is a bridge we've already crossed. getImageData scales pixels down from the device's pixel ratio; getImageDataHD doesn't, copying backing store pixels one to one.) There is no real reason why you could use it in both HD and non-HD APIs. Rather, there's no reason you couldn't. You can definitely create an ImageData with getImageData and then pass it to putImageDataHD (which would cause the image to be scaled on devices with a pixel ratio other than 1, of course). -- Glenn Maynard
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 3:49 PM, Rik Cabanier caban...@gmail.com wrote: On Tue, Mar 12, 2013 at 3:03 PM, Kenneth Russell k...@google.com wrote: On Tue, Mar 12, 2013 at 2:04 PM, Rik Cabanier caban...@gmail.com wrote: On Tue, Mar 12, 2013 at 11:40 AM, Kenneth Russell k...@google.com wrote: On Tue, Mar 12, 2013 at 11:15 AM, Rik Cabanier caban...@gmail.com wrote: sounds good! I think this is a convenient and useful addition. Great. do you want to keep doubles to define the dimensions instead of integers? If so, the size should probably 4 * ceil(sw) * ceil(sh) I would prefer to use integers, and only used doubles to be consistent with the other APIs like getImageData and createImageData. In this case it would make more sense to use integers, since the width and height are simply being used to interpret preexisting data in the Uint8ClampedArray. The current canvas spec doesn't specifically state what happens with partial pixels. What happens today? (Also is there a definition somewhere that states when a pixel is considered filled?) Safari, Firefox and Chrome all round the double arguments to putImageData to integers using the truncate rounding mode and then draw the source ImageData pixel-for-pixel. For example, passing 64.5 or 64.99 for the dx or dy arguments is equivalent to passing 64. Here's a test case. canvas id=canvas width=256 height=256/canvas script var canvas = document.getElementById(canvas); var ctx = canvas.getContext(2d); var width = canvas.width; var height = canvas.height; ctx.fillRect(0, 0, width, height); var imageData = ctx.createImageData(width / 2, height / 2); for (var ii = 0; ii imageData.data.length; ii += 4) { imageData.data[ii + 0] = 0; imageData.data[ii + 1] = 255; imageData.data[ii + 2] = 0; imageData.data[ii + 3] = 255; } // Try passing 64.5, 64.99, or 65 for one or both of these arguments and see the results ctx.putImageData(imageData, 64, 64); /script In other words, the source ImageData would not be rendered into the canvas at a half-pixel offset if ctx.putImageData(imageData, 64.5, 64.5) were called. Thanks for investigating this. The fact that 'truncate' is called, should probably go in the spec. Maybe we should change the IDL to integer. I think that would be a good idea. I believe it would be backward compatible and leave the definition of double - long conversion to the Web IDL and ECMAScript specs. I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. That probably won't work since it results in code that executes differently on devices that are HD. I think it works. The application will call the new ImageData constructor and pass it to either putImageData or putImageDataHD. These interpret the incoming ImageData differently depending on the devicePixelRatio. In contrast, CanvasRenderingContext2D's existing createImageDataHD and getImageDataHD methods will create an ImageData that may have a different width and height from those passed in. The reason for this is that these methods are referring to the canvas's backing store. For this new constructor which simply wraps existing pixel data, the application knows exactly how many pixels are contained in the array, so it makes the most sense to take the incoming width and height verbatim. I don't see any advantage to having an alternate high-DPI constructor which would multiply the width and height by the devicePixelRatio behind the scenes. Your proposal is: createImageData would throw an exception if the length of the Uint8ClampedArray was not equal to 4 * floor(sw) * floor(sh), or at least, if the length of the array was less than this value. Yes. So, if you create an imageData that is going to be used in putImageDataHD, the bounds checking happens when you pass it into putImageDataHD? It seems the imageData object should know if it was meant for an HD call. There is no real reason why you could use it in both HD and non-HD APIs. Glenn already answered this, but you can already call getImageData and pass the result to putImageDataHD (and vice versa -- getImageDataHD/putImageData). The only difference between putImageData and putImageDataHD is that on high-DPI displays putImageDataHD will take the same image data and display it in a smaller region. All of the size checking would be performed in the new ImageData constructor we're discussing. I don't think ImageData itself should know anything about high DPI because it's designed for pixel-by-pixel manipulation. -Ken On Tue, Mar 12, 2013 at 10:50 AM, Kenneth Russell k...@google.com wrote: It should simply reference the Uint8ClampedArray, not copy it or do anything else esoteric. The only way to display an ImageData in the 2D canvas context is via the putImageData API. I am not
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 4:16 PM, Glenn Maynard gl...@zewt.org wrote: On Tue, Mar 12, 2013 at 12:14 AM, Boris Zbarsky bzbar...@mit.edu wrote: CSE can get rid of the redundant .data gets. Similarly, .data gets can be loop-hoisted in many cases. Doing COW based on page-faults is nicer anyway, but I don't know about the data structures of JS engines to know whether this is feasible. (For example, if an object in JS is preceded by a header that gets written by the engine now and then, it'll probably lie on the same page as the data, which would trigger an expensive fault each time.) I suppose padding the backing store so it doesn't share pages with anything else might be reasonable here: up to about 8k of waste on a system with 4kb pages. The cost of marking the pages read-only would only have to be paid when the copy-on-write action (eg. a call to putImageData) is actually made. Very small buffers could simply disable copy-on-write and always perform a copy, where the waste for padding is more significant and the benefits of avoiding a copy are smaller. (For what it's worth, marking a 128 MB buffer read-only in Linux with mprotect takes on the order of 3 microseconds on my typical desktop-class system. I don't know if Windows's VirtualProtect is slower.) On Tue, Mar 12, 2013 at 4:04 PM, Rik Cabanier caban...@gmail.com wrote: I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. That probably won't work since it results in code that executes differently on devices that are HD. The difference between getImageData(HD) and putImageData(HD) is in the canvas operation, not the ImageData: it determines how pixels are scaled when being read out of and written into the canvas backing store. It doesn't apply to this API; ImageData objects don't know anything beyond their pixel data and dimensions. (Code executing differently on high-DPI devices is a bridge we've already crossed. getImageData scales pixels down from the device's pixel ratio; getImageDataHD doesn't, copying backing store pixels one to one.) There is no real reason why you could use it in both HD and non-HD APIs. Rather, there's no reason you couldn't. You can definitely create an ImageData with getImageData and then pass it to putImageDataHD (which would cause the image to be scaled on devices with a pixel ratio other than 1, of course). It feels like something is missing. How does putImageDataHD know that the bitmap should be scaled? Width and height refer to the pixel dimensions and not the 'px' unit
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 4:54 PM, Rik Cabanier caban...@gmail.com wrote: On Tue, Mar 12, 2013 at 4:16 PM, Glenn Maynard gl...@zewt.org wrote: On Tue, Mar 12, 2013 at 12:14 AM, Boris Zbarsky bzbar...@mit.edu wrote: CSE can get rid of the redundant .data gets. Similarly, .data gets can be loop-hoisted in many cases. Doing COW based on page-faults is nicer anyway, but I don't know about the data structures of JS engines to know whether this is feasible. (For example, if an object in JS is preceded by a header that gets written by the engine now and then, it'll probably lie on the same page as the data, which would trigger an expensive fault each time.) I suppose padding the backing store so it doesn't share pages with anything else might be reasonable here: up to about 8k of waste on a system with 4kb pages. The cost of marking the pages read-only would only have to be paid when the copy-on-write action (eg. a call to putImageData) is actually made. Very small buffers could simply disable copy-on-write and always perform a copy, where the waste for padding is more significant and the benefits of avoiding a copy are smaller. (For what it's worth, marking a 128 MB buffer read-only in Linux with mprotect takes on the order of 3 microseconds on my typical desktop-class system. I don't know if Windows's VirtualProtect is slower.) On Tue, Mar 12, 2013 at 4:04 PM, Rik Cabanier caban...@gmail.com wrote: I don't think it is necessary to provide a createImageDataHD in this interface. The caller will know the devicePixelRatio and determine whether to generate high-DPI data. That probably won't work since it results in code that executes differently on devices that are HD. The difference between getImageData(HD) and putImageData(HD) is in the canvas operation, not the ImageData: it determines how pixels are scaled when being read out of and written into the canvas backing store. It doesn't apply to this API; ImageData objects don't know anything beyond their pixel data and dimensions. (Code executing differently on high-DPI devices is a bridge we've already crossed. getImageData scales pixels down from the device's pixel ratio; getImageDataHD doesn't, copying backing store pixels one to one.) There is no real reason why you could use it in both HD and non-HD APIs. Rather, there's no reason you couldn't. You can definitely create an ImageData with getImageData and then pass it to putImageDataHD (which would cause the image to be scaled on devices with a pixel ratio other than 1, of course). It feels like something is missing. How does putImageDataHD know that the bitmap should be scaled? Width and height refer to the pixel dimensions and not the 'px' unit putImageData measures the affected region of the scratch bitmap in CSS pixels and putImageDataHD measures it in device pixels. http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-putimagedata
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Tue, Mar 12, 2013 at 6:54 PM, Rik Cabanier caban...@gmail.com wrote: It feels like something is missing. How does putImageDataHD know that the bitmap should be scaled? Width and height refer to the pixel dimensions and not the 'px' unit It's putImageData that scales, not putImageDataHD. putImageData *always* scales by the pixel ratio. If you're on a system with a ratio of 2, calling putImageData with a 500x1000 buffer will always draw a 1000x2000 image, scaling the image up. putImageDataHD on a 500x1000 buffer will always draw a 500x1000 image, regardless of the pixel ratio. In other words, the blitter knows whether to scale or not based on whether it was putImageData or putImageDataHD that you called, not on something inside the ImageData you passed in. -- Glenn Maynard
Re: [whatwg] Enabling LCD Text and antialiasing in canvas
On Tue, Mar 12, 2013 at 3:08 PM, Stephen White senorbla...@chromium.orgwrote: On Tue, Mar 12, 2013 at 5:36 PM, Rik Cabanier caban...@gmail.com wrote: On Tue, Mar 12, 2013 at 10:03 AM, Stephen White senorbla...@chromium.org wrote: Here's a draft of proposal (1) above: Motivation: Compositing a canvas element into the page can be expensive, due to blending operations, and lack of opportunity for culling. Since arbitrary graphics operations can affect the opacity of the canvas, it is difficult to determine programmatically whether the canvas is opaque. Allowing the developer to explicitly mark a canvas as opaque allows the user agent to optimize blending at page composite time, as well to cull fully-obscured elements behind the canvas. Description: The opaque attribute is a boolean attribute of the canvas element, whose presence indicates that the alpha values in the canvas backing store must be 1.0 at all times. All canvas operations are modified to preserve this invariant. If the opaque attribute is not present, or if parsing its value returns an error, then the default value (false) must be used instead. When a canvas has the opaque attribute, the backing store must be initialized to opaque black (rgba(0, 0, 0, 1.0)), instead of transparent black (rgba(0, 0, 0, 0.0)). Setting, changing, removing or setting the attribute redundantly to its existing value causes the canvas to be cleared to the appropriate value. When a canvas has the opaque attribute, clearRect() clears to opaque black instead of transparent black. The behaviour of putImageData() and putImageDataHD() when a canvas has the opaque attribute is to premultiply the RGB components by the alpha component as usual, but write 1.0 into destination alpha. In other words, if (r, g, b, a) are the component values in a given pixel passed to putImageData[HD](), then r' = ar, g' = ag, b' = ab are the colour components of the resulting canvas pixel, and (r', g', b', 1.0) is written to the canvas backing store. When a canvas has the opaque attribute, all globalCompositeOperation modes behave as normal and the resulting RGB components are written to the canvas backing store, but the alpha component is left unchanged at 1.0. What does 'normal' mean? Is it 'composite with the usual formula' or 'composite with source-over'? Normal means composite with the usual formula. Composite with source-over would be proposal 2) above (but only for those modes which could leave destination alpha at something other than 1.0). Here is what I think the modified compositing math would be for proposal 1) above: mode result opaque result would require opaque mode clear [0, 0] [1, 0] 0 == 1 clear-opaque source-over [Sa + (1 - Sa) * Da, Sc + (1 - Sa) * Dc] [1, Sc + (1 - Sa) * Dc] 1 == 1 source-over source-in [Da * Sa, Da * Sc] [1, Sc] Sa == 1 copy-opaque source-out [(1 - Da) * Sa, (1 - Da) * Sc] [1, 0] 0 == 1 clear-opaque source-atop [Da, Da * Sc + (1 - Sa) * Dc] [1, Sc + (1 - Sa) * Dc] 1 == 1source-atop destination-over [(1 - Da) * Sa + Da, (1 - Da) * Sc + Dc] [1, Dc + (1 - Da) * Sc] 1 == 1 destination-over destination-in [Sa * Da, Sa * Dc] [1, Sa * Dc] Sa == 1destination-in-opaque destination-out [(1 - Sa) * Da, (1 - Sa) * Dc] [1, (1 - Sa) * Dc] Sa == 0xor-opaque destination-atop [Sa, (1 - Da) * Sc + Sa * Dc] [1, Sa * Dc] Sa == 1destination-in-opaque lighter [Sa + Da, Sc + Dc] [1, Sc + Dc] Sa = 0 lighter darker sc * da dc * sa ? srcover : dstover sc dc * sa ? srcover : dstover 1 == 1 darker copy [Sa, Sc] [1, Sc] Sa == 1 copy-opaque xor [(1 - Da) * Sa + (1 - Sa) * Da, (1 - Da) * Sc + (1 - Sa) * Dc] [1, (1 - Sa) * Dc] Sa == 1 xor-opaque (Note: the opaque mode contains some names I made up for the 4 new required modes, but that's just for reference -- these names would not appear in the spec or the API). That looks correct. Did you add darker because you believe it should be added to the list of supported compositing modes? Also, should opaque go on CanvasRenderingContext2D or the canvas object? If it's applied to the canvas object, it seems that it should apply to WebGL too. Does Firefox apply this to WebGL contexts?