Harmonizing CSSMatrix and SVGMatrix [2D]

While these interfaces will probably never be the most widely used
methods of accessing transformation functionality, I think it would be
beneficial if they shared the same basic mechanics and nomenclature.
The interfaces don't need to be identical, it would just be nice to
not have to remember which object you are using and have to adjust the
order of operations accordingly.

I'm referring, of course, to the old, dreaded (and unfortunately
poorly defined) "row-major" vs "column-major" matrix representations.
I'm going to use "column-major" to mean matrices that are used to
transform vectors represented as columns, and "row-major" to mean the
transpose of "column-major." Unfortunately this often does not
correspond to the other meaning of the terms, which describes the
array representations of tabular data (like matrices).

Here are the current definitions of the interfaces:
http://www.w3.org/TR/SVG/coords.html#InterfaceSVGMatrix
http://www.w3.org/TR/css3-2d-transforms/#cssmatrix-interface (the
editor's draft's interface appears to be unchanged from this version)

Based on the "Nested Transformations" section of the SVG spec
http://www.w3.org/TR/SVG/coords.html#NestedTransformations
it is very clear that SVG's matrices are column-major. This means that
when composing an existing transformation and a new
transformation--when the new transformation is to take place *within*
the space defined by the existing one--the two matrices are multiplied
with the new transformation on the right (there are several examples
at the last link if that explanation is not helpful to you).

There is no place (that I see) in the CSS 2d transform spec that
explicitly states the matrix representation to be used. This might
actually be ideal, because in most cases it doesn't really matter in
terms of the exposed interface. The "matrix(a, b, c, d, e, f)"
transformation function is a good example of this; regardless of
implementation, [a, b] (or [a, b, 0]) is the x basis vector, [c,d] the
y, and [e,f] the translation vector.

However, it is clear that the reference algorithms are in reference to
a row-major matrix representation, and this is backed up by the Webkit
implementation (the only one, I think). This means that even though

firstMatrix.multiply(secondMatrix);

does the multiplication with secondMatrix on the right in both
frameworks, the resulting SVGMatrix will have the secondMatrix nested
within the firstMatrix while the resulting (WebKit)CSSMatrix will have
the firstMatrix nested within the secondMatrix.

--------------
I see at least two possible solutions. Both should be fairly easy to
implement since the interface is so small, and aside from written
descriptions in the spec(s), should only affect the matrix interfaces
(for instance, the "transform" attribute/property is already agreed to
composite in list order).

1) Standardize on one kind of exposed matrix representation. This is
less urgent now (especially with the a-f attributes), but will be
difficult to avoid with a 3d matrix interface. Column-major matrices
are pretty standard in mathematics and recent (last ~20 years)
computer graphics, but row-major matrices have a very long historical
CG precedent.

2) Remain representation neutral. multiply() could then just be
defined in terms of the second matrix applying to the "local" or
"user" coordinate space defined by the first. This would also ensure
that the other methods would be defined in terms of multiply(), e.g.

var result = mat.scale(5);

would be equivalent to

var s = identityMatrix.scale(5);
var result = mat.multiply(s);

Since both interfaces specify that multiply() leaves the underlying
matrix unaffected, I think having one multiplication method should be
sufficient (i.e. matA.multiplyView(matB) saves nothing over
matB.multiply(matA)).

This solution also avoids the (for me, at least) confusing use of
"post-multiply" as a verb in a sentence. Even in the SVG spec, where
the effect of post-multiplication is well described, it can be
difficult to parse which matrix is the subject and which the object of
the operation.
-----------------

Either way, this would be a significant change, but I think one that
would be beneficial going forward. Please let me know your thoughts.

Received on Tuesday, 27 April 2010 22:00:23 UTC