-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Add shapeSmoothingEnabled option for CanvasRenderingContext2D #9192
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you very much for getting this moving.
Not an exhaustive review yet, and definitely not authoritative, but I wonder if this would need some deeper definition.
For instance we could hook into the fill and stroke steps. This might be the occasion to finally define the fill
algorithm that they both do call (see #8145). But maybe this could be handled in a follow-up PR if that's too much work.
Another thing that might require discussion: it's relatively unclear if this should affect clip()
or not.
cc @whatwg/canvas
|
||
<dd> | ||
<p>Returns whether the fill and stroke of paths should be smoothed ("anti-aliased") when drawn, | ||
if their pixels don't line up exactly with the display.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My build complained about "may" -> "can".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not quite sure why that would be? This line has neither of those words...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My review got completely mixed up by github with a prior one I started against the first commit, so all the line numbers are wrong, sorry. It used to be correct on the "files changed" tab but isn't anymore.
Anyway, the "may" in question is at line 68211
the user agent may choose to fill [...]
<div w-nodev> | ||
|
||
<p>Objects that implement the <code>CanvasShapeSmoothing</code> interface have attributes that | ||
control how shape smoothing is performed.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The expression "shape smoothing" seems a bit vague here. Maybe it's best we talk about "rendering" in the authoritative parts? "Smoothing" could also refer to the act of converting angles to curves. To be clear, I still think "shapeSmoothinEnabled" is the right name for the method given imageSmoothingEnabled
, it's really just here that I might prefer something clearer.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Makes sense. How about:
control how shape smoothing is performed.</p> | |
control how shape rasterization is performed.</p> |
as this is really about the conversion of the shape into pixels?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes sounds better to me. Hopefully one day we'd have a formal step by step algo where this would fit in. But for now that might do.
<p>When false, the user agent may choose to fill and stroke paths without smoothing | ||
("anti-aliasing").</p> | ||
|
||
<p>Can be set, to change whether filled and stroked paths are smoothed (true) or, at the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"at the discretion of ..." sounds a bit funny. What about we call it a "hint" directly?
Maybe something along
Can be set, to hint to the user agent whether filled and stroked paths should be smoothed (true), or not (false).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"at the discretion of" follows the language in CanvasFontKerning, though I don't see that language anywhere else. I'm happy to follow your suggestion, though :)
<dt><code data-x=""><var>context</var>.<span subdfn data-x="dom-context-2d-shapeSmoothingEnabled">shapeSmoothingEnabled</span> [ = <var>value</var> ]</code></dt> | ||
|
||
<dd> | ||
<p>When false, the user agent may choose to fill and stroke paths without smoothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I support the idea that this option should be a hint, since UAs are not require to implement any form of anti-aliasing, but I think the wording should be imperative when it comes to disabling anti-aliasing since there are important use cases that require anti-aliasing to be disabled. In particular, the use case of drawing meshes without seams requires AA to be disabled. This has been a long-standing source of pain for developers who've been forced to limit their apps to use pixel-aligned rects, or switch to WebGL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this attribute were an enum instead of a bool, the "imperativeness" and "hint-ness" of the option could be implied in the names of the options in the enum. For example, the options could be "default" and "pixelated".
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on past feature requests, I know many developers would want this option to apply to drawImage(), and IMHO it should also apply to fillRect and strokeRect, for consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree this should also apply to strokeRect()
and fillRect()
, and I believe that if we do hook to the currently undefined fill operation I talked about in my previous comment we'd get them all in one place.
However I'm a bit curious about this drawImage()
idea. How would that cohabit with imageSmoothing[Enabled|Quality]
? Would one overrule the other? Based on what?
As for the attribute being an enum directly, I personally have no strong opinion, it came like that as a kind of symmetry with the existing imageSmoothing[...]
attributes, but it's true that it's not necessary we follow this path. In that case we could also choose to get closer to SVG and their shape-rendering
attribute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this option should affect image smoothing, as @Kaiido says we already have imageSmoothingEnabled
for that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for hintness, it seems like @junov is suggesting we flip the optionality here, to make drawing shapes with AA be optional when shapeSmoothingEnabled = true
, but drawing shapes without AA be required when shapeSmoothingEnabled = false
.
I agree with @junov that this is can be important for maintaining authorial intent. The initial suggestion to phrase this as a hint to the UA was from @mysteryDate here. SVG's shape-rendering
attribute is also phrased as a hint.
My feeling is that phrasing shape smoothing as a hint is okay; there are several other properties of canvas that clearly convey authorial intent but are phrased as a "hint" in the spec. I don't see this one as being particularly different.
As for getting closer to SVG's shape-rendering
, that seems not unreasonable. I'm not really sure what the difference here between crispEdges
and optimizeSpeed
is supposed to be, but it looks like Chromium treats them the same (both meaning "do not anti-alias"). I don't think I have enough domain expertise here to know if this is needless complexity or clever future-proofing. Perhaps @mysteryDate could weigh in?
@@ -63139,6 +63140,11 @@ interface mixin <dfn interface>CanvasImageSmoothing</dfn> { | |||
--> | |||
}; | |||
|
|||
interface mixin <dfn interface>CanvasShapeSmoothing</dfn> { | |||
// shape smoothing | |||
attribute boolean <span data-x="dom-context-2d-shapeSmoothingEnabled">shapeSmoothingEnabled</span>; // (default true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's not repeat the mistake of imageSmoothingEnabled. Please make this attribute an enum and just call it "shapeSmoothing" so that it can be extended in the future if necessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, future extension of this feature might include:
- controlling qualitiy vs performance tradeoffs (number of MSAA samples, choice of analytical AA algorithm, etc.)
- disallowing subpixel AA to avoid artifacts when images are re-scaled or composited
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we go in the enum direction I'm inclined to follow SVG's shape-rendering
, e.g.
enum ShapeRenderingValue { "auto", "optimizeSpeed", "crispEdges", "geometricPrecision" }
interface mixin CanvasShapeRendering {
attribute ShapeRenderingValue shapeRendering; // (default "auto")
}
How would you imagine those future extensions would be added? As additional options in the enum?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for helping to move this forward.
<dt><code data-x=""><var>context</var>.<span subdfn data-x="dom-context-2d-shapeSmoothingEnabled">shapeSmoothingEnabled</span> [ = <var>value</var> ]</code></dt> | ||
|
||
<dd> | ||
<p>When false, the user agent may choose to fill and stroke paths without smoothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If this attribute were an enum instead of a bool, the "imperativeness" and "hint-ness" of the option could be implied in the names of the options in the enum. For example, the options could be "default" and "pixelated".
<dt><code data-x=""><var>context</var>.<span subdfn data-x="dom-context-2d-shapeSmoothingEnabled">shapeSmoothingEnabled</span> [ = <var>value</var> ]</code></dt> | ||
|
||
<dd> | ||
<p>When false, the user agent may choose to fill and stroke paths without smoothing |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Based on past feature requests, I know many developers would want this option to apply to drawImage(), and IMHO it should also apply to fillRect and strokeRect, for consistency.
@@ -63139,6 +63140,11 @@ interface mixin <dfn interface>CanvasImageSmoothing</dfn> { | |||
--> | |||
}; | |||
|
|||
interface mixin <dfn interface>CanvasShapeSmoothing</dfn> { | |||
// shape smoothing | |||
attribute boolean <span data-x="dom-context-2d-shapeSmoothingEnabled">shapeSmoothingEnabled</span>; // (default true) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FWIW, future extension of this feature might include:
- controlling qualitiy vs performance tradeoffs (number of MSAA samples, choice of analytical AA algorithm, etc.)
- disallowing subpixel AA to avoid artifacts when images are re-scaled or composited
@Kaiido I think it would make sense to mention this property in a more formal description of the fill algorithm, but I don't think this change should be blocked on that. |
I did play a bit with the currently proposed chromium patch, and I believe a few more Path2D consumers should be affected. As I presumed, it's a bit surprising at use that Then, it doesn't affect |
Fixes #3181
(See WHATWG Working Mode: Changes for more details.)
/acknowledgements.html ( diff )
/canvas.html ( diff )
/index.html ( diff )