Skip to content

Commit 522d784

Browse files
committed
Define the to() operation properly. This is intentionally more generic than needed, so we can define toSum() with the same machinery.
1 parent 117cd4d commit 522d784

File tree

1 file changed

+211
-19
lines changed

1 file changed

+211
-19
lines changed

css-typed-om/Overview.bs

Lines changed: 211 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ Markup Shorthands: markdown yes
3030
[data-algorithm]:not(.heading) > :last-child {
3131
margin-bottom: 0;
3232
}
33+
[data-algorithm] [data-algorithm] {
34+
margin: 1em 0;
35+
}
3336
</style>
3437

3538
<pre class=anchors>
@@ -723,26 +726,215 @@ The following are the arithmetic operations you can perform on dimensions:
723726
into another one with the specified |unit|.
724727
When called, it must perform the following steps:
725728

726-
1. If |unit| does not have a [=CSS type=],
727-
[=throw=] a {{SyntaxError}}
728-
and abort this algorithm.
729+
1. Let |type| be the result of [=creating a type=] from |unit|.
730+
If |type| is failure,
731+
[=throw=] a {{SyntaxError}}.
729732

730-
2. If |this| is a {{CSSUnitValue}}
731-
and |this|’s {{CSSUnitValue/unit}} internal slot and |unit| are [=compatible units=],
732-
return a new {{CSSUnitValue}}
733-
with its {{CSSUnitValue/unit}} internal slot set to |unit|
734-
and its {{CSSUnitValue/value}} internal slot set to |this|’s {{CSSUnitValue/value}}
735-
multiplied by the conversion ratio between the two units.
736-
737-
3. If |this| is a {{CSSCalcValue}}:
738-
1. Let |sum| be 0.
739-
2. [=map/For each=] |oldUnit| → |value| in |this|’s [=map entries=]:
740-
1. If |oldUnit| and |unit| are not [=compatible units=],
741-
[=throw=] a {{TypeError}}.
742-
2. Increment |sum| by |value| times the conversion ratio between |oldUnit| and |unit|.
743-
3. Return a new {{CSSUnitValue}}
744-
with its {{CSSUnitValue/unit}} internal slot set to |unit|
745-
and its {{CSSUnitValue/value}} internal slot set to |sum|.
733+
2. Let |sum| be the result of [=creating a sum value=] from |this|.
734+
If |sum| is failure,
735+
[=throw=] a {{TypeError}}.
736+
737+
3. If |sum| has more than one [=list/item=],
738+
[=throw=] a {{TypeError}}.
739+
Otherwise, let |item| be the sole [=list/item=] in |sum|.
740+
741+
4. If |item| has more than one [=map/value=] in its [=sum value/unit map=],
742+
or that single [=map/value=]’s value is anything other than `1`,
743+
[=throw=] a {{TypeError}}.
744+
Otherwise, let |item unit| be the sole [=map/key=] in the [=sum value/unit map=],
745+
and |item value| be |item|’s [=sum value/value=].
746+
747+
5. If |unit| and |item unit| are not [=compatible units=],
748+
[=throw=] a {{TypeError}}.
749+
750+
6. Return a new {{CSSUnitValue}}
751+
whose {{CSSUnitValue/unit}} internal slot
752+
is set to |unit|,
753+
and whose {{CSSUnitValue/value}} internal slot
754+
is set to |item value|
755+
multiplied by the conversion ratio between |item unit|
756+
and |unit|.
757+
</div>
758+
759+
<div algorithm="sum value">
760+
A <dfn>sum value</dfn>
761+
is an abstract representation of a {{CSSNumericValue}}
762+
as a sum of numbers with (possibly complex) units.
763+
Not all {{CSSNumericValue}}s can be expressed as a [=sum value=].
764+
765+
A [=sum value=] is a [=list=].
766+
Each entry in the list is a [=tuple=] of a <dfn for="sum value">value</dfn>,
767+
which is a number,
768+
and a <dfn for="sum value">unit map</dfn>,
769+
which is a [=ordered map|map=] of units (strings) to powers (integers).
770+
771+
<div class=example>
772+
Here are a few examples of CSS values,
773+
and their equivalent [=sum values=]:
774+
775+
* ''1px'' becomes `«(1, «"px"→1»)»`
776+
* ''calc(1px + 1in)'' becomes `«(97, «"px"→1»)»`
777+
(because ''in'' and ''px'' are [=compatible units=],
778+
and ''px'' is the [=canonical unit=] for them)
779+
* ''calc(1px + 2em)'' becomes `«(1, «"px"→1»), (2, «"em"→»1)»`
780+
* ''calc(1px * 2em)'' becomes `«(2, «"em"→1, "px"→1»)»`
781+
* ''calc(1px + 1deg)'' can't be represented as a [=sum value=]
782+
because it's an invalid computation
783+
* ''calc(1px * 1deg)'' becomes `«(2, «"deg"→1, "px"→1»)»`
784+
</div>
785+
786+
To <dfn lt="create a sum value|creating a sum value">create a sum value</dfn> from a {{CSSNumericValue}} |this|,
787+
the steps differ based on |this|’s class:
788+
789+
<dl class=switch>
790+
: {{CSSUnitValue}}
791+
::
792+
<div algorithm="sum value from CSSUnitValue">
793+
1. Let |unit| be the value of |this|’s {{CSSUnitValue/unit}} internal slot,
794+
and |value| be the value of |this|’s {{CSSUnitValue/value}} internal slot.
795+
2. If |unit| is a member of a set of [=compatible units=],
796+
and is not the set's [=canonical unit=],
797+
multiply |value| by the conversion ratio between |unit| and the [=canonical unit=],
798+
and change |unit| to the [=canonical unit=].
799+
3. If |unit| is `"number"`,
800+
return «(|value|, «»)».
801+
3. Otherwise, return <code>«(|value|, «|unit|→1»)»</code>.
802+
</div>
803+
804+
: {{CSSMathSum}}
805+
::
806+
<div algorithm="sum value from CSSMathSum">
807+
1. Let |values| initially be an empty list.
808+
809+
2. [=list/For each=] |item| in |this|’s {{CSSMathSum/values}} internal slot:
810+
811+
1. Let |value| be the result of [=creating a sum value=] from |item|.
812+
If |value| is failure,
813+
return failure.
814+
815+
2. [=list/For each=] |subvalue| of |value|:
816+
817+
1. If |values| already contains an [=list/item=]
818+
with the same [=sum value/unit map=] as |subvalue|,
819+
increment that [=list/item=]’s [=sum value/value=]
820+
by the [=sum value/value=] of |subvalue|.
821+
822+
2. Otherwise, [=list/append=] |subvalue| to |values|.
823+
824+
3. [=create a type from a unit map|Create a type=]
825+
from the [=sum value/unit map=]
826+
of each [=list/item=] of |values|,
827+
and [=add=] all the types together.
828+
If the result is failure,
829+
return failure.
830+
831+
4. Return |values|.
832+
</div>
833+
834+
: {{CSSMathNegate}}
835+
::
836+
<div algorithm="sum value from CSSMathNegate">
837+
1. Let |values| be the result of [=creating a sum value=]
838+
from |this|’s {{CSSMathNegate/value}} internal slot.
839+
840+
2. If |values| is failure,
841+
return failure.
842+
843+
3. Negate the [=sum value/value=] of each [=list/item=] of |values|.
844+
845+
4. Return |values|.
846+
</div>
847+
848+
: {{CSSMathProduct}}
849+
::
850+
<div algorithm="sum value from CSSMathProduct">
851+
1. Let |values| initially be the [=sum value=] «(1, «»)».
852+
(I.e. what you'd get from ''1''.)
853+
854+
2. [=list/For each=] |item| in |this|’s {{CSSMathProduct/values}} internal slot:
855+
856+
1. Let |new values| be the result of [=creating a sum value=] from |item|.
857+
Let |temp| initially be an empty [=list=].
858+
859+
2. [=list/For each=] |item1| in |values|:
860+
861+
1. [=list/For each=] |item2| in |new values|:
862+
863+
1. Let |item| be a [=tuple=] with its [=sum value/value=]
864+
set to the product of the [=sum value/values=] of |item1| and |item2|,
865+
and its [=sum value/unit map=]
866+
set to the union of the [=sum value/unit maps=] of |item1| and |item2|,
867+
with all [=map/entries=] with a zero value removed.
868+
869+
2. Append |item| to |temp|.
870+
871+
3. Set |values| to |temp|.
872+
873+
3. Return |values|.
874+
</div>
875+
876+
: {{CSSMathInvert}}
877+
::
878+
<div algorithm="sum value from CSSMathInvert">
879+
1. Let |values| be the result of [=creating a sum value=]
880+
from |this|’s {{CSSMathInvert/value}} internal slot.
881+
882+
2. If |values| is failure,
883+
return failure.
884+
885+
3. If the length of [=values=] is more than one,
886+
return failure.
887+
888+
3. Invert (find the reciprocal of) the [=sum value/value=] of the [=list/item=] in |values|,
889+
and negate the [=map/value=] of each [=map/entry=] in its [=sum value/unit map=].
890+
891+
4. Return |values|.
892+
</div>
893+
894+
: {{CSSMathMin}}
895+
::
896+
<div algorithm="sum value from CSSMathMin">
897+
1. Let |args| be the result of [=creating a sum value=]
898+
[=list/for each=] [=list/item=] in |this|’s {{CSSMathMin/values}} internal slot.
899+
900+
2. If any [=list/item=] of |args| has a length greater than one,
901+
return failure.
902+
903+
3. If not all of the [=sum value/unit maps=] among the [=list/items=] of |args| are identical,
904+
return failure.
905+
906+
4. Return the [=list/item=] of |args| whose sole [=list/item=] has the smallest [=sum value/value=].
907+
</div>
908+
909+
: {{CSSMathMax}}
910+
::
911+
<div algorithm="sum value from CSSMathMax">
912+
1. Let |args| be the result of [=creating a sum value=]
913+
[=list/for each=] [=list/item=] in |this|’s {{CSSMathMax/values}} internal slot.
914+
915+
2. If any [=list/item=] of |args| has a length greater than one,
916+
return failure.
917+
918+
3. If not all of the [=sum value/unit maps=] among the [=list/items=] of |args| are identical,
919+
return failure.
920+
921+
4. Return the [=list/item=] of |args| whose sole [=list/item=] has the largest [=sum value/value=].
922+
</div>
923+
</dl>
924+
925+
<div algorithm>
926+
To <dfn>create a type from a unit map</dfn> |unit map|:
927+
928+
1. Let |types| be an initially empty [=list=].
929+
930+
2. [=map/For each=] |unit| → |power| in |unit map|:
931+
932+
1. Let |type| be the result of [=creating a type=] from |unit|.
933+
2. Set |type|’s sole [=map/value=] to |power|.
934+
3. [=list/Append=] |type| to |types|.
935+
936+
3. Return the result of [=multiplying=] all the [=list/items=] of |types|.
937+
</div>
746938
</div>
747939

748940
The {{CSSNumericValue/parse()}} method allows a {{CSSNumericValue}}

0 commit comments

Comments
 (0)