Re: [whatwg] remove resetClip from the Canvas 2D spec
Although Skia could support resetClip() via SkRegion::kReplace_Op, it's problematic for the API in general, and I think we should avoid it. In particular, it makes it impossible to place a display list (SkPicture in Skia parlance) inside a parent display list containing a clip and be assured that the child will not draw outside the given region, since the child display list can always resetClip() its way out of the parent's clip. It probably also prevents culling optimizations for the same reason. For example, if one used Skia to draw the entirety of a browser UI including chrome and content, the resetClip() inside the web page contents would overwrite the browser UI. Obviously we don't do that in Chrome, but it goes some idea of the problem at the API level. Stephen On Thu, Jul 18, 2013 at 1:39 PM, Ian Hickson i...@hixie.ch wrote: On Tue, 29 Jan 2013, Rik Cabanier wrote: we were looking at how resetClip could be implemented in WebKit. Looking over the Core Graphics implementation, this feature can't be implemented without significant overhead. I also found an email from 2007 where Maciej states the same concern: http://permalink.gmane.org/gmane.org.w3c.whatwg.discuss/10582 The solution on Mac is probably for Apple to update CoreGraphics to support this feature. This is a quite widely requested feature. Since no browser has implemented it, can it be removed from the spec? It's new, so no browser having implemented it is expected. If browsers don't implement it, it'll get removed in due course. But it would be sad for authors, who are the main concern here. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] remove resetClip from the Canvas 2D spec
On Fri, 9 Aug 2013, Stephen White wrote: Although Skia could support resetClip() via SkRegion::kReplace_Op, it's problematic for the API in general, and I think we should avoid it. In particular, it makes it impossible to place a display list (SkPicture in Skia parlance) inside a parent display list containing a clip and be assured that the child will not draw outside the given region, since the child display list can always resetClip() its way out of the parent's clip. It probably also prevents culling optimizations for the same reason. For example, if one used Skia to draw the entirety of a browser UI including chrome and content, the resetClip() inside the web page contents would overwrite the browser UI. Obviously we don't do that in Chrome, but it goes some idea of the problem at the API level. This is a quite widely requested feature. What should we do to address this request instead? -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] remove resetClip from the Canvas 2D spec
I originally opened this bug/request for performance reasons, since I try to avoid all use of save() and restore() on the context. As a refresher resetting any piece of context state by itself is possible except for clipping regions. I do see Rik's point about the mess a resetClip() function would make with save() and restore(). It also seems, if I am reading Rik's reasoning right (and its totally possible I'm wrong here), that such a problem would not exist if we had a setClip() function instead. As an alternative I would propose something like setClip() or setClip(path) (with the former working on the current path, just like clip()/fill()/stroke() does). The reason we need something else is because clip() can only ever get smaller, since it takes the intersection of the current clipping region and the current path. setClip() would not take the intersection, instead it would override the current clipping region with the current path (or given path if you prefer). This setClip would still allow de-facto resets of the clipping state by doing: // most likely the transform would also be reset right before this, if it was not already identity // ctx.setTransform(1, 0, 0, 1, 0, 0); ctx.beginPath(); ctx.rect(0, 0, canvas.width, canvas.height); ctx.setClip(); Would such a set up make it easier to accommodate save and restore? (which many people using this would not be using anyway). I'd expect it to be similar to setTransform() in that regard, but maybe not. More generally, does this seem more reasonable, or feasible? On Fri, Aug 9, 2013 at 4:20 PM, Ian Hickson i...@hixie.ch wrote: On Fri, 9 Aug 2013, Stephen White wrote: Although Skia could support resetClip() via SkRegion::kReplace_Op, it's problematic for the API in general, and I think we should avoid it. In particular, it makes it impossible to place a display list (SkPicture in Skia parlance) inside a parent display list containing a clip and be assured that the child will not draw outside the given region, since the child display list can always resetClip() its way out of the parent's clip. It probably also prevents culling optimizations for the same reason. For example, if one used Skia to draw the entirety of a browser UI including chrome and content, the resetClip() inside the web page contents would overwrite the browser UI. Obviously we don't do that in Chrome, but it goes some idea of the problem at the API level. This is a quite widely requested feature. What should we do to address this request instead? -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Mon, 11 Mar 2013, Kenneth Russell 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. Doesn't ImageBitmap support this already? I'm not sure I understand the use case here. Where are you getting the image data from, that it's already in raw RGBA form rather than compressed e.g. as a PNG? (Presumably this isn't coming over the network, since I would imagine the time to compress and decompress an image is far smaller than the time to send uncompressed data. But maybe I'm wrong about that.) On Mon, 11 Mar 2013, Justin Novosad wrote: The use cases I see for this new interface is for relaying image data, that is *not* generated in JS. For example, suppose a chunk of image data is generated on the server side and sent to the client via WebSocket. Wouldn't you send that as a PNG and then just use ImageBitmap? [snip the rest of this thread, which seemed to mainly discuss implementation details -- without knowing what the use case is, it's impossible to evaluate that level of detail] -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] remove resetClip from the Canvas 2D spec
On Fri, Aug 9, 2013 at 4:20 PM, Ian Hickson i...@hixie.ch wrote: This is a quite widely requested feature. What should we do to address this request instead? What if resetClip restored the clip to what it was at the save call that created the current state stack level? In other words, restore the clip, but without popping it off the save/restore stack. Also, resetMatrix could be defined to do the same. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
I think one problem you might run into is that, if you consider a stroked line to be centered on pixel centers rather than pixel edges, then the same path when filled and stroked would touch different pixels along each edge. Consider a 10x10 rectangle, drawn at coordinates coordinates 5, 5. If filled, this would fill pixels 5-14 in X and 5-14 in Y. If stroked, this will draw 1-pixel wide rectangles centered along (5, 5) - (14, 5) - (14, 14) - (5, 5). With antialiasing this will touch pixels 4-15 in each dimension. http://jsfiddle.net/6KS4V/ If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/ . (Please ignore blurriness induced by the CSS upscaling; you can remove the CSS and use a zooming tool if you prefer). Stephen On Tue, Jul 23, 2013 at 7:19 PM, Rik Cabanier caban...@gmail.com wrote: All, we've noticed that if you draw lines in canvas or SVG, they always end up blurry. For instance see this fiddle: http://jsfiddle.net/V92Gn/128/ This happens because you offset 1 pixel and then draw a half pixel stroke on each side. Since it covers only half the pixel, the color gets mapped to 50% gray. You can work around this by doing an extra offset of half the devicepixelratio, but ideally this should never happen. Is this behavior specified somewhere? Is there a way to turn this off?
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Fri, Aug 9, 2013 at 1:32 PM, Ian Hickson i...@hixie.ch wrote: On Mon, 11 Mar 2013, Kenneth Russell 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. Doesn't ImageBitmap support this already? I'm not sure I understand the use case here. Where are you getting the image data from, that it's already in raw RGBA form rather than compressed e.g. as a PNG? (Presumably this isn't coming over the network, since I would imagine the time to compress and decompress an image is far smaller than the time to send uncompressed data. But maybe I'm wrong about that.) From re-reading the thread, it seems that this data comes from the server (or a web worker?) as uncompressed data. The http protocol likely did compression on the packets so the size difference is probably not that great. I think the use-case is to avoid having to copy over the data pixel by pixel from the arraybuffer. On Mon, 11 Mar 2013, Justin Novosad wrote: The use cases I see for this new interface is for relaying image data, that is *not* generated in JS. For example, suppose a chunk of image data is generated on the server side and sent to the client via WebSocket. Wouldn't you send that as a PNG and then just use ImageBitmap? [snip the rest of this thread, which seemed to mainly discuss implementation details -- without knowing what the use case is, it's impossible to evaluate that level of detail] -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 4:17 PM, Stephen White senorbla...@chromium.orgwrote: If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/ My proposal addresses this, by adding an outer stroke mode. http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2013-July/040252.html -- Glenn Maynard
Re: [whatwg] Proposal: ImageData constructor or factory method with preexisting data
On Fri, 9 Aug 2013, Rik Cabanier wrote: On Fri, Aug 9, 2013 at 1:32 PM, Ian Hickson i...@hixie.ch wrote: On Mon, 11 Mar 2013, Kenneth Russell 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. Doesn't ImageBitmap support this already? I'm not sure I understand the use case here. Where are you getting the image data from, that it's already in raw RGBA form rather than compressed e.g. as a PNG? (Presumably this isn't coming over the network, since I would imagine the time to compress and decompress an image is far smaller than the time to send uncompressed data. But maybe I'm wrong about that.) From re-reading the thread, it seems that this data comes from the server (or a web worker?) as uncompressed data. The http protocol likely did compression on the packets so the size difference is probably not that great. I think the use-case is to avoid having to copy over the data pixel by pixel from the arraybuffer. Could you elaborate on the use case? I'm happy to believe that there are times that a server or worker is generating lots of pixel data, but having never run into such a case myself, I would very much like to understand it better. It may be that there are better solutions to the real underlying problem. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
That's an interesting idea. I suppose the fully general solution would be to have a stroke offset. E.g., with a stroke width of 4 and and offset of 2 you'd get outer, offset -2 you'd get inner, offset 1 you'd get 3 pixels outer and 1 pixel inner, etc. Dunno how useful that is, though. Stephen On Fri, Aug 9, 2013 at 5:24 PM, Glenn Maynard gl...@zewt.org wrote: On Fri, Aug 9, 2013 at 4:17 PM, Stephen White senorbla...@chromium.orgwrote: If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/ My proposal addresses this, by adding an outer stroke mode. http://lists.whatwg.org/htdig.cgi/whatwg-whatwg.org/2013-July/040252.html -- Glenn Maynard
Re: [whatwg] Priority between a download and content-disposition
On Sat, 16 Mar 2013, Jonas Sicking wrote: It's currently unclear what to do if a page contains markup like a href=page.txt download=A.txt if the resource at audio.wav responds with either (I'm assuming this is all on the same origin, that there is no script changing the various attributes, etc, just the user clicking, that we're on a platform with meaningful filename extensions, and that the file is returned with an audio/wave type.) 1) Content-Disposition: inline You go down the as a download algorithm, as follows: 1. filname = void 2. doesn't apply 3. interface origin = origin A 4. resource origin = origin A 5. trusted operation = true, since they're the same 6. doesn't apply 7. doesn't apply 8. proposed filename = A.txt 9. filename = proposed filename, A.txt; jump to 13 13. allow user to influence filename; let's assume user does not 14. filename looks ok, so nothing changes 15. doesn't apply 16. claimed type = {audio/wave - wav}; named type = {text/plain - txt} 17. doesn't apply given assumption in step 13 18. doesn't apply 19. filename becomes A.txt.wav 20. return A.txt.wav This seems unambiguous. Where's the problem? 2) Content-Disposition: inline; filename=B.txt You go down the as a download algorithm, as follows: 1. filename = void 2. doesn't apply 3. interface origin = origin A 4. resource origin = origin A 5. trusted operation = true, since they're the same 6. filename = B.txt, jump to 13 13. allow user to influence filename; let's assume user does not 14. filename looks ok, so nothing changes 15. doesn't apply 16. claimed type = {audio/wave - wav}; named type = {text/plain - txt} 17. doesn't apply given assumption in step 13 18. doesn't apply 19. filename becomes B.txt.wav 20. return B.txt.wav Again, this seems unambiguous. 3) Content-Disposition: attachment; filename=B.txt You go down the as a download algorithm, as follows: 1. filename = void 2. filename = B.txt, jump to 13 13. allow user to influence filename; let's assume user does not 14. filename looks ok, so nothing changes 15. doesn't apply 16. claimed type = {audio/wave - wav}; named type = {text/plain - txt} 17. doesn't apply given assumption in step 13 18. doesn't apply 19. filename becomes B.txt.wav 20. return B.txt.wav Again, seems clear. People generally seem to have a harder time with getting header data right, than getting markup right, and so I think that in all cases we should display the save as dialog (or display equivalent download UI) and suggest the filename A.txt. I agree that people fail to set headers. But do we have reason to believe that people are setting their content-attachment headers with a filename incorrectly in the wild? The problem with ignoring the server in the cross-origin case is that it's a security risk (imagine a page trying to cause someone to download a sensitive file, but claiming it's a local file with some filename specific to the site, and then later asking for it to be uploaded again). Given that, it seems sane to try to be consistent between cross-origin and same-origin cases where possible, which means trusting the server over the markup if there's a filename. It seems to me that if a filename is given by the server, it's more likely to be right than wrong. (I agree that it's more likely that there won't be a filename at all.) Potentially there are reasons to do something different in the case when the linked resource lives off of a different origin since in that case there might be security reasons to use the filename or disposition of the server that is actually serving up the content. However I don't think we can expect people to indicate Content-Disposition: inline in order to protect resources. The only way you can end up using the download= attribute's value in the cross-origin case is if the server says Content-Disposition:attachment but doesn't include a filename. Nor do I think that simply using a different filename is going to meaningfully protect downloaded content. I think it's a heck of a lot more likely that you can trick someone into uploading highscores.dat or cartoon-profile.jpeg than it is that you can trick them into uploading John-Doe-bank-account-8172002.csv. So I think a stronger UI warning is needed in this scenario. Steps 12 and 13 of the as a download algorithm, 12 in particular, are all about this. That's what all the warning text in step 12 says, including: it is in the user's interests that the user be somehow notified that the resource in question comes from quite a different source, and to prevent confusion, any suggested file name from the potentially hostile interface origin should be ignored. On Sun, 17 Mar 2013, Glenn Maynard wrote: inline is only there because it has to be; there's no way of saying Content-Disposition: don't care; filename=foo. inline is the default. I think @download should be able to force a download regardless of whether a C-D
Re: [whatwg] Priority between a download and content-disposition
On Fri, Aug 9, 2013 at 3:53 PM, Ian Hickson i...@hixie.ch wrote: On Sat, 16 Mar 2013, Jonas Sicking wrote: It's currently unclear what to do if a page contains markup like a href=page.txt download=A.txt if the resource at audio.wav responds with either (I'm assuming this is all on the same origin, that there is no script changing the various attributes, etc, just the user clicking, that we're on a platform with meaningful filename extensions, and that the file is returned with an audio/wave type.) I don't know what a platform with meaningful filename extensions mean. But other than that, yes. 1) Content-Disposition: inline [snip] This seems unambiguous. Where's the problem? 2) Content-Disposition: inline; filename=B.txt [snip] Again, this seems unambiguous. 3) Content-Disposition: attachment; filename=B.txt [snip] Again, seems clear. I assume that you realize that there is a problem if you think the spec is clear, yet people don't understand what the spec intends to say, or that implementations do different things, that there still is a problem, right? People generally seem to have a harder time with getting header data right, than getting markup right, and so I think that in all cases we should display the save as dialog (or display equivalent download UI) and suggest the filename A.txt. I agree that people fail to set headers. But do we have reason to believe that people are setting their content-attachment headers with a filename incorrectly in the wild? Yes. Generally speaking people get headers wrong all the time. Even when they send the headers. The problem with ignoring the server in the cross-origin case is that it's a security risk (imagine a page trying to cause someone to download a sensitive file, but claiming it's a local file with some filename specific to the site, and then later asking for it to be uploaded again). Given that, it seems sane to try to be consistent between cross-origin and same-origin cases where possible, which means trusting the server over the markup if there's a filename. It seems to me that if a filename is given by the server, it's more likely to be right than wrong. (I agree that it's more likely that there won't be a filename at all.) I agree that having cross-origin and same-origin behave differently is a problem. It's unclear to me if it's a bigger problem than that people can't override the headers that a same-origin server is sending. Note that in this case the problem wasn't with the filename, but rather with inline vs. attachment. At least if I recall correctly. It's been a while. On Mon, 18 Mar 2013, Jonas Sicking wrote: Over in [1] we immediately ran into people wanting to override an explicitly set header. So no, I don't think that is accurate. I think it is just as common to want to control a situation from markup when you are dealing with a server that is sending a header, as when dealing with a server that is not sending a header. At least if you account for the number of servers setting headers. [1] https://bugzilla.mozilla.org/show_bug.cgi?id=676619#c117 Well, this is a Mozilla site. Why is a filename set if you don't want it? Why would you want that video.ogg file downloaded as with-target.txt? IIRC, the problem here was that the server was always sending Content-disposition: inline, which made it impossible to use a download. / Jonas
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 2:17 PM, Stephen White senorbla...@chromium.orgwrote: I think one problem you might run into is that, if you consider a stroked line to be centered on pixel centers rather than pixel edges, then the same path when filled and stroked would touch different pixels along each edge. Consider a 10x10 rectangle, drawn at coordinates coordinates 5, 5. If filled, this would fill pixels 5-14 in X and 5-14 in Y. If stroked, this will draw 1-pixel wide rectangles centered along (5, 5) - (14, 5) - (14, 14) - (5, 5). With antialiasing this will touch pixels 4-15 in each dimension. http://jsfiddle.net/6KS4V/ If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/. (Please ignore blurriness induced by the CSS upscaling; you can remove the CSS and use a zooming tool if you prefer). Yes, I agree that strokes and fills should be treated the same to avoid this problem. I'm unsure if Glenn's suggestion for an outer and inner stroke fix the problem. An inner or outer stroke will look very different. In addition if the corners of the path don't align with the grid, you will get a blurry outline again. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). I then recreated the content in Illustrator, opened the file in Acrobat and took a screenshot: http://bit.ly/15loBhu As you can see, Acrobat doesn't apply any anti-aliasing. It seems to 'snap' the points to the grid and adjust the stroke width so it fills whole pixels. I ran some experiments and I *think* this is also what CSS does. I believe that this could be accomplished with a new attribute in the graphics state. Doing it programmatically should also work but is quite difficult. I wonder if our mozilla friends that work on shumway and pdf.js are running into this...
Re: [whatwg] Priority between a download and content-disposition
On Fri, 9 Aug 2013, Jonas Sicking wrote: On Fri, Aug 9, 2013 at 3:53 PM, Ian Hickson i...@hixie.ch wrote: On Sat, 16 Mar 2013, Jonas Sicking wrote: It's currently unclear what to do if a page contains markup like a href=page.txt download=A.txt if the resource at audio.wav responds with either (I'm assuming this is all on the same origin, that there is no script changing the various attributes, etc, just the user clicking, that we're on a platform with meaningful filename extensions, and that the file is returned with an audio/wave type.) I don't know what a platform with meaningful filename extensions mean. One in which a file's name decides its processing. So for example, Windows is such a platform. When you tell Windows to invoke a file, it examines the part of the name after the final dot, looks that string up in a registry, and uses the information there to decide how to invoke the file. Most Unix shells are examples of platforms that are not extension-based. If you tell Bash to execute a file, it examines the file's contents to determine how to invoke it (e.g. looking for hash-bangs). But other than that, yes. 1) Content-Disposition: inline [snip] This seems unambiguous. Where's the problem? 2) Content-Disposition: inline; filename=B.txt [snip] Again, this seems unambiguous. 3) Content-Disposition: attachment; filename=B.txt [snip] Again, seems clear. I assume that you realize that there is a problem if you think the spec is clear, yet people don't understand what the spec intends to say, or that implementations do different things, that there still is a problem, right? Yes, that's why I asked where's the problem. :-) I don't understand why the spec is ambiguous. Can you elaborate? People generally seem to have a harder time with getting header data right, than getting markup right, and so I think that in all cases we should display the save as dialog (or display equivalent download UI) and suggest the filename A.txt. I agree that people fail to set headers. But do we have reason to believe that people are setting their content-attachment headers with a filename incorrectly in the wild? Yes. Generally speaking people get headers wrong all the time. Even when they send the headers. Fair enough. (I would feel more comfortable with this if we had data specifically for this header, but let's move on.) I agree that having cross-origin and same-origin behave differently is a problem. It's unclear to me if it's a bigger problem than that people can't override the headers that a same-origin server is sending. I don't know. Note that in this case the problem wasn't with the filename, but rather with inline vs. attachment. At least if I recall correctly. It's been a while. I'm not sure I know what problem you're referring to here. Well, this is a Mozilla site. Why is a filename set if you don't want it? Why would you want that video.ogg file downloaded as with-target.txt? IIRC, the problem here was that the server was always sending Content-disposition: inline, which made it impossible to use a download. Content-disposition: inline doesn't make it impossible to use download= according to the spec as far as I can see. -- Ian Hickson U+1047E)\._.,--,'``.fL http://ln.hixie.ch/ U+263A/, _.. \ _\ ;`._ ,. Things that are impossible just take longer. `._.-(,_..'--(,_..'`-.;.'
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 8:16 PM, Rik Cabanier caban...@gmail.com wrote: On Fri, Aug 9, 2013 at 2:17 PM, Stephen White senorbla...@chromium.orgwrote: I think one problem you might run into is that, if you consider a stroked line to be centered on pixel centers rather than pixel edges, then the same path when filled and stroked would touch different pixels along each edge. Consider a 10x10 rectangle, drawn at coordinates coordinates 5, 5. If filled, this would fill pixels 5-14 in X and 5-14 in Y. If stroked, this will draw 1-pixel wide rectangles centered along (5, 5) - (14, 5) - (14, 14) - (5, 5). With antialiasing this will touch pixels 4-15 in each dimension. http://jsfiddle.net/6KS4V/ If the stroke was instead drawn centered over half pixels, the stroked rects would be centered along (5.5, 5.5) - (14.5, 5.5) - (14.5, 14.5) - (14.5, 5.5) - (5.5, 5.5). This would touch pixels 5-15 in each dimension. If drawn with transparency, the resulting left and top edges would look different than the bottom and right edges. E.g., http://jsfiddle.net/9xbkX/. (Please ignore blurriness induced by the CSS upscaling; you can remove the CSS and use a zooming tool if you prefer). Yes, I agree that strokes and fills should be treated the same to avoid this problem. I'm unsure if Glenn's suggestion for an outer and inner stroke fix the problem. An inner or outer stroke will look very different. Sure, but it's up to the developer to choose. It looks like Illustrator has something very similar; see the Align Stroke buttons here: http://help.adobe.com/en_US/illustrator/cs/using/WSA1E31D7D-13E6-41ac-AA8C-4AD129B9FC1Ca.html. I don't have a copy of Illustrator to try it, though. In addition if the corners of the path don't align with the grid, you will get a blurry outline again. Well, as long as you choose the right mitering style, I think the corners would be fine. It's basically the same algorithm as normal path stroking, except instead of translating half the stroke width on either side of the path along the tangent, you'd just use the path as one edge and translate the other the full stroke width. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). I think this more like what the outer stroke style would do: http://jsfiddle.net/ZrbQh/ The interior rectangle is the same in each one, with the outer edge nudged outwards along the tangent (the sizes may be wrong for the 1 lineWidth cases; I didn't spend too long on it). Stephen I then recreated the content in Illustrator, opened the file in Acrobat and took a screenshot: http://bit.ly/15loBhu As you can see, Acrobat doesn't apply any anti-aliasing. It seems to 'snap' the points to the grid and adjust the stroke width so it fills whole pixels. I ran some experiments and I *think* this is also what CSS does. I believe that this could be accomplished with a new attribute in the graphics state. Doing it programmatically should also work but is quite difficult. I wonder if our mozilla friends that work on shumway and pdf.js are running into this...
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 7:16 PM, Rik Cabanier caban...@gmail.com wrote: In addition if the corners of the path don't align with the grid, you will get a blurry outline again. That's the purpose of the second half of my proposal: snapping coordinates and line widths to integers. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Right. In case anyone's not following, this is what's happening: https://zewt.org/~glenn/stroke-alignment.png The red box is the rectangle being drawn. The blue lines are the actual strokes. (This was created by hand, it's not an actual Canvas rendering.) The top row is drawing with integer coordinates. With a 1px stroke, the stroke sits across two pixels, so it aliases. With a 2px stroke, it fully covers two pixels and doesn't alias. With a 3px stroke, it aliases again. The middle row is drawing with half-coordinates. The pattern is reversed: clean, aliased, clean. Additionally, fills (with no stroke) always aliases, since the red box lies between pixels. The bottom row is an outer stroke and integer coordinates: neither strokes nor fills alias, in all three cases. This is the mode I'm suggesting. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). (That seems wrong to me--it should continue to draw based on pixel coverage--but that's a separate issue...) -- Glenn Maynard
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 8:12 PM, Glenn Maynard gl...@zewt.org wrote: On Fri, Aug 9, 2013 at 7:16 PM, Rik Cabanier caban...@gmail.com wrote: In addition if the corners of the path don't align with the grid, you will get a blurry outline again. That's the purpose of the second half of my proposal: snapping coordinates and line widths to integers. As an experiment, I drew 4 rectangles in JSFiddle with stroke width of .5, .75, 1, 1.5 and 2: http://jsfiddle.net/6KS4V/2/ I aligned them to the grid as Glenn suggested. This is a blown up screenshot from IE (Firefox looked the same): http://bit.ly/16FVCKd and here's one from Chrome: http://bit.ly/19Tf9Ko The rectangle that's 2 points wide is somewhat blurry, but the one that is 1.5 is very bad. Right. In case anyone's not following, this is what's happening: https://zewt.org/~glenn/stroke-alignment.png The red box is the rectangle being drawn. The blue lines are the actual strokes. (This was created by hand, it's not an actual Canvas rendering.) The top row is drawing with integer coordinates. With a 1px stroke, the stroke sits across two pixels, so it aliases. With a 2px stroke, it fully covers two pixels and doesn't alias. With a 3px stroke, it aliases again. The middle row is drawing with half-coordinates. The pattern is reversed: clean, aliased, clean. Additionally, fills (with no stroke) always aliases, since the red box lies between pixels. How would you fix a 1.5 pixel width for the stroke or a 1.5 transform? The bottom row is an outer stroke and integer coordinates: neither strokes nor fills alias, in all three cases. This is the mode I'm suggesting. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). (That seems wrong to me--it should continue to draw based on pixel coverage--but that's a separate issue...) Is it? Obviously you can't draw less than a pixel, but the user did specify that he wants it too look black. I admit that this is not a clear cut problem. Our applications also have different ways of rendering depending on what the user is trying to accomplish. If the intent is to mimic high resolution printed output, we blur the lines like Canvas and SVG currently do. If the screen is considered the output device (like in Acrobat), we snap the line art because it looks better (ie grids for spreadsheets). This is most likely why CSS snaps too.
Re: [whatwg] Blurry lines in 2D Canvas (and SVG)
On Fri, Aug 9, 2013 at 11:07 PM, Rik Cabanier caban...@gmail.com wrote: How would you fix a 1.5 pixel width for the stroke or a 1.5 transform? By snapping the final, post-transform width of the stroke to an integer. If you scale by 1.25, eg. ctx.scale(1.25, 1.25), then draw a stroke with a lineWidth of 1.5, the resulting width is 1.875 pixels. That would be rounded up to 2 pixels, after applying the transform (scale) and before invoking the trace a path algorithm. Chrome seems ignore stroke widths that are smaller than 1 (which is reasonable). (That seems wrong to me--it should continue to draw based on pixel coverage--but that's a separate issue...) Is it? Obviously you can't draw less than a pixel, but the user did specify that he wants it too look black. strokeStyle = black doesn't mean every pixel in the stroke should be black. It's the color of the pen. If you draw over half of a pixel with a black pen, you get 50% grey. It'd be one thing if Chrome didn't antialias at all, but if Chrome is antialiasing a stroke with a lineWidth of 1.5, it doesn't make sense that it's not antialiasing a stroke with a lineWidth of 0.75. I don't think this is strictly specified; the only mention of anti-aliasing is an example of how to do it (oversampling). This is tangental, though. Might want to start another thread if you want to go over this more, or we'll derail this one... -- Glenn Maynard