Skip to content
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

[css-shapes-2] Specify the grammar for shape() #11207

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 90 additions & 31 deletions css-shapes-2/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,16 @@ spec:css-writing-modes-4; type:concept; text:physical
spec:css-writing-modes-4; type:concept; text:"writing mode"
spec:svg2; type:property;
text:fill-rule
spec:css-values-5; type:value;
text:top;
text:right;
text:bottom;
text:left;
text:center;
text:x-start;
text:y-start;
text:x-end;
text:y-end;
</pre>

<style type="text/css">
Expand Down Expand Up @@ -162,17 +172,32 @@ The ''shape()'' Function</h4>
Each command's starting point is the previous command's ending point.

<pre class=prod>
<<shape-command>> = <<move-command>> | <<line-command>> | <<hv-line-command>> |
<<curve-command>> | <<smooth-command>> | <<arc-command>> | close
<<shape-command>> = <<move-command>> | <<line-command>> | close
<<horizontal-line-command>> | <<vertical-line-command>> |
<<curve-command>> | <<smooth-command>> | <<arc-command>>

<<move-command>> = move <<command-end-point>>
<<line-command>> = line <<command-end-point>>
<<horizontal-line-command>> = hline
[ to [ <<length-percentage>> | left | center | right | x-start | x-end ]
| by <<length-percentage>> ]
<<vertical-line-command>> = vline
[ to [ <<length-percentage>> | top | center | bottom | y-start | y-end ]
| by <<length-percentage>> ]
<<curve-command>> = curve
[ [ to <<position>> && with <<control-point>> [ / <<control-point>> ]? ]
| [ by <<coordinate-pair>> && with <<relative-control-point>> [ / <<relative-control-point>> ]? ] ]
<<smooth-command>> = smooth
[ [ to <<position>> && [with <<control-point>> ]? ]
| [ by <<coordinate-pair>> && [ with <<relative-control-point>> ]? ] ]
<<arc-command>> = arc <<command-end-point>>
&& of <<coordinate-pair>>
&& <<arc-sweep>>? && <<arc-size>>? && [rotate <<angle>>]?

<<command-end-point>> = [ to <<position>> | by <<coordinate-pair>> ]
<<control-point>> = [ <<position>> | <<relative-control-point>> ]
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When implementing this, I mentioned this to @smfr, and he didn't quite agree, but I thought I would bring it to a slightly larger audience.

While generally I don't really see the benefit in disallowing to be used for by (since is really just sugar for [ ], but if the distinction is going to be made, I think the grammar can be a bit more friendly:

<control-point> = [ <position> | <relative-control-point> ]

with one like so:

<absolute-control-point> = <position> [ from [ start | end | origin ] ]?

or, if you dislike the duplication, of the from section,

<control-point-from> = [ from [ start | end | origin ] ]
<absolute-control-point> = <position> <control-point-from>?
<relative-control-point> = <coordinate-pair> <control-point-from>?

This allows a user who is already using an absolute control point, for example like so:

... curve to center center with top left ...

who decides that with top left (aka with 0% 0%) should really be with top left from start to do so. In the current grammar, they have to translate their top left to percentage form and write out with 0% 0% from start.

