-
Notifications
You must be signed in to change notification settings - Fork 707
[css-borders-4] Specify how borders are rendered for corner-shape
#11610
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
Comments
corner-shape
for rendering edge casescorner-shape
This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org> Reviewed-by: Fredrik Söderquist <fs@opera.com> Cr-Commit-Position: refs/heads/main@{#1421457}
This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org> Reviewed-by: Fredrik Söderquist <fs@opera.com> Cr-Commit-Position: refs/heads/main@{#1421457}
This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org> Reviewed-by: Fredrik Söderquist <fs@opera.com> Cr-Commit-Position: refs/heads/main@{#1421457}
I created a codepen that renders Basically, to achieve the effect where the thickness of the border is equal to the relevant This becomes very apparent with And also with Or scoop: In the prototype, the outer radius is reduced in a number that's a function of the corresponding border and the curvature. (It still looks a bit off at around scoop though, so we're not done with the formula) |
I have a hand full of examples of partial bordered and a couple of others from the giant use case thread: |
Thanks, I wonder how these use case translate to the specifics of border rendering? |
In this example I notice that the thicker right border's width is maintained through the entirety of the top-right angled corner. The width of the drawn border does not transition from the |
There is no current semantic for defining where the corner gets the |
I've drawn up some diagrams of how I think bevel and scoop should be rendered. Note that with uneven border widths, you can't think of rendering the border as stroking a path; it has to be inner and outer paths computed separately. BevelThe goal is to have the bevel section maintain the border width. Naively joining the points you'd use for Proposed algorithm for computing the inner border edge:
ScoopThe goal here again is to maintain the width of the scoop section, and also to have the inner scoop edge prescribe an ellipse around the outer box corner (this looks better than perpendicular joins at the inner edges). Proposed algorithm for computing the inner border edge:
|
The formula in the codepen is sort of what you wrote for bevel. It's equivalent to reducing the outer radius by |
A focused discussion for the WG here is whether concave corner borders (scoop/notch) can be allowed to overlap each other. The alternative is to shrink the outer radius and create some kind of join. I believe the latter is a reasonable constraints for corners, however some use cases will not be possible (a sharp "star" using scoops where the borders overlap). Note that this would be possible with This prototype attempts to solve the join problem to appear consistent with the existing rounded/square shapes. |
Hm, I notice in your prototype that the point on the border's outer edge that looks like it starts the corner stays constant while the border is convex, but moves slightly closer to the corner as it becomes concave. I presume this is what Simon was referring to. @smfr, in your diagrams, could you indicate exactly what parts are intended to correspond to the specified radiuses? I presume it's the length of the outer dashed sides? |
Yes, this is intentional. It creates an effect where |
@smfr I looked at the bevel formula and generalized it to any superellipse, by using the approximate tangent. It looks something like this:
|
Update: I changed the algorithm in the prototype to modify the inner radius instead, but constrain the radius so that it doesn't overlap (effectively shrinking the outer radius when close to 50%). |
…only Automatic update from web-platform-tests Rendering of corner-shape: bevel This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org> Reviewed-by: Fredrik Söderquist <fs@opera.com> Cr-Commit-Position: refs/heads/main@{#1421457} -- wpt-commits: cd546585e048de3c88ffdaa7f83e23f4a0dba932 wpt-pr: 50777
…only Automatic update from web-platform-tests Rendering of corner-shape: bevel This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org> Reviewed-by: Fredrik Söderquist <fs@opera.com> Cr-Commit-Position: refs/heads/main@{#1421457} -- wpt-commits: cd546585e048de3c88ffdaa7f83e23f4a0dba932 wpt-pr: 50777
…only Automatic update from web-platform-tests Rendering of corner-shape: bevel This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdrchromium.org> Commit-Queue: Noam Rosenthal <nrosenthalchromium.org> Reviewed-by: Fredrik Söderquist <fsopera.com> Cr-Commit-Position: refs/heads/main{#1421457} -- wpt-commits: cd546585e048de3c88ffdaa7f83e23f4a0dba932 wpt-pr: 50777 UltraBlame original commit: 402b0e16cc0e1dafd266edb84ae86e3516159e06
…only Automatic update from web-platform-tests Rendering of corner-shape: bevel This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdrchromium.org> Commit-Queue: Noam Rosenthal <nrosenthalchromium.org> Reviewed-by: Fredrik Söderquist <fsopera.com> Cr-Commit-Position: refs/heads/main{#1421457} -- wpt-commits: cd546585e048de3c88ffdaa7f83e23f4a0dba932 wpt-pr: 50777 UltraBlame original commit: 402b0e16cc0e1dafd266edb84ae86e3516159e06
…only Automatic update from web-platform-tests Rendering of corner-shape: bevel This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdrchromium.org> Commit-Queue: Noam Rosenthal <nrosenthalchromium.org> Reviewed-by: Fredrik Söderquist <fsopera.com> Cr-Commit-Position: refs/heads/main{#1421457} -- wpt-commits: cd546585e048de3c88ffdaa7f83e23f4a0dba932 wpt-pr: 50777 UltraBlame original commit: 402b0e16cc0e1dafd266edb84ae86e3516159e06
…only Automatic update from web-platform-tests Rendering of corner-shape: bevel This sets the infrastructure for rendering corner-shape, by storing 4-float "CornerCurvature" on a FloatRoundedRect. Currently only the special-case for "bevel" is handled, with the idea of iterating on the different aspects of rendering as we go along. To properly render bevel (and any other curvature that's lower than round), drawing a straight line from the outer/inner sides doesn't create the right effect, because the diagonal distance between those lines doesn't match the border width. To correct that, while maintaining rendering within the initial corners, the outer corner is shrunk to the point where the resulting diagonal quad has a width equal to the border-width (or interpolating between two border-widths). See open spec issue: w3c/csswg-drafts#11610 Removed existing hand-coded SVG tests, and generating the refs using a canvas polyfill instead. This polyfill can be amended later on as we polish the spec. Bug: 394059604 Change-Id: I9fb76dd7dc557ed10c40adecbb9f68f672de1acc Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6250197 Reviewed-by: Philip Rogers <pdr@chromium.org> Commit-Queue: Noam Rosenthal <nrosenthal@chromium.org> Reviewed-by: Fredrik Söderquist <fs@opera.com> Cr-Commit-Position: refs/heads/main@{#1421457} -- wpt-commits: cd546585e048de3c88ffdaa7f83e23f4a0dba932 wpt-pr: 50777
After many iterations together with @smfr and @fserb, I think we have a good model:
Would love to get a resolution on this soon! Feel free to play with the different options on https://noamr.github.io/squircle-testbed/corner-shape.html |
That definitely feels pretty good to me when I play around with it a little, and your description matches how I think they should work. While we still need to define the diagonal-corner overlap avoidance rules (which your demo mostly avoids, by limiting the radiuses to half the half the side size), I like the shape of this chunk of the rules. (By the way, there's a rendering bug if some of the corners are zero radius.) |
@noamr Sorry for the late reply. This looks very nice, I see that there are two Mode options at the bottom, does the actual implementation of Blink use the bezier curve approximation as well? |
Currently in canary, blink uses the bezier curve approximation and the web platform tests use point-by-point superellipse. |
Here are my test pages for corner inner/outer edge rendering https://noamr.github.io/squircle-testbed/corner-visualizer/shape-renderer.html and with some explanatory control points: (inner edge intersection is not handled yet). I think the main question here is what level of detail the spec should go into. "UAs should attempt to preserve border thickness for various corner shapes", or something more detailed? |
I think we should say that, and also that the borders don't affect the constraint of the outer shape, only go inwards - which means there could be overlaps in some cases. |
The CSS Working Group just discussed
The full IRC log of that discussion<TabAtkins> noamr: this has been a lot of work<TabAtkins> noamr: how detailed does this need to be in the spec? <TabAtkins> noamr: there's an intricate algorithm to make the corner appear consistent <TabAtkins> noamr: like if you have two adjacent scoops, we want them to cut into each other <TabAtkins> noamr: top-right and bottom-right both "scoop 50%" <TabAtkins> noamr: the outer border follows the shape math. the inner borders can overlap <TabAtkins> noamr: don't have a clear idea of how to do this in the spec, but maybe we wnat to say that the border thicknesses need to be consistent at the start and end <TabAtkins> noamr: border overlap does not constrain the radius <TabAtkins> noamr: and are clipped by the outer radius <TabAtkins> noamr: so you can create shapes that fold into themselves <astearns> ack fantasai <TabAtkins> fantasai: I think the behavior you're takling about is that we determine the radiuses per the formula, we shape the outer border edge, then we shape the inner border edge to match by offsetting the endpoints of the corner shape (where it connects to the straight part of the border) by insetting those normal to the curve, and using that to inperolate the inner line, then clipping the inner curve <TabAtkins> fantasai: so you don't get overlapping <TabAtkins> fantasai: i do think we need to spec it <TabAtkins> noamr: also, for very high or low curvatures, outside of 1/-1, we adjust the inner curvature <TabAtkins> noamr: in this example, the inner and outer have a differnet superellipse value to make the thickness appear consistent <TabAtkins> noamr: so question is to what extent is needed to specify <TabAtkins> fantasai: need to specify as far as getting the same math, so impls can match. <fantasai> fantasai: Can allow for approximation, but we need interop here <fantasai> TabAtkins: Should be testable in WPT with some amount of pixel fuzziness <fantasai> TabAtkins: Is your inner ellipse calculation similar to the interpolation, where you get the diagonal width correct and then figure out the superellipse param? <TabAtkins> noamr: not exactly, it creates a vector... it's not just moving the lines, the superellipse needs the same center too <TabAtkins> noamr: it's all similar math <TabAtkins> noamr: i create a line perpendicular to the hull (two straight lines snug to the superellipse) and make something perpendicular to that <TabAtkins> noamr: i can't use the half corner here <TabAtkins> noamr: i think the important bit here is if we're okay with the behavior here, that the border width doesn't affect the outer-radius shape <TabAtkins> noamr: so it stays the same as for normal rounded rects <TabAtkins> fantasai: i think that makes sense <TabAtkins> +1 <fantasai> TabAtkins: In particular, getting the star shape is a desired behavior <fantasai> PROPOSED: Radii are resolved for the outer shape just as for rounded-rect <fantasai> RESOLVED: Radii are resolved for the outer shape just as for existing border-radius rounded-rect shapes <fantasai> fantasai: inner radius gets clipped as soon as it hits any side or other corner <fantasai> PROPOSED: Inner radius gets clipped as soon as it intersects the inner edge of any adjacent side/corner <smfr> q+ <fantasai> s/radius/radius curve/ <TabAtkins> (exact details matter when the borders are partially-transparent, fwiw) <fantasai> PROPOSED: Inner curve gets clipped as soon as it intersects the inner edge of any adjacent side/corner <astearns> ack smfr <TabAtkins> smfr: i think we do radius cosntraints for existing round rects, we shirnk so they dont' join on the inside? <TabAtkins> fantasai: no, it's the outer curve we care about <TabAtkins> smfr: just want to make sure we have consistent behavior <TabAtkins> fantasai: right, we just now resolved to be consistent with the outer radius. <TabAtkins> fantasai: you don't really have the problem the inner radius for curves <TabAtkins> fantasai: the current formula onlya pplies to the outer radius <TabAtkins> fantasai: and as a consequence the inner radius doesn't intersect <TabAtkins> fantasai: but it's the outer radius that's controlled by border-radius <fantasai> RESOLVED: Inner curve gets clipped as soon as it intersects the inner edge of any adjacent side/corner <fantasai> PROPOSED: smfr and noam to spec the math that makes the inner curve look good <fantasai> RESOLVED: smfr and noam to spec the math that makes the inner curve look good |
Follow-up on #10993
corner-shape
cannot be naturally stroked in the same way as ordinary rounded corners or a stroke path, and some details need to be defined.For example, how should stroking bevel/notch look like? Do the inner border collapse into each other, or stay confined within the corner?
The text was updated successfully, but these errors were encountered: