@@ -841,30 +841,160 @@ rather than on {{CSSNumericValue}} instances.
841841 and return the result.
842842</div>
843843
844- {{CSSNumericValue}} s can be <dfn export for=CSSNumericValue lt="strong type|strongly typed">strongly typed</dfn> to a type
845- and/or <dfn export for=CSSNumericValue lt="weak type|weakly typed">weakly typed</dfn> to one or more types,
846- or <dfn export for=CSSNumericValue>untyped</dfn> .
844+ ### Numeric Value Typing ### {#numeric-typing}
845+
846+ Each {{CSSNumericValue}} has an associated <dfn for=CSSNumericValue>type</dfn> ,
847+ which is a combination of an [=ordered map|map=] of [=base types=] to integers,
848+ and a [=percent hint=] .
849+ The <dfn for=CSSNumericValue lt="base type">base types</dfn> are
850+ "length",
851+ "angle",
852+ "time",
853+ "frequency",
854+ "resolution",
855+ "flex",
856+ and "percent".
857+ The ordering of a [=type=] ’s entries always matches this [=base type=] ordering.
858+ The <dfn for=CSSNumericValue>percent hint</dfn>
859+ is either null or a [=base type=] other than "percent".
847860
848- A {{CSSUnitValue}} is [=weakly typed=] to the [=CSS type=] of its {{CSSUnitValue/unit}} internal slot’s value
849- if that [=CSS type=] is "percent" or "number".
850- It's [=strongly typed=] to that [=CSS type=] otherwise.
851- It's never [=untyped=] .
861+ <div algorithm>
862+ To <dfn local-lt="add | addition">add two types</dfn> |type1| and |type2|,
863+ perform the following steps:
864+
865+ 1. Replace |type1| with a fresh copy of |type1|,
866+ and |type2| with a fresh copy of |type2|.
867+ Let |finalType| be a new [=type=]
868+ with an initially empty [=ordered map=]
869+ and an initially null [=percent hint=] .
870+
871+ 2.
872+ <dl class=switch>
873+ : If both |type1| and |type2| have non-null [=percent hints=]
874+ with different values
875+ :: The types can't be added.
876+ Return failure.
877+
878+ : If |type1| has a non-null [=percent hint=] |hint| and |type2| doesn't
879+ :: [=Apply the percent hint=] |hint| to |type2|.
880+
881+ Vice versa if |type2| has a non-null [=percent hint=] and |type1| doesn't.
882+
883+ : Otherwise
884+ :: Continue to the next step.
885+ </dl>
886+
887+
888+ 3.
889+ <dl class=switch>
890+ : If all the [=map/entries=] of |type1| with non-zero values
891+ are [=map/contained=] in |type2| with the same value,
892+ and vice-versa
893+ :: Copy all of |type1|’s [=map/entries=] to |finalType|,
894+ and then copy all of |type2|’s [=map/entries=] to |finalType|
895+ that |finalType| doesn't already [=map/contain=] .
896+ Set |finalType|’s [=percent hint=] to |type1|’s [=percent hint=] .
897+ Return |finalType|.
898+
899+ : If |type1| and/or |type2| [=map/contain=] "percent" with a non-zero value,
900+ and |type1| and/or |type2| [=map/contain=] a key *other than* "percent" with a non-zero value
901+ :: For each [=base type=] other than "percent" |hint|:
902+
903+ 1. Provisionally [=apply the percent hint=] |hint| to both |type1| and |type2|.
904+
905+ 2. If, afterwards, all the [=map/entries=] of |type1| with non-zero values
906+ are [=map/contained=] in |type2| with the same value,
907+ and vice versa,
908+ then copy all of |type1|’s [=map/entries=] to |finalType|,
909+ and then copy all of |type2|’s [=map/entries=] to |finalType|
910+ that |finalType| doesn't already [=map/contain=] .
911+ Set |finalType|’s [=percent hint=] to |hint|.
912+ Return |finalType|.
913+
914+ 3. Otherwise, revert |type1| and |type2| to their state at the start of this loop.
915+
916+ If the loop finishes without returning |finalType|,
917+ then the types can't be added.
918+ Return failure.
919+
920+ Note: You can shortcut this in some cases
921+ by just checking the sum of all the [=map/values=]
922+ of |type1| vs |type2|.
923+ If the sums are different,
924+ the types can't be added.
925+
926+ : Otherwise
927+ :: The types can't be added.
928+ Return failure.
929+ </dl>
930+ </div>
931+
932+ <div algorithm>
933+ To <dfn>apply the percent hint</dfn> |hint| to a |type|,
934+ perform the following steps:
935+
936+ 1. If |type| doesn't [=map/contain=] |hint|, set |type|[|hint|] to 0.
937+ 2. If |type| [=map/contains=] "percent", add |type|["percent"] to |type|[|hint|] ,
938+ then set |type|["percent"] to 0.
939+ 4. Set |type|’s [=percent hint=] to |hint|.
940+ </div>
852941
853- A {{CSSMathSum}} , {{CSSMathProduct}} , {{CSSMathMin}} , or {{CSSMathMax}}
854- is [=strongly typed=]
855- if any of the values in its {{CSSMathSum/values}} internal slot
856- are [=strongly typed=] ,
857- to that same [=strong type=] .
858- It's [=weakly typed=] to the union of the [=weak types=]
859- of all of the values in its {{CSSMathSum/values}} internal slot.
860- It's [=untyped=] if its {{CSSMathSum/values}} internal slot [=list/is empty=] .
942+ <div algorithm>
943+ To <dfn for=CSSNumericValue local-lt="multiply | multiplication">multiply two types</dfn> |type1| and |type2|,
944+ perform the following steps:
945+
946+ 1. Replace |type1| with a fresh copy of |type1|,
947+ and |type2| with a fresh copy of |type2|.
948+ Let |finalType| be a new [=type=]
949+ with an initially empty [=ordered map=]
950+ and an initially null [=percent hint=] .
951+
952+ 2. If both |type1| and |type2| have non-null [=percent hints=]
953+ with different values,
954+ the types can't be multiplied.
955+ Return failure.
956+
957+ 3. If |type1| has a non-null [=percent hint=] |hint| and |type2| doesn't,
958+ [=apply the percent hint=] |hint| to |type2|.
861959
862- A {{CSSMathNegate}} or {{CSSMathInvert}}
863- is [=strongly typed=] ,
864- [=weakly typed=] ,
865- or [=untyped=]
866- identically to the value in its {{CSSMathNegate/value}} internal slot.
960+ Vice versa if |type2| has a non-null [=percent hint=] and |type1| doesn't.
961+
962+ 4. Copy all of |type1|’s [=map/entries=] to |finalType|,
963+ then [=map/for each=] |baseType| → |power| of |type2|:
964+
965+ 1. If |finalType|[|baseType|] [=map/exists=] ,
966+ increment its value by |power|.
967+ 2. Otherwise, set |finalType|[|baseType|] to |power|.
968+
969+ Set |finalType|’s [=percent hint=] to |type1|’s [=percent hint=] .
970+
971+ 5. Return |finalType|.
972+ </div>
867973
974+ A [=type=] is said to <dfn for=CSSNumericValue>match</dfn> a CSS production in some circumstances:
975+
976+ * A [=type=] matches <<length>>
977+ if its only non-zero [=map/entry=] is «[ "length" → 1 ] »
978+ and its [=percent hint=] is null.
979+ Similarly for <<angle>> , <<time>> , <<frequency>> , <<resolution>> , and <<flex>> .
980+ * A [=type=] matches <<percentage>>
981+ if its only non-zero [=map/entry=] is «[ "percent" → 1 ] ».
982+ * A [=type=] matches <<length-percentage>>
983+ if its only non-zero [=map/entry=] is either «[ "length" → 1 ] » or «[ "percentage" → 1 ] »
984+ Same for <<angle-percentage>> , <<time-percentage>> , etc.
985+ * A [=type=] matches <<number>>
986+ if it has no non-zero [=map/entries=]
987+ and its [=percent hint=] is null.
988+ * A [=type=] matches <<number-percentage>>
989+ if it has no non-zero [=map/entries=] ,
990+ or its only non-zero [=map/entry=] is «[ "percentage" → 1 ] ».
991+
992+ Many specifications use ''[ <<length>> | <<percentage>> ]''
993+ instead of ''<<length-percentage>>'' in their grammar,
994+ and specify in prose that the <<length>> and <<percentage>> can be combined.
995+ For the purposes of [=matching=] ,
996+ these cases should be treated as <<length-percentage>> .
997+ Similarly for <<angle-percentage>> , etc.
868998
869999
8701000
@@ -937,40 +1067,37 @@ are represented as {{CSSUnitValue}}s.
9371067<div algorithm="CSSUnitValue.type">
9381068 The <dfn attribute for=CSSUnitValue>type</dfn> attribute of a {{CSSUnitValue}} |this| must,
9391069 on reading,
940- return the [=CSS type=] of |this|’s {{CSSUnitValue/unit}} internal slot’s value.
1070+
1071+ Issue: Figure out how we're exposing types. This should probably move up to the superclass, then.
9411072</div>
9421073
9431074<div algorithm="CSS type of a unit">
944- The <dfn>CSS type</dfn> of a string |unit| is:
1075+ The [=type=] of a {{CSSUnitValue}}
1076+ depends on its {{CSSUnitValue/unit}} as follows:
9451077
9461078 <dl class=switch>
9471079 : |unit| is "number"
948- :: "number"
1080+ :: [=type=] is « [ ] » (empty map)
9491081 : |unit| is "percent"
950- :: "percent"
1082+ :: [=type=] is « [ "percent" → 1 ] »
9511083 : |unit| is a <<length>> unit
952- :: "length"
1084+ :: [=type=] is « [ "length" → 1 ] »
9531085 : |unit| is an <<angle>> unit
954- :: "angle"
1086+ :: [=type=] is « [ "angle" → 1 ] »
9551087 : |unit| is a <<time>> unit
956- :: "time"
1088+ :: [=type=] is « [ "time" → 1 ] »
9571089 : |unit| is a <<frequency>> unit
958- :: "frequency"
1090+ :: [=type=] is « [ "frequence" → 1 ] »
9591091 : |unit| is a <<resolution>> unit
960- :: "resolution"
1092+ :: [=type=] is « [ "resolution" → 1 ] »
9611093 : |unit| is a <<flex>> unit
962- :: "flex"
1094+ :: [=type=] is « [ "flex" → 1 ] »
9631095 : anything else
9641096 :: the string does not have a [=CSS type=]
9651097 </dl>
966- </div>
9671098
968- A {{CSSUnitValue}} matches a CSS type production,
969- such as <<number>> or <<length>> ,
970- if its equivalent CSS value
971- (with the same value and unit,
972- or similar with "number" and "percent")
973- matches that production.
1099+ In all cases, the [=percent hint=] of the [=type=] is null.
1100+ </div>
9741101
9751102<div algorithm>
9761103 When asked to <dfn export local-lt="new unit value">create a new unit value</dfn>
@@ -1111,24 +1238,8 @@ of all the "math" operations.
11111238 The <dfn attribute for="CSSMathValue, CSSMathSum, CSSMathProduct, CSSMathMin, CSSMathMax, CSSMathNegate, CSSMathInvert">type</dfn> attribute
11121239 of a {{CSSMathValue}} |this| must,
11131240 on reading,
1114- perform the following steps:
1115-
1116- 1. Let |types| initially be an empty [=ordered set=] .
1117-
1118- 2. If |this| has a [=strong type=] ,
1119- [=set/append=] its [=strong type=] to |types|.
1120-
1121- 3. If |this| has the "percent" [=weak type=] ,
1122- [=set/append=] "percent" to |types|.
1123-
1124- 4. If |this| has the "number" [=weak type=] ,
1125- [=set/append=] "number" to |types|.
1126-
1127- 5. Return the concatenation of the strings in |types|,
1128- each separated by a U+002D HYPHEN-MINUS (-) character.
11291241
1130- Note: This implies that if |this| is [=untyped=] ,
1131- this attribute returns the empty string.
1242+ Issue: Figure out how we're outputting .type
11321243</div>
11331244
11341245<div algorithm="CSSMathSum(...args)">
0 commit comments