Skip to content

Commit

Permalink
[css-transforms-1] Specify the "pad, interpolate prefix, then smoosh"…
Browse files Browse the repository at this point in the history
… interpolation behavior

This fixes w3c#927.
  • Loading branch information
birtles committed Oct 16, 2018
1 parent a4ec7a5 commit 719d477
Showing 1 changed file with 59 additions and 34 deletions.
93 changes: 59 additions & 34 deletions css-transforms-1/Overview.bs
Original file line number Diff line number Diff line change
Expand Up @@ -1092,45 +1092,69 @@ The scaling causes a non-invertible CTM for the coordinate space of the div box.
Interpolation of Transforms {#interpolation-of-transforms}
==========================================================

When animating or transitioning transforms, the transform function lists must be interpolated. For interpolation between one transform <em>from-transform</em> and a second transforms <em>to-transform</em>, the rules described below are applied.
[=Interpolation=] of transform function lists is performed as follows:

<ul>
<li id="none-none-animation">
If both the <em>from-</em> and <em>to-transform</em> are ''transform/none'':
* There is no interpolation necessary. The computed value stays ''transform/none''.

<li id="none-transform-animation">
If one of the <em>from-</em> or <em>to-transforms</em> is ''transform/none'':
* The value ''transform/none'' is replaced by an equivalent [=identity transform function=] list for the corresponding transform function list. Both transform function lists get interpolated following the next rule.

<div class="example">
For example, if <em>from-transform</em> is ''scale(2)'' and <em>to-transform</em> is ''transform/none'' then the value ''scale(1)'' will be used for <em>to-transform</em> and animation will proceed using the next rule. Similarly, if <em>from-transform</em> is ''transform/none'' and <em>to-transform</em> is ''scale(2) rotate(50deg)'' then the animation will execute as if <em>from-transform</em> is ''scale(1) rotate(0)''.

<li id=none-none-interpolation>
If both <var>V<sub>a</sub></var> and <var>V<sub>b</sub></var>
are ''transform/none'':
* <var>V<sub>result</sub></var> is ''transform/none''.

<li id=transform-interpolation-length-fixup>
Treating ''transform/none'' as a list of zero length,
if <var>V<sub>a</sub></var> or <var>V<sub>b</sub></var> differ in length:
* extend the shorter list to the length of the longer list,
setting the function at each additional position
to the [=identity transform function=] matching
the function at the corresponding position in the longer list.
Both transform function lists are then interpolated
following the next rule.

<div class=example>
For example, if <var>V<sub>a</sub></var> is ''scale(2)''
and <var>V<sub>b</sub></var> is ''transform/none''
then the value ''scale(1)'' will be used for <var>V<sub>b</sub></var>
and interpolation will proceed using the next rule.
Similarly, if <var>V<sub>a</sub></var> is ''scale(1)''
and <var>V<sub>b</sub></var> is ''scale(2) rotate(50deg)''
then the interpolation will be performed as if
<var>V<sub>a</sub></var> were ''scale(1) rotate(0)''.
</div>

<li id="transform-transform-animation">
If <em>from-</em> and <em>to-transform</em> have the same number of transform functions, each transform function pair has either the same name, or is a derivative of the same <a href="#transform-primitives">primitive</a>:
* Interpolate each transform function pair as described in <a href="#interpolation-of-transform-functions">Interpolation of transform functions</a>. The computed value is the resulting transform function list.

<div class="example">
For example, if <em>from-transform</em> is ''scale(1) translate(0)'' and <em>to-transform</em> is ''translate(100px) scale(2)'' then ''scale(1)'' and ''translate(100px)'' as well as ''translate(0)'' and ''scale(2)'' don't share a common primitive and therefore can not get interpolated following this rule.

<li>
Let <var>V<sub>result</sub></var> be an empty list.
Beginning at the start of
<var>V<sub>a</sub></var> and <var>V<sub>b</sub></var>,
compare the corresponding functions at each position:
* While the functions have either the same name,
or are derivatives of the same
[[#transform-primitives|primitive transform function]],
interpolate the corresponding pair of functions as described in
[[#interpolation-of-transform-functions]]
and append the result to <var>V<sub>result</sub></var>.
* If the pair do not have a common name
or [[#transform-primitives|primitive transform function]],
post-multiply the remaining transform functions in each of
<var>V<sub>a</sub></var> and <var>V<sub>b</sub></var> respectively
to produce two 4x4 matrices.
[=Interpolate=] these two matrices as described in
[[#matrix-interpolation]],
append the result to <var>V<sub>result</sub></var>,
and cease iterating over
<var>V<sub>a</sub></var> and <var>V<sub>b</sub></var>.

<div class=example>
For example,
if <var>V<sub>a</sub></var> is ''scale(1) rotate(90deg) translate(20px)''
and <var>V<sub>b</sub></var> is ''scale(2) translate(10px) rotate(270deg)'',
the ''scale(1)'' and ''scale(2)'' functions will be interpolated
according to [[#interpolation-of-transform-functions]]
while the remainder of each list--
''rotate(90deg) translate(20px)'' and ''translate(10px) rotate(270deg)''--
will first be converted to equivalent 4x4 matrices
and then interpolated as described in [[#matrix-interpolation]].
</div>

<li id="transform-transform-neutral-extend-animation">
If <em>from-</em> and <em>to-transform</em> have a different number of transform functions, and the functions of the shorter transform list have either the same name, or are derivatives of the same <a href="#transform-primitives">primitive</a> of the function at the equivalent position in the longer list:
* Extend the shorter list to the length of the longer list, setting the function at each additional position to the [=identity transform function=] matching the function at the equivalent position in the longer list.

* Interpolate each transform function pair as described in <a href="#interpolation-of-transform-functions">Interpolation of transform functions</a>. The computed value is the resulting transform function list.

<div class="example">
For example, if <em>from-transform</em> is ''scale(1.5)'' and <em>to-transform</em> is ''scale(1.5) rotate(720deg)'', it interpolates as if the <em>from-transform</em> were specified as ''scale(1.5) rotate(0deg)''.
</div>

<li id="other-animation">
In all other cases:
* The transform functions of each transform function list on the <em>from-</em> and <em>to-transform</em> get <a>post-multiplied</a> and converted into 4x4 matrices. Each of the matrices gets interpolated following the instructions in <a href="#matrix-interpolation">Interpolation of matrices</a>. The computed value is the transform function <<matrix()>>.

</ul>

In some cases, an animation might cause a transformation matrix to be singular or non-invertible. For example, an animation in which scale moves from 1 to -1. At the time when the matrix is in such a state, the transformed element is not rendered.
Expand Down Expand Up @@ -1502,7 +1526,8 @@ The following changes were made since the <a href="https://www.w3.org/TR/2017/WD
* Clarify behavior of 'transform' on overflow area.
* Remove ''translateX(0)'', ''translateY(0)'', ''scaleX(0)'', ''scaleY(0)'' from the list of neutral elements.
* Remove any reference of 3D transformations of transform function definitions.
* Allow interpolation between some <<transform-list>>s with different length.
* Specify interpolation between <<transform-list>>s to match lengths and
avoid matrix interpolation for the common prefix of the two lists.
* No 'transform' on non-replaced inline boxes, table-column boxes, and table-column-group boxes.
* Define target coordinate space for transformations on <{pattern}>, <{linearGradient}>, <{radialGradient}> and <{clipPath}> elements.
* Remove 3-value <<rotate()>> from transform function primitives.
Expand Down

0 comments on commit 719d477

Please sign in to comment.