@@ -804,16 +804,8 @@ rather than on {{CSSNumericValue}} instances.
804804 [=throw=] a {{SyntaxError}}
805805 and abort this algorithm.
806806
807- 3. If |result| is a <<dimension-token>> , <<number-token>> , or <<percentage-token>> ,
808- return a new {{CSSUnitValue}} object
809- with its {{CSSUnitValue/value}} internal slot set to the token's value,
810- and its {{CSSUnitValue/value}} internal slot set to the token's unit if it's a <<dimension-token>> ,
811- or `"number"` if it's a <<number-token>> ,
812- or `"percentage"` if it's a <<percentage-token>> .
813-
814- 4. If |result| is a <<calc()>> :
815-
816- Issue: TODO
807+ 3. [=Normalize a numeric value=] |result|,
808+ and return the result.
817809</div>
818810
819811{{CSSNumericValue}} s can be <dfn export for=CSSNumericValue lt="strong type|strongly typed">strongly typed</dfn> to a type
@@ -1877,8 +1869,8 @@ CSS <<number>>, <<percentage>>, and <<dimension>> values become {{CSSUnitValue}}
18771869<div algorithm>
18781870 To <dfn export>normalize a numeric value</dfn> |num|:
18791871
1880- 1. If |num| is a ''calc()'' expression,
1881- [=normalize a calc() expression=] from |num|
1872+ 1. If |num| is a ''calc()'' , ''min()'' , or ''max()'' expression,
1873+ [=normalize a math expression=] from |num|
18821874 and return the result.
18831875
18841876 2. If |num| is the unitless value ''0'' and |num| is a <<dimension>> ,
@@ -1898,34 +1890,81 @@ CSS <<number>>, <<percentage>>, and <<dimension>> values become {{CSSUnitValue}}
18981890</div>
18991891
19001892<div algorithm>
1901- To <dfn export>normalize a ''calc()'' expression</dfn> |num|
1902-
1903- 1. Simplify |num| into an equivalent summation of terms with unique units
1904- (preserving terms with a zero value).
1905-
1906- 2. If |num| is a [=computed value=] and |num| contains only a single term,
1907- [=normalize a numeric value=] from that single term
1908- and return the result.
1909-
1910- 3. Return a {{CSSCalcValue}} ,
1911- whose [=map entries=] is an ordered map which contains, in order:
1912-
1913- 1. If |num| contains a <<number>> term,
1914- the [=map/entry=] «[ "number" → |val| ] »,
1915- where |val| is the value of that term.
1916- 2. If |num| contains any <<dimension>> terms,
1917- the [=map/entries=] «[ |unit| → |val| ] » for each term,
1918- where |unit| is the term's unit and |val| is the term's value,
1919- sorted in [=ASCII case-insensitive=] alphabetical order by their |unit|.
1920- 3. If |num| contains a <<percentage>> term,
1921- the [=map/entry=] «[ "percent" → |val| ] »,
1922- where |val| is the value of that term.
1893+ To <dfn for=CSSMath export local-lt="normalize">normalize a math expression</dfn> |num|:
1894+
1895+ 1. If |num| is a ''min()'' or ''max()'' expression:
1896+ 1. Let |values| be the result of [=CSSMath/normalizing=]
1897+ the arguments to the expression,
1898+ treating each argument as if it were the contents of a ''calc()'' expression.
1899+
1900+ 2. Return a new {{CSSMathMin}} or {{CSSMathMax}} object, respectively,
1901+ with its {{CSSMathMin/values}} internal slot
1902+ set to |values|.
1903+
1904+ 2. Assert: Otherwise, |num| is a ''calc()'' .
1905+
1906+ 3. Turn |num|’s argument
1907+ into an expression tree
1908+ using standard PEMDAS precedence rules,
1909+ with the following exceptions/clarification:
1910+
1911+ * Treat subtraction as instead being addition,
1912+ with the RHS argument instead wrapped in a special "negate" node.
1913+ * Treat division as instead being multiplication,
1914+ with the RHS argument instead wrapped in a special "invert" node.
1915+ * Addition and multiplication are N-ary;
1916+ each node can have any number of arguments.
1917+ * If an expression has only a single value in it,
1918+ and no operation,
1919+ treat it as an addition node with the single argument.
1920+
1921+ 4. Recursively transform the expression tree into objects,
1922+ as follows:
1923+
1924+ <dl class=switch>
1925+ : addition node
1926+ :: becomes a new {{CSSMathSum}} object,
1927+ with its {{CSSMathSum/values}} internal slot
1928+ set to its list of arguments
1929+ : multiplication node
1930+ :: becomes a new {{CSSMathProduct}} object,
1931+ with its {{CSSMathProduct/values}} internal slot
1932+ set to its list of arguments
1933+ : negate node
1934+ :: becomes a new {{CSSMathNegate}} object,
1935+ with its {{CSSMathNegate/value}} internal slot
1936+ set to its argument
1937+ : invert node
1938+ :: becomes a new {{CSSMathInvert}} object,
1939+ with its {{CSSMathInvert/value}} internal slot
1940+ set to its argument
1941+ : leaf node
1942+ :: normalized as appropriate
1943+ </dl>
1944+
1945+ <div class=example>
1946+ For example, ''calc(1px - 2 * 3em)''
1947+ produces the structure:
1948+
1949+ <pre>
1950+ CSSMathSum(
1951+ CSS.px(1),
1952+ CSSMathNegate(
1953+ CSSMathProduct(
1954+ 2,
1955+ CSS.em(3)
1956+ )
1957+ )
1958+ )
1959+ </pre>
1960+ </div>
19231961
19241962 Note: The value computation process may transform different units into identical ones,
19251963 simplifying the resulting expression.
19261964 For example, ''calc(1px + 2em)'' as a specified value
1927- results in a {{CSSCalcValue}} with <nobr> «[ "em" → 2, "px" → 1 ] »</nobr> ,
1928- but as a computed value will give a {{CSSUnitValue}} something like <code> {unit: "px", value: 33}</code> .
1965+ results in a <nobr><code> CSSMathSum(CSS.px(1), CSS.em(2))</code></nobr> ,
1966+ but as a computed value will give <nobr><code> CSS.px(33)</code></nobr> or similar
1967+ (depending on the value of an ''em'' in that context).
19291968</div>
19301969
19311970
0 commit comments