@@ -285,7 +285,7 @@ as well as other [=custom functions=] via <<dashed-function>>s.
285285
286286The '@function/result' descriptor itself does not have a type,
287287but its [=resolve function styles|resolved=] value is type-checked
288- during the [=substitute a dashed function|substitution=] of a <<dashed-function>> .
288+ during the [=replace a dashed function|substitution=] of a <<dashed-function>> .
289289
290290Arguments & Local Variables {#args}
291291-----------------------------------
@@ -385,7 +385,7 @@ with a <<dashed-function>>.
385385
386386A <dfn><<dashed-function>></dfn> is a [=functional notation=]
387387whose function name starts with two dashes (U+002D HYPHEN-MINUS).
388- Its syntax is:
388+ Its [=argument grammar=] is:
389389
390390<pre class="prod informative" nohighlight>
391391 <dashed-function> = --*( <<declaration-value>> #? )
@@ -396,7 +396,7 @@ A <<dashed-function>> can only be used where ''var()'' is allowed.
396396If a property contains one or more <<dashed-function>> s,
397397the entire property’s grammar must be assumed to be valid at parse time.
398398At computed-value time,
399- every <<dashed-function>> must be [=substitute a dashed function|substituted =]
399+ every <<dashed-function>> must be [=replace a dashed function|replaced =]
400400before finally being checked against the property's grammar.
401401
402402Note: Within the body of a [=custom function=] ,
@@ -420,18 +420,18 @@ a [=calling context's=] <dfn for="calling context">root element</dfn>
420420is the real element at the root of the [=calling context=] stack.
421421
422422<div algorithm>
423- To <dfn>substitute a dashed function</dfn> in a value ,
424- with |dashed function| being a <<dashed-function>> :
423+ To <dfn>replace a dashed function</dfn> |dashed function| ,
424+ with a list of |arguments| :
425425
426426 1. Let |function| be the result of dereferencing
427427 the |dashed function|'s name as a [=tree-scoped reference=] .
428- If no such name exists, return failure .
429- 2. [=substitute arbitrary substitution functions|Substitute=]
430- any [= arbitrary substitution functions=]
431- within |dashed function|'s arguments,
432- then parse it as ''<<declaration-value>>#''
433- and let | arguments| be the result
434- (a comma-separated list of CSS values ).
428+ If no such name exists, return the [=guaranteed-invalid value=] .
429+ 2. For each |arg| in |arguments|,
430+ [=substitute arbitrary subsitution functions=] in |arg|,
431+ and replace |arg| with the result.
432+
433+ Note: This may leave some (or all) arguments as the [=guaranteed-invalid value=] ,
434+ triggering [=default values=] (if any ).
435435 3. If |dashed function| is being substituted into a property on an element,
436436 let |calling context| be a [=calling context=]
437437 with that element and that property
@@ -442,17 +442,12 @@ is the real element at the root of the [=calling context=] stack.
442442 Let |calling context| be a [=calling context=]
443443 with that "hypothetical element" and that descriptor.
444444
445- 5 . [=Evaluate a custom function=] ,
445+ 4 . [=Evaluate a custom function=] ,
446446 using |function|, |arguments|, and |calling context|,
447- and replace the <<dashed-function>> with the [=equivalent token sequence=]
447+ and return the [=equivalent token sequence=]
448448 of the value resulting from the evaluation.
449449</div>
450450
451- If [=substitute a dashed function=] fails,
452- and the substitution is taking place on a property's value,
453- then the declaration containing the <<dashed-function>> becomes
454- [=invalid at computed-value time=] .
455-
456451<div class='example'>
457452 A [=comma-containing productions|comma-containing value=]
458453 may be passed as a single argument
@@ -468,6 +463,66 @@ then the declaration containing the <<dashed-function>> becomes
468463 </pre>
469464</div>
470465
466+ <div class='example'>
467+ In the following,
468+ <code> --foo()</code> is in a cycle with itself:
469+
470+ <pre class='lang-css'>
471+ @function --foo(--x) {
472+ result: --foo(10);
473+ }
474+ </pre>
475+
476+ Similarly,
477+ <code> --bar()</code> is in a cycle with itself,
478+ even though the local variable <code> --x</code> is never referenced
479+ by '@function/result' :
480+
481+ <pre class='lang-css'>
482+ @function --bar() {
483+ --x: --bar();
484+ result: 1;
485+ }
486+ </pre>
487+
488+ However, <code> --baz()</code> is not in a cycle with itself here,
489+ since we never evaluate the <code> result</code> declaration within
490+ the <code> @media</code> rule:
491+
492+ <pre class='lang-css'>
493+ @function --baz(--x) {
494+ @media (unknown-feature) {
495+ result: --baz(42);
496+ }
497+ result: 1;
498+ }
499+
500+ </pre>
501+ </div>
502+
503+ <div class='example'>
504+ The function <code> --baz()</code> is not in a cycle in the example below:
505+ even though <code> var(--x)</code> and <code> var(--y)</code> appear in the function body,
506+ they refer to a [=function parameter=] and [=local variable=] , respectively.
507+ The [=custom properties=] <code> --x</code> and <code> --y</code>
508+ both reference <code> --baz()</code> , but that's fine:
509+ those [=custom properties=] are not referenced within <code> --baz()</code> .
510+
511+ <pre class='lang-css'>
512+ @function --baz(--x) {
513+ --y: 10px;
514+ result: calc(var(--x) + var(--y));
515+ }
516+
517+ div {
518+ --x: --baz(1px);
519+ --y: --baz(2px);
520+ width: var(--x); /* 11px */
521+ height: var(--y); /* 12px */
522+ }
523+ </pre>
524+ </div>
525+
471526Evaluating Custom Functions {#evaluating-custom-functions}
472527----------------------------------------------------------
473528
@@ -486,52 +541,71 @@ with its [=function parameters=] overriding "inherited" custom properties of the
486541 and a list of CSS values |arguments|,
487542 returning a CSS value:
488543
489- 1. If the number of items in |arguments|
544+ 1. Let |substitution context| be a [=substitution context=]
545+ containing &bs<<;"function", |custom function|&bs>> ;.
546+
547+ Note: Due to [=tree-scoped names|tree-scoping=] ,
548+ the same function name may appear multiple times on the stack
549+ while referring to different [=custom functions=] .
550+ For this reason, the [=custom function=] itself is included
551+ in the [=substitution context=] , not just its name.
552+ 2. [=guarded|Guard=] |substitution context| for the remainder of this algorithm.
553+ If |substitution context| is marked as [=cyclic substitution context|cyclic=] ,
554+ return the [=guaranteed-invalid value=] .
555+ 3. If the number of items in |arguments|
490556 is greater than the number of [=function parameters=] in |custom function|,
491557 return the [=guaranteed-invalid value=] .
492- 2 . Let |registrations| be an initially empty set of [=custom property registrations=] .
493- 3 . For each [=function parameter=] of |custom function|,
558+ 4 . Let |registrations| be an initially empty set of [=custom property registrations=] .
559+ 5 . For each [=function parameter=] of |custom function|,
494560 create a [=custom property registration=]
495561 with the parameter's name,
496562 a syntax of the [=parameter type=] ,
497563 an inherit flag of "true",
498564 and no initial value.
499565 Add the registration to |registrations|.
500- 4 . If |custom function| has a [=custom function/return type=] ,
566+ 6 . If |custom function| has a [=custom function/return type=] ,
501567 create a [=custom property registration=]
502568 with the name "return"
503569 (violating the usual rules for what a registration's name can be),
504570 a syntax of the [=custom function/return type=] ,
505571 an inherit flag of "false",
506572 and no initial value.
507573 Add the registration to |registrations|.
508- 5 . Let |argument rule| be an initially empty [=style rule=] .
509- 6 . For each [=function parameter=] of |custom function|:
574+ 7 . Let |argument rule| be an initially empty [=style rule=] .
575+ 8 . For each [=function parameter=] of |custom function|:
510576 1. Let |arg value| be the value of the corresponding argument in |arguments|,
511577 or the [=guaranteed-invalid value=] if there is no corresponding argument.
512578 2. Let |default value| be the parameter's [=default value=] .
513579 3. Add a [=custom property=] to |argument rule|
514580 with a name of the parameter's name,
515581 and a value of ''first-valid(|arg value|, |default value|)'' .
516- 7 . [=Resolve function styles=] using |argument styles|, |registrations|, and |calling context|.
582+ 9 . [=Resolve function styles=] using |custom function|, |argument styles|, |registrations|, and |calling context|.
517583 Let |argument styles| be the result.
518- 8 . Let |body rule| be the [=function body=] of |custom function|,
584+ 10 . Let |body rule| be the [=function body=] of |custom function|,
519585 as a [=style rule=] .
520- 9 . For each [=custom property registration=] of |registrations|,
586+ 11 . For each [=custom property registration=] of |registrations|,
521587 set its initial value
522588 to the corresponding value in |argument styles|,
523589 set its syntax
524590 to the [=universal syntax definition=] ,
525591 and prepend a [=custom property=] to |body rule|
526592 with the property name and value in |argument styles|.
527- 10 . [=Resolve function styles=] using |body rule|, |registrations|, and |calling context|.
593+ 12 . [=Resolve function styles=] using |custom function|, |body rule|, |registrations|, and |calling context|.
528594 Let |body styles| be the result.
529- 11. Return the value of the '@function/result' property in |body styles|.
595+ 13. If |substitution context| is marked as a [=cyclic substitution context=] ,
596+ return the [=guaranteed-invalid value=] .
597+
598+ Note: Nested [=arbitrary substitution functions=]
599+ may have marked |substitution context| as [=cyclic substitution context|cyclic=]
600+ at some point after step 2,
601+ for example when resolving '@function/result' .
602+ 14. Return the value of the '@function/result' property in |body styles|.
530603</div>
531604
532605<div algorithm>
533606 To <dfn>resolve function styles</dfn> ,
534- given a style rule |rule|,
607+ given a [=custom function=] |custom function|,
608+ a style rule |rule|,
535609 a set of [=custom property registrations=] |registrations|,
536610 and a [=calling context=] |calling context|,
537611 returning a set of [=computed value|computed=] styles:
@@ -565,6 +639,17 @@ with its [=function parameters=] overriding "inherited" custom properties of the
565639 Note: ''result: inherit'' , for example,
566640 will cause the <<dashed-function>> to <em> evaluate to</em> the ''inherit'' keyword,
567641 similar to ''var(--unknown, inherit)'' .
642+ * For a given [=custom property=] |prop|,
643+ during [=property replacement=] for that property,
644+ the [=substitution context=] also includes |custom function|.
645+ In other words, the [=substitution context=] is
646+ &bs<<;"property", |prop|'s name, |custom function|&bs>> ;
647+
648+ Note: Due to dynamic scoping,
649+ the same property name may appear multiple times on the stack
650+ while referring to different [=custom properties=] .
651+ For this reason, the [=custom function=] itself is included
652+ in the [=substitution context=] , not just its name.
568653
569654 3. Determine the [=computed value=] of all [=custom properties=]
570655 and the '@function/result' "property" on |el|,
@@ -588,88 +673,6 @@ with its [=function parameters=] overriding "inherited" custom properties of the
588673 will be used from these styles.
589674</div>
590675
591-
592-
593-
594- Cycles {#cycles}
595- ----------------
596-
597- The ''@function/result'' descriptor and [=local variables=]
598- within a [=custom function=]
599- may reference other [=custom functions=] or [=custom properties=] ,
600- and may therefore create [[css-variables-1#cycles|cycles]] .
601-
602- For each element, add a node for every specified [=custom function=]
603- to the graph described in [[css-variables-1#cycles]] ;
604- add a node for each [=local variable=]
605- defined within each of those functions;
606- then, for each [=custom function=] <var> func</var> , add edges as follows:
607-
608- * From <var> func</var> to any [=custom function=]
609- referenced by a <<dashed-function>> within <var> func</var> 's body.
610- * From <var> func</var> to any [=custom property=] or [=local variable=]
611- referenced by a ''var()'' within <var> func</var> 's body.
612- * To <var> func</var> from any [=custom property=] or [=local variable=]
613- that references <var> func</var>
614- using a <<dashed-function>> .
615-
616- A <<dashed-function>> referencing a [=custom function=]
617- which is part of a cycle
618- makes the containing [=declaration=] [=invalid at computed-value time=] .
619-
620- Note: Cycles are disallowed even through branches that are not taken
621- during execution.
622-
623- <div class='example'>
624- In the following,
625- <code> --foo()</code> is in a cycle with itself,
626- even though the media query never evaluates to "true":
627-
628- <pre class='lang-css'>
629- @function --foo(--x) {
630- @media (unknown-feature) {
631- result: --foo(42);
632- }
633- result: 1;
634- }
635- </pre>
636-
637- Similarly,
638- <code> --bar()</code> is in a cycle with itself,
639- even though the local variable <code> --x</code> is never referenced:
640-
641- <pre class='lang-css'>
642- @function --bar() {
643- --x: --bar();
644- result: 1;
645- }
646- </pre>
647- </div>
648-
649- <div class='example'>
650- The function <code> --baz()</code> is not in a cycle in the example below:
651- even though <code> var(--x)</code> and <code> var(--y)</code> appear in the function body,
652- they refer to a [=function parameter=] and [=local variable=] , respectively.
653- The [=custom properties=] <code> --x</code> and <code> --y</code>
654- both reference <code> --baz()</code> , but that's fine:
655- those [=custom properties=] are not referenced within <code> --baz()</code> .
656-
657- <pre class='lang-css'>
658- @function --baz(--x) {
659- --y: 10px;
660- result: calc(var(--x) + var(--y));
661- }
662-
663- div {
664- --x: --baz(1px);
665- --y: --baz(2px);
666- width: var(--x); /* 11px */
667- height: var(--y); /* 12px */
668- }
669- </pre>
670- </div>
671-
672-
673676<!-- Big Text: execution
674677
675678█████▌ █ █ █████▌ ███▌ █▌ █▌ █████▌ ████ ███▌ █ █▌
0 commit comments