(doing this also removes a slightly annoying, though manageable, ambiguity in the grammar when parsing <<control-point> since its not clear if "10% 10%" should match <position> or <coordinate-pair>.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When implementing this, I mentioned this to @smfr, and he didn't quite agree, but I thought I would bring it to a slightly larger audience.

While generally I don't really see the benefit in disallowing to be used for by (since is really just sugar for [ ], but if the distinction is going to be made, I think the grammar can be a bit more friendly:

<control-point> = [ <position> | <relative-control-point> ]

with one like so:

<absolute-control-point> = <position> [ from [ start | end | origin ] ]?

or, if you dislike the duplication, of the from section,

<control-point-from> = [ from [ start | end | origin ] ]
<absolute-control-point> = <position> <control-point-from>?
<relative-control-point> = <coordinate-pair> <control-point-from>?

This allows to bottom left from end, how would you interpret that?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As identical to ‘to 100% 0% from end’?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As identical to ‘to 100% 0% from end’?

Ah so like transpose the reference rect to the start/end point... not sure it's a useful box for positioning, might create more confusion than usefulness.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More confusing than the fact that ‘to 100% 0% from end’ is valid and ‘to bottom left’ is valid but not the merged form?

Mostly the point I am trying to make is that treating as something other than syntax sugar for two s seems undesirable. But changing this later is also non-breaking as far I can tell, so I really don’t want to push this any further than I have.

Copy link
Collaborator Author

@noamr noamr Nov 18, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

More confusing than the fact that ‘to 100% 0% from end’ is valid and ‘to bottom left’ is valid but not the merged form?

to 0 100% from end is not valid, only with 0 100% from end or with 10px 220px / 100% 0% from end, the from start|end|origin syntax is only for curve control points.

I read with bottom left as a shorthand for with 0 100% from origin, so expanding it to with 0 100% from origin from end is indeed confusing.

Mostly the point I am trying to make is that treating as something other than syntax sugar for two s seems undesirable. But changing this later is also non-breaking as far I can tell, so I really don’t want to push this any further than I have.

Sounds good!

<<relative-control-point>> = <<coordinate-pair>> [ from [ start | end | origin ] ]?
<<coordinate-pair>> = <<length-percentage>>{2}
<<by-to>> = by | to
<<move-command>> = move <<by-to>> <<coordinate-pair>>
<<line-command>> = line <<by-to>> <<coordinate-pair>>
<<hv-line-command>> = [hline | vline] <<by-to>> <<length-percentage>>
<<curve-command>> = curve [<<by-to>> <<coordinate-pair>> using <<coordinate-pair>>{1,2}]
<<smooth-command>> = smooth [[<<by-to>> <<coordinate-pair>>] || [using <<coordinate-pair>>]?]
<<arc-command>> = arc [[<<by-to>> <<coordinate-pair>>] || [of <<length-percentage>>{1,2}] ||
<<arc-sweep>>? || <<arc-size>>? || [rotate <<angle>>]?]
<<arc-sweep>> = cw | ccw
<<arc-size>> = large | small
</pre>
Expand All @@ -185,19 +210,25 @@ The ''shape()'' Function</h4>
Percentages are resolved against the width or height, respectively,
of the [=reference box=].

<dt><dfn><<by-to>></dfn> = <dfn value for="shape(), <by-to>">by</dfn> | <dfn value for="shape(), <by-to>">to</dfn>
<dt><dfn><<command-end-point>></dfn> = [ <dfn value for="shape(), <command-end-point>">by</dfn> <<position>> | <dfn value for="shape(), <command-end-point>">to</dfn> <<coordinate-pair>> ]
<dd>
Every command can be specified in "absolute" or "relative" coordinates,
determined by their <<by-to>> component.
''to'' indicates that any <<coordinate-pair>>s in the command
determined by their ''shape()/by'' or ''shape()/to'' component.
''shape()/to'' indicates that any <<coordinate-pair>>s in the command
are relative to the top-left corner of the [=reference box=],
while ''by'' indicates that the <<coordinate-pair>>s
while ''shape()/by'' indicates that the <<coordinate-pair>>s
are relative to the command's starting point.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is no longer true when from start / from end are used. There probably needs to be a new paragraph that explains how control points are resolved, or a "see below for details".

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right... There is a paragraph for control points, I'll refer to that.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use ''shape()/by'' for the markup. I think.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed


<<relative-control-point>> defines how ''shape()/by'' and ''shape()/to'' are interpreted for curve control points,
while <<horizontal-line-command>> and <<vertical-line-command>> define how ''shape()/by'' and ''shape()/to'' are
interpreted for horizontal and vertical lines, respectively.

When ''shape()/to'' is used, the coordinates can be specified as <<position>>s instead of <<coordinate-pair>>s.

Note: In either case, <<percentage>> values in <<coordinate-pair>>s
are always computed relative to the [=reference box's=] size.

<dt><dfn><<move-command>></dfn> = <dfn value>move</dfn> <<by-to>> <<coordinate-pair>>
<dt><dfn><<move-command>></dfn> = <dfn value>move</dfn> <<command-end-point>>
<dd>
Adds a <a href="https://www.w3.org/TR/SVG/paths.html#PathDataMovetoCommands">moveto</a> command
to the list of path data commands,
Expand All @@ -209,42 +240,58 @@ The ''shape()'' Function</h4>
Note: This starts a new subpath,
for the purpose of the ''close'' command.

<dt><dfn><<line-command>></dfn> = <dfn value>line</dfn> <<by-to>> <<coordinate-pair>>
<dt><dfn><<line-command>></dfn> = <dfn value>line</dfn> <<command-end-point>>
<dd>
Adds a <a href="https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands">lineto</a> command
to the list of path data commands,
with an ending point specified by the <<coordinate-pair>>.

This draws a straight line from the command's starting point to its ending point.

<dt><dfn><<hv-line-command>></dfn> = [<dfn value>hline</dfn> | <dfn value>vline</dfn>] <<by-to>> <<length-percentage>>
<dt><dfn><<horizontal-line-command>></dfn> = hline [ to [ <length-percentage> | left | center | right | x-start | x-end ]
| by <length-percentage> ]
<dd>
Adds a horizontal (for ''hline'') or vertical (for ''vline'')
Adds a horizontal
<a href="https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands">lineto</a> command
to the list of path data commands.

This is equivalent to a ''line'' command
with the <<length-percentage>> given as the horizontal or vertical component, respectively,
of the <<coordinate-pair>>,
and the other component specified appropriately to make the line horizontal or vertical.
with the <<length-percentage>> given as the horizontal component of the <<coordinate-pair>>.
Specifying the horizontal component of <<position>> instead of a <<length-percentage>> (''left'', ''center'', ''right'', ''x-start'', or ''x-end''),
would draw a line to that <<position>>, with the <<position>>'s vertical component remaining the same as the starting point.

<dt><dfn><<vertical-line-command>></dfn> = vline [ to [ <length-percentage> | top | center | bottom | y-start | y-end ] | by <length-percentage> ]
<dd>
Adds a vertical
<a href="https://www.w3.org/TR/SVG/paths.html#PathDataLinetoCommands">lineto</a> command
to the list of path data commands.

<dt><dfn><<curve-command>></dfn> = <dfn value>curve</dfn> [[<<by-to>> <<coordinate-pair>>] || [using <<coordinate-pair>>{1,2}]]
This is equivalent to a ''line'' command
with the <<length-percentage>> given as the vertical component of the <<coordinate-pair>>.
Specifying the horizontal component of <<position>>
(''top'', ''center'', ''bottom'', ''y-start'', or ''y-end'')
instead of a <<length-percentage>>,
would draw a line to that <<position>>, with the <<position>>'s horizontal component remaining the same as the starting point.

<dt><dfn><<curve-command>></dfn> = <dfn value>curve</dfn> [ [ to <<position>> && with <<control-point>> [ / <<control-point>> ]? ]
| [ by <<coordinate-pair>> && with <<relative-control-point>> [ / <<relative-control-point>> ]? ] ]
<dd>
Adds a Bézier curve command to the list of path data commands,
ending at the point specified by the first <<coordinate-pair>>.
ending at the point specified by the <<position>> following the ''shape()/to'' keyword,
or the <<coordinate-pair>> following the ''shape()/by'' keyword, as specified by <<command-end-point>>.

The <css>using</css> component specifies control points for the curve:
if a single <<coordinate-pair>> is provided,
The <css>with</css> component specifies control points for the curve:
if a single <<control-point>> or <<relative-control-point>> is provided,
the command specifies a <a href="https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands">quadratic curve</a>;
if two <<coordinate-pair>>s are provided,
if two <<control-point>>s or <<relative-control-point>>s are provided,
it specifies a <a href="https://www.w3.org/TR/SVG/paths.html#PathDataCubicBezierCommands">cubic curve</a>.

<dt><dfn><<smooth-command>></dfn> = <dfn value>smooth</dfn> [[<<by-to>> <<coordinate-pair>>] || [using <<coordinate-pair>>]?]
<dt><dfn><<smooth-command>></dfn> = <dfn value>smooth</dfn> [ [ to <<position>> && [with <<control-point>> ]? ]
| [ by <<coordinate-pair>> && [ with <<relative-control-point>> ]? ] ]
<dd>
Adds a smooth Bézier curve command to the list of path data commands,
ending at the point specified by the first <<coordinate-pair>>.

The <css>using</css> component specifies control points for the curve:
ending at the point specified by the <<position>> following the ''shape()/to'' keyword, or the <<coordinate-pair>> following the ''shape()/by'' keyword, as specified by <<command-end-point>>.
The <css>with</css> component specifies control points for the curve:
if it's omitted,
the command specifies a <a href="https://www.w3.org/TR/SVG/paths.html#PathDataQuadraticBezierCommands">smooth quadratic curve</a>;
if it's provided,
Expand All @@ -259,11 +306,23 @@ The ''shape()'' Function</h4>
so the curve appears to smoothly continue from the previous command,
rather than possibly making a sudden direction change.

<dt><dfn><<control-point>></dfn> = [ <<position>> | <<relative-control-point>> ]
<dd>
Provides a control point to a quadratic or cubic Bézier curve.

<dt><dfn><<relative-control-point>></dfn> = <<coordinate-pair>> [ from [ start | end | origin ] ]?
<dd>
Provides a control point to a quadratic or cubic Bézier curve.
When a <css>from</css> keyword is specified followed by <css>start</css>, <css>end</css>, or <css>origin</css>,
the given <<coordinate-pair>> is relative to
the command's starting point, the command's end point, or the [=reference box=], respectively.
If such component is not provided, the <<coordinate-pair>> is relative to the segment's start.

<dt><dfn><<arc-command>></dfn> = <dfn value>arc</dfn> [[<<by-to>> <<coordinate-pair>>] || [of <<length-percentage>>{1,2}] || <<arc-sweep>>? || <<arc-size>>?|| rotate <<angle>>? ]
<dd>
Add an <a href="https://www.w3.org/TR/SVG/paths.html#PathDataEllipticalArcCommands">elliptical arc</a> command
to the list of path data commands,
ending at the point specified by the <<coordinate-pair>>.
ending at the <<command-end-point>>.

The <css>of</css> component specifies the size of the ellipse that the arc is taken from.
The first <<length-percentage>> provides the horizontal radius of the ellipse
Expand Down