Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Intent to implement: DOMMatrix

536 views
Skip to first unread message

Rik Cabanier

unread,
May 30, 2014, 8:02:23 PM5/30/14
to dev-pl...@lists.mozilla.org
Primary eng emails
caba...@adobe.com, dsch...@adobe.com

*Proposal*
*http://dev.w3.org/fxtf/geometry/#DOMMatrix
<http://dev.w3.org/fxtf/geometry/#DOMMatrix>*

*Summary*
Expose new global objects named 'DOMMatrix' and 'DOMMatrixReadOnly' that
offer a matrix abstraction.

*Motivation*
The DOMMatrix and DOMMatrixReadOnly interfaces represent a mathematical
matrix with the purpose of describing transformations in a graphical
context. The following sections describe the details of the interface.
The DOMMatrix and DOMMatrixReadOnly interfaces replace the SVGMatrix
interface from SVG.

In addition, DOMMatrix will be part of CSSOM where it will simplify getting
and setting CSS transforms.

*Mozilla bug*
https://bugzilla.mozilla.org/show_bug.cgi?id=1018497
I will implement this behind the flag: layout.css.DOMMatrix

*Concerns*
None.
Mozilla already implemented DOMPoint and DOMQuad

*Compatibility Risk*
Blink: unknown
WebKit: in development [1]
Internet Explorer: No public signals
Web developers: unknown

1: https://bugs.webkit.org/show_bug.cgi?id=110001

Jonas Sicking

unread,
May 30, 2014, 8:18:26 PM5/30/14
to Rik Cabanier, dev-pl...@lists.mozilla.org
I'll defer to the layout folks for this one.

/ Jonas
> _______________________________________________
> dev-platform mailing list
> dev-pl...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-platform

Robert O'Callahan

unread,
May 30, 2014, 11:53:52 PM5/30/14
to Jonas Sicking, dev-pl...@lists.mozilla.org, Rik Cabanier
I'm all for it! :-)

Rob
--
Jtehsauts tshaei dS,o n" Wohfy Mdaon yhoaus eanuttehrotraiitny eovni
le atrhtohu gthot sf oirng iyvoeu rs ihnesa.r"t sS?o Whhei csha iids teoa
stiheer :p atroa lsyazye,d 'mYaonu,r "sGients uapr,e tfaokreg iyvoeunr,
'm aotr atnod sgaoy ,h o'mGee.t" uTph eann dt hwea lmka'n? gBoutt uIp
waanndt wyeonut thoo mken.o w

Rik Cabanier

unread,
May 31, 2014, 12:00:52 AM5/31/14
to Robert O'Callahan, dev-pl...@lists.mozilla.org, Jonas Sicking
Since DOMMatrix is replacing SVGMatrix, I don't see a way to implement it
behind a flag.
Should I wait to make that change and leave both SVGMatrix and DOMMatrix in
the code for now?


On Fri, May 30, 2014 at 8:53 PM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

Benoit Jacob

unread,
May 31, 2014, 12:00:57 AM5/31/14
to Rik Cabanier, dev-pl...@lists.mozilla.org
I never seem to be able to discourage people from dragging the W3C into
specialist topics that are outside its area of expertise. Let me try again.

Objection #1:

The skew* methods are out of place there, because, contrary to the rest,
they are not geometric transformations, they are just arithmetic on matrix
coefficients whose geometric impact depends entirely on the choice of a
coordinate system. I'm afraid of leaving them there will propagate
widespread confusion about "skews" --- see e.g. the authors of
http://dev.w3.org/csswg/css-transforms/#matrix-interpolation who seemed to
think that decomposing a matrix into a product of things including a skew
would have geometric significance, leading to clearly unwanted behavior as
demonstrated in
http://people.mozilla.org/~bjacob/transform-animation-not-covariant.html

Objection #2:

This DOMMatrix interface tries to be simultaneously a 4x4 matrices
representing projective 3D transformations, and about 2x3 matrices
representing affine 2D transformations; this mode switch corresponds to the
is2D() getter. I have a long list of objections to this mode switch:
- I believe that, being based on exact floating point comparisons, it is
going to be fragile. For example, people will assert that !is2D() when they
expect a 3D transformation, and that will intermittently fail when for
whatever reason their 3D matrix is going to be exactly 2D.
- I believe that these two classes of transformations (projective 3D and
affine 2D) should be separate classes entirely, that that will make the API
simpler and more efficiently implementable and that forcing authors to
think about that choice more explicitly is doing them a favor.
- I believe that that feature set, with this choice of two classes of
transformations (projective 3D and affine 2D), is arbitrary and
inconsistent. Why not support affine 3D or projective 2D, for instance?

Objection #3:

I dislike the way that this API exposes multiplication order. It's not
obvious enough which of A.multiply(B) and A.multiplyBy(B) is doing A=A*B
and which is doing A=B*A.

Objection #4:

By exposing a inverse() method but no solve() method, this API will
encourage people who have to solve linear systems to do so by doing
matrix.inverse().transformPoint(...), which is inefficient and can be
numerically unstable.

But then of course once we open the pandora box of exposing solvers, the
API grows a lot more. My point is not to suggest to grow the API more. My
point is to discourage you and the W3C from getting into the matrix API
design business. Matrix APIs are bound to either grow big or be useless. I
believe that the only appropriate Matrix interface at the Web API level is
a plain storage class, with minimal getters (basically a thin wrapper
around a typed array without any nontrivial arithmetic built in).

Benoit

Rik Cabanier

unread,
May 31, 2014, 12:40:53 AM5/31/14
to Benoit Jacob, dev-pl...@lists.mozilla.org
On Fri, May 30, 2014 at 9:00 PM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

> I never seem to be able to discourage people from dragging the W3C into
> specialist topics that are outside its area of expertise. Let me try again.
>
> Objection #1:
>
> The skew* methods are out of place there, because, contrary to the rest,
> they are not geometric transformations, they are just arithmetic on matrix
> coefficients whose geometric impact depends entirely on the choice of a
> coordinate system. I'm afraid of leaving them there will propagate
> widespread confusion about "skews" --- see e.g. the authors of
> http://dev.w3.org/csswg/css-transforms/#matrix-interpolation who seemed
> to think that decomposing a matrix into a product of things including a
> skew would have geometric significance, leading to clearly unwanted
> behavior as demonstrated in
> http://people.mozilla.org/~bjacob/transform-animation-not-covariant.html
>

Many people think that the skew* methods were a mistake.
However, DOMMatrix is meant as a drop-in replacement for SVGMatrix which
unfortunately has these methods:
http://www.w3.org/TR/SVG11/coords.html#InterfaceSVGMatrix

I would note though that skewing is very popular among animators so I would
object to their removal.


> Objection #2:
>
> This DOMMatrix interface tries to be simultaneously a 4x4 matrices
> representing projective 3D transformations, and about 2x3 matrices
> representing affine 2D transformations; this mode switch corresponds to the
> is2D() getter. I have a long list of objections to this mode switch:
> - I believe that, being based on exact floating point comparisons, it is
> going to be fragile. For example, people will assert that !is2D() when they
> expect a 3D transformation, and that will intermittently fail when for
> whatever reason their 3D matrix is going to be exactly 2D.
> - I believe that these two classes of transformations (projective 3D and
> affine 2D) should be separate classes entirely, that that will make the API
> simpler and more efficiently implementable and that forcing authors to
> think about that choice more explicitly is doing them a favor.
> - I believe that that feature set, with this choice of two classes of
> transformations (projective 3D and affine 2D), is arbitrary and
> inconsistent. Why not support affine 3D or projective 2D, for instance?
>

These objections sound valid.
However WebKit, Blink and Microsoft already expose CSSMatrix that combines
a 4x4 and 2x3 matrix:
https://developer.apple.com/library/safari/documentation/AudioVideo/Reference/WebKitCSSMatrixClassReference/WebKitCSSMatrix/WebKitCSSMatrix.html
and
it is used extensively by authors.
The spec is standardizing that existing class so we can remove the prefix.


> Objection #3:
>
> I dislike the way that this API exposes multiplication order. It's not
> obvious enough which of A.multiply(B) and A.multiplyBy(B) is doing A=A*B
> and which is doing A=B*A.
>

The "by" methods do the transformation in-place. In this case, both are A =
A * B
Maybe you're thinking of preMultiply?


> Objection #4:
>
> By exposing a inverse() method but no solve() method, this API will
> encourage people who have to solve linear systems to do so by doing
> matrix.inverse().transformPoint(...), which is inefficient and can be
> numerically unstable.
>
> But then of course once we open the pandora box of exposing solvers, the
> API grows a lot more. My point is not to suggest to grow the API more. My
> point is to discourage you and the W3C from getting into the matrix API
> design business. Matrix APIs are bound to either grow big or be useless. I
> believe that the only appropriate Matrix interface at the Web API level is
> a plain storage class, with minimal getters (basically a thin wrapper
> around a typed array without any nontrivial arithmetic built in).
>

We already went over this at length about a year ago.
Dirk's been asking for feedback on this interface on www-style and
public-fx so can you raise your concerns there? Just keep in mind that we
have to support the SVGMatrix and CSSMatrix interfaces.

Anne van Kesteren

unread,
May 31, 2014, 3:11:09 AM5/31/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org
On Sat, May 31, 2014 at 6:40 AM, Rik Cabanier <caba...@gmail.com> wrote:
> We already went over this at length about a year ago.

It does seem useful to note some of the lessons you learned in the
specification. E.g. that skew() is largely misplaced, but that it's
there for compatibility. And what the plan is for evolving the API
going forward as it seems that might affect implementation strategy
reading Benoit's comments.


--
http://annevankesteren.nl/

Rik Cabanier

unread,
May 31, 2014, 12:03:53 PM5/31/14
to Anne van Kesteren, Benoit Jacob, dev-pl...@lists.mozilla.org
On Sat, May 31, 2014 at 12:11 AM, Anne van Kesteren <ann...@annevk.nl>
wrote:
I'm unaware of planned extensions to the API. Following Benoit's comments
and some experiments we might change the internal implementation to be
either use a 2d or 3d matrix and this will change the spec a bit.
Benoit, please let us know what we can test to reproduce your concerns. You
should already be able to reproduce it with WebKitCSSMatrix.

The API is planned as a replacement for SVGMatrix and will be used in
Canvas 2D and CSSOM.
It also takes arrayBuffers in the constructor and in toFloatxxArray to
simplify interaction with WebGL. It's not meant as a high performance
replacement for a WebGL matrix.

Bob

unread,
Jun 1, 2014, 5:05:42 PM6/1/14
to
In a play on words, is this some kind of SM (not SeaMonkey) feature?

Benoit Jacob

unread,
Jun 1, 2014, 6:11:29 PM6/1/14
to Rik Cabanier, dev-pl...@lists.mozilla.org
2014-05-31 0:40 GMT-04:00 Rik Cabanier <caba...@gmail.com>:

> Objection #3:
>>
>> I dislike the way that this API exposes multiplication order. It's not
>> obvious enough which of A.multiply(B) and A.multiplyBy(B) is doing A=A*B
>> and which is doing A=B*A.
>>
>
> The "by" methods do the transformation in-place. In this case, both are A
> = A * B
> Maybe you're thinking of preMultiply?
>

Ah, I was totally confused by the method names. "Multiply" is already a
verb, and the method name "multiply" already implicitly means "multiply
*by*". So it's very confusing that there is another method named multiplyBy.

Methods on DOMMatrixReadOnly are inconsistently named: some, like
"multiply", are named after the /verb/ describing what they /do/, while
others, like "inverse", are named after the /noun/ describing what they
/return/.

Choose one and stick to it; my preference goes to the latter, i.e. rename
"multiply" to "product" in line with the existing "inverse" and then the
DOMMatrix.multiplyBy method can drop the "By" and become "multiply".

If you do rename "multiply" to "product" that leads to the question of what
"preMultiply" should become.

In an ideal world (not commenting on whether that's a thing we can get on
the Web), "product" would be a global function, not a class method, so you
could let people write product(X, Y) or product(Y, X) and not have to worry
about naming differently the two product orders.




>
>> Objection #4:
>>
>> By exposing a inverse() method but no solve() method, this API will
>> encourage people who have to solve linear systems to do so by doing
>> matrix.inverse().transformPoint(...), which is inefficient and can be
>> numerically unstable.
>>
>> But then of course once we open the pandora box of exposing solvers, the
>> API grows a lot more. My point is not to suggest to grow the API more. My
>> point is to discourage you and the W3C from getting into the matrix API
>> design business. Matrix APIs are bound to either grow big or be useless. I
>> believe that the only appropriate Matrix interface at the Web API level is
>> a plain storage class, with minimal getters (basically a thin wrapper
>> around a typed array without any nontrivial arithmetic built in).
>>
>
> We already went over this at length about a year ago.
> Dirk's been asking for feedback on this interface on www-style and
> public-fx so can you raise your concerns there? Just keep in mind that we
> have to support the SVGMatrix and CSSMatrix interfaces.
>

My ROI for arguing on standards mailing on matrix math topics lists has
been very low, presumably because these are specialist topics outside of
the area of expertise of these groups.

Here are a couple more objections by the way:

Objection #5:

The isIdentity() method has the same issue as was described about is2D()
above: as matrices get computed, they are going to jump unpredicably
between being exactly identity and not. People using isIdentity() to jump
between code paths are going to get unexpected jumps between code paths
i.e. typically performance cliffs, or worse if they start asserting that a
matrix should or should not be exactly identity. For that reason, I would
remove the isIdentity method.

Objection #6:

The determinant() method, being in this API the only easy way to get
something that looks roughly like a measure of invertibility, will probably
be (mis-)used as a measure of invertibility. So I'm quite confident that it
has a strong mis-use case. Does it have a strong good use case? Does it
outweigh that? Note that if the intent is precisely to offer some kind of
measure of invertibility, then that is yet another thing that would be best
done with a singular values decomposition (along with solving, and with
computing a polar decomposition, useful for interpolating matrices), by
returning the ratio between the lowest and the highest singular value.

Either that, or explain how tricky it is to correctly use the determinant
in a measure of invertibility, and integrate a code example about that.

Benoit

Rik Cabanier

unread,
Jun 1, 2014, 11:19:41 PM6/1/14
to Benoit Jacob, dev-pl...@lists.mozilla.org
On Sun, Jun 1, 2014 at 3:11 PM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

>
>
>
> 2014-05-31 0:40 GMT-04:00 Rik Cabanier <caba...@gmail.com>:
>
> Objection #3:
>>>
>>> I dislike the way that this API exposes multiplication order. It's not
>>> obvious enough which of A.multiply(B) and A.multiplyBy(B) is doing A=A*B
>>> and which is doing A=B*A.
>>>
>>
>> The "by" methods do the transformation in-place. In this case, both are A
>> = A * B
>> Maybe you're thinking of preMultiply?
>>
>
> Ah, I was totally confused by the method names. "Multiply" is already a
> verb, and the method name "multiply" already implicitly means "multiply
> *by*". So it's very confusing that there is another method named multiplyBy.
>

Yeah, we had discussion on that. 'by' is not ideal, but it is much shorter
than 'InPlace'. Do you have a suggestion to improve the name?


> Methods on DOMMatrixReadOnly are inconsistently named: some, like
> "multiply", are named after the /verb/ describing what they /do/, while
> others, like "inverse", are named after the /noun/ describing what they
> /return/.
>
> Choose one and stick to it; my preference goes to the latter, i.e. rename
> "multiply" to "product" in line with the existing "inverse" and then the
> DOMMatrix.multiplyBy method can drop the "By" and become "multiply".
>
> If you do rename "multiply" to "product" that leads to the question of
> what "preMultiply" should become.
>
> In an ideal world (not commenting on whether that's a thing we can get on
> the Web), "product" would be a global function, not a class method, so you
> could let people write product(X, Y) or product(Y, X) and not have to worry
> about naming differently the two product orders.
>

Unfortunately, we're stuck with the API names that SVG gave to its matrix.
The only way to fix this is to duplicate the API and support both old and
new names which is very confusing,


> Objection #4:
>>>
>>> By exposing a inverse() method but no solve() method, this API will
>>> encourage people who have to solve linear systems to do so by doing
>>> matrix.inverse().transformPoint(...), which is inefficient and can be
>>> numerically unstable.
>>>
>>> But then of course once we open the pandora box of exposing solvers, the
>>> API grows a lot more. My point is not to suggest to grow the API more. My
>>> point is to discourage you and the W3C from getting into the matrix API
>>> design business. Matrix APIs are bound to either grow big or be useless. I
>>> believe that the only appropriate Matrix interface at the Web API level is
>>> a plain storage class, with minimal getters (basically a thin wrapper
>>> around a typed array without any nontrivial arithmetic built in).
>>>
>>
>> We already went over this at length about a year ago.
>> Dirk's been asking for feedback on this interface on www-style and
>> public-fx so can you raise your concerns there? Just keep in mind that we
>> have to support the SVGMatrix and CSSMatrix interfaces.
>>
>
> My ROI for arguing on standards mailing on matrix math topics lists has
> been very low, presumably because these are specialist topics outside of
> the area of expertise of these groups.
>

It is a constant struggle. We need to strike a balance between
mathematicians and average authors. Stay with it and prepare to repeat
yourself; it's frustrating for everyone involved.
If you really don't want to participate anymore, we can get to an agreement
here and I can try to convince the others.


> Here are a couple more objections by the way:
>
> Objection #5:
>
> The isIdentity() method has the same issue as was described about is2D()
> above: as matrices get computed, they are going to jump unpredicably
> between being exactly identity and not. People using isIdentity() to jump
> between code paths are going to get unexpected jumps between code paths
> i.e. typically performance cliffs, or worse if they start asserting that a
> matrix should or should not be exactly identity. For that reason, I would
> remove the isIdentity method.
>

isIdentity() indeed suffers from rounding errors but since it's useful, I'm
hesitant to remove it.
In our rendering libraries at Adobe, we check if a matrix is *almost*
identity. Maybe we can do the same here?


> Objection #6:
>
> The determinant() method, being in this API the only easy way to get
> something that looks roughly like a measure of invertibility, will probably
> be (mis-)used as a measure of invertibility. So I'm quite confident that it
> has a strong mis-use case. Does it have a strong good use case? Does it
> outweigh that? Note that if the intent is precisely to offer some kind of
> measure of invertibility, then that is yet another thing that would be best
> done with a singular values decomposition (along with solving, and with
> computing a polar decomposition, useful for interpolating matrices), by
> returning the ratio between the lowest and the highest singular value.
>
> Either that, or explain how tricky it is to correctly use the determinant
> in a measure of invertibility, and integrate a code example about that.
>

I don't know why the determinant method was added and I would be fine with
removing it

Benoit Jacob

unread,
Jun 2, 2014, 7:57:30 AM6/2/14
to Rik Cabanier, dev-pl...@lists.mozilla.org
2014-06-01 23:19 GMT-04:00 Rik Cabanier <caba...@gmail.com>:

>
>
>
> On Sun, Jun 1, 2014 at 3:11 PM, Benoit Jacob <jacob.b...@gmail.com>
> wrote:
>
>>
>>
>>
>> 2014-05-31 0:40 GMT-04:00 Rik Cabanier <caba...@gmail.com>:
>>
>> Objection #3:
>>>>
>>>> I dislike the way that this API exposes multiplication order. It's not
>>>> obvious enough which of A.multiply(B) and A.multiplyBy(B) is doing A=A*B
>>>> and which is doing A=B*A.
>>>>
>>>
>>> The "by" methods do the transformation in-place. In this case, both are
>>> A = A * B
>>> Maybe you're thinking of preMultiply?
>>>
>>
>> Ah, I was totally confused by the method names. "Multiply" is already a
>> verb, and the method name "multiply" already implicitly means "multiply
>> *by*". So it's very confusing that there is another method named multiplyBy.
>>
>
> Yeah, we had discussion on that. 'by' is not ideal, but it is much shorter
> than 'InPlace'. Do you have a suggestion to improve the name?
>

My suggestion was the one below that part (multiply->product,
multiplyBy->multiply) but it seems that that's moot because:


>
>
>> Methods on DOMMatrixReadOnly are inconsistently named: some, like
>> "multiply", are named after the /verb/ describing what they /do/, while
>> others, like "inverse", are named after the /noun/ describing what they
>> /return/.
>>
>> Choose one and stick to it; my preference goes to the latter, i.e. rename
>> "multiply" to "product" in line with the existing "inverse" and then the
>> DOMMatrix.multiplyBy method can drop the "By" and become "multiply".
>>
>> If you do rename "multiply" to "product" that leads to the question of
>> what "preMultiply" should become.
>>
>> In an ideal world (not commenting on whether that's a thing we can get on
>> the Web), "product" would be a global function, not a class method, so you
>> could let people write product(X, Y) or product(Y, X) and not have to worry
>> about naming differently the two product orders.
>>
>
> Unfortunately, we're stuck with the API names that SVG gave to its matrix.
> The only way to fix this is to duplicate the API and support both old and
> new names which is very confusing,
>

Sounds like the naming is not even up for discussion, then? In that case,
what is up for discussion?

That's basically the core disagreement here: I'm not convinced that just
because something is in SVG implies that it should be propagated as a
"blessed" abstraction for the rest of the Web. Naming and branding matter:
something named "SVGMatrix" clearly suggests "should be used for dealing
with SVG" while something named "DOMMatrix" sounds like it's recommended
for use everywhere on the Web.

I would rather have SVG keep its own matrix class while the rest of the Web
gets something nicer.



>
>
>> Objection #4:
>>>>
>>>> By exposing a inverse() method but no solve() method, this API will
>>>> encourage people who have to solve linear systems to do so by doing
>>>> matrix.inverse().transformPoint(...), which is inefficient and can be
>>>> numerically unstable.
>>>>
>>>> But then of course once we open the pandora box of exposing solvers,
>>>> the API grows a lot more. My point is not to suggest to grow the API more.
>>>> My point is to discourage you and the W3C from getting into the matrix API
>>>> design business. Matrix APIs are bound to either grow big or be useless. I
>>>> believe that the only appropriate Matrix interface at the Web API level is
>>>> a plain storage class, with minimal getters (basically a thin wrapper
>>>> around a typed array without any nontrivial arithmetic built in).
>>>>
>>>
>>> We already went over this at length about a year ago.
>>> Dirk's been asking for feedback on this interface on www-style and
>>> public-fx so can you raise your concerns there? Just keep in mind that we
>>> have to support the SVGMatrix and CSSMatrix interfaces.
>>>
>>
>> My ROI for arguing on standards mailing on matrix math topics lists has
>> been very low, presumably because these are specialist topics outside of
>> the area of expertise of these groups.
>>
>
> It is a constant struggle. We need to strike a balance between
> mathematicians and average authors. Stay with it and prepare to repeat
> yourself; it's frustrating for everyone involved.
> If you really don't want to participate anymore, we can get to an
> agreement here and I can try to convince the others.
>

I'm happy to continue to provide input on matrix API design or other math
topics. I can't go spontaneously participate in conversations on all the
mailing lists though; dev-platform is the only one that I monitor closely,
and where I'm very motivated to get involved, because what really makes my
life harder is if the wrong API gets implemented in Gecko.


>
>> Here are a couple more objections by the way:
>>
>> Objection #5:
>>
>> The isIdentity() method has the same issue as was described about is2D()
>> above: as matrices get computed, they are going to jump unpredicably
>> between being exactly identity and not. People using isIdentity() to jump
>> between code paths are going to get unexpected jumps between code paths
>> i.e. typically performance cliffs, or worse if they start asserting that a
>> matrix should or should not be exactly identity. For that reason, I would
>> remove the isIdentity method.
>>
>
> isIdentity() indeed suffers from rounding errors but since it's useful,
> I'm hesitant to remove it.
> In our rendering libraries at Adobe, we check if a matrix is *almost*
> identity. Maybe we can do the same here?
>

Since you say that isIdentity() is useful, can you provide an example of a
valid use case for it, to make this conversation concrete?
Switching isIdentity() to use a fuzzy comparison, as IIUC you say Adobe
uses internally, doesn't change fundamentally the problem here, which is
that there is a sudden jump. The discontinuity is merely moved elsewhere.
Any discontinuous matrix function, in particular any function taking a
matrix and returning a boolean, is easy to misuse. I'm willing to believe
that Adobe uses that for a precise, valid purpose though --- but here in a
DOMMatrix interface we can't assume any specific purpose.

Benoit

Robert O'Callahan

unread,
Jun 2, 2014, 7:59:17 AM6/2/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 3:19 PM, Rik Cabanier <caba...@gmail.com> wrote:

> isIdentity() indeed suffers from rounding errors but since it's useful, I'm
> hesitant to remove it.
> In our rendering libraries at Adobe, we check if a matrix is *almost*
> identity. Maybe we can do the same here?
>

One option would be to make "isIdentity" and "is2D" state bits in the
object rather than predicates on the matrix coefficients. Then for each
matrix operation, we would define how it affects the isIdentity and is2D
bits. For example we could say translate(tx, ty, tz)'s result isIdentity if
and only if the source matrix isIdentity and tx, ty and tz are all exactly
0.0, and the result is2D if and only if the source matrix is2D and tz is
exactly 0.0.

With that approach, isIdentity and is2D would be much less sensitive to
precision issues. In particular they'd be independent of the precision used
to compute and store store matrix elements, which would be helpful I think.

Benoit Jacob

unread,
Jun 2, 2014, 8:07:38 AM6/2/14
to Robert O'Callahan, dev-pl...@lists.mozilla.org, Rik Cabanier
2014-06-02 7:59 GMT-04:00 Robert O'Callahan <rob...@ocallahan.org>:

> On Mon, Jun 2, 2014 at 3:19 PM, Rik Cabanier <caba...@gmail.com> wrote:
>
>> isIdentity() indeed suffers from rounding errors but since it's useful,
>> I'm
>> hesitant to remove it.
>> In our rendering libraries at Adobe, we check if a matrix is *almost*
>> identity. Maybe we can do the same here?
>>
>
> One option would be to make "isIdentity" and "is2D" state bits in the
> object rather than predicates on the matrix coefficients. Then for each
> matrix operation, we would define how it affects the isIdentity and is2D
> bits. For example we could say translate(tx, ty, tz)'s result isIdentity if
> and only if the source matrix isIdentity and tx, ty and tz are all exactly
> 0.0, and the result is2D if and only if the source matrix is2D and tz is
> exactly 0.0.
>
> With that approach, isIdentity and is2D would be much less sensitive to
> precision issues. In particular they'd be independent of the precision used
> to compute and store store matrix elements, which would be helpful I think.
>

+1 ! If we do want to keep the isIdentity and is2D methods, then indeed
this is the right way do implement them.

Benoit

Philip Chee

unread,
Jun 2, 2014, 8:44:25 AM6/2/14
to
On 02/06/2014 05:05, Bob wrote:
> In a play on words, is this some kind of SM (not SeaMonkey) feature?

No it isn't.

Phil

--
Philip Chee <phi...@aleytys.pc.my>, <phili...@gmail.com>
http://flashblock.mozdev.org/ http://xsidebar.mozdev.org
Guard us from the she-wolf and the wolf, and guard us from the thief,
oh Night, and so be good for us to pass.

Martin Thomson

unread,
Jun 2, 2014, 11:04:21 AM6/2/14
to Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier
On 2014-05-30, at 21:00, Benoit Jacob <jacob.b...@gmail.com> wrote:

> 2x3 matrices
> representing affine 2D transformations; this mode switch corresponds to the
> is2D() getter

Am I the only one that finds this method entirely unintuitive? After looking at only the IDL, admittedly, is2D() === true.

Is the name intended to convey the fact that this is a highly specialised matrix, because it doesn’t really do that for me.

Rik Cabanier

unread,
Jun 2, 2014, 11:50:09 AM6/2/14
to Benoit Jacob, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 4:57 AM, Benoit Jacob <jacob.b...@gmail.com>
wrote:
All the methods of DOMMatrix and the helper methods of DOMMatrixReadOnly

That's basically the core disagreement here: I'm not convinced that just
> because something is in SVG implies that it should be propagated as a
> "blessed" abstraction for the rest of the Web. Naming and branding matter:
> something named "SVGMatrix" clearly suggests "should be used for dealing
> with SVG" while something named "DOMMatrix" sounds like it's recommended
> for use everywhere on the Web.
>
> I would rather have SVG keep its own matrix class while the rest of the
> Web gets something nicer.
>

SVG really wants to replace its matrix with something better. (You can't
even "new" an SVGMatrix) Also, since DOMMatrix will be exposed in CSS, SVG
transforms would be returned as DOMMatrix in CSS and SVGMatrix in the DOM
which would be very unintuitive.

IMO it's silly to have 2 classes that do almost the same thing on the web
platform.
Well, your life would be just as hard if all the other browsers implement
it :-)


> Here are a couple more objections by the way:
>>>
>>> Objection #5:
>>>
>>> The isIdentity() method has the same issue as was described about is2D()
>>> above: as matrices get computed, they are going to jump unpredicably
>>> between being exactly identity and not. People using isIdentity() to jump
>>> between code paths are going to get unexpected jumps between code paths
>>> i.e. typically performance cliffs, or worse if they start asserting that a
>>> matrix should or should not be exactly identity. For that reason, I would
>>> remove the isIdentity method.
>>>
>>
>> isIdentity() indeed suffers from rounding errors but since it's useful,
>> I'm hesitant to remove it.
>> In our rendering libraries at Adobe, we check if a matrix is *almost*
>> identity. Maybe we can do the same here?
>>
>

Rik Cabanier

unread,
Jun 2, 2014, 11:52:27 AM6/2/14
to Robert O'Callahan, Benoit Jacob, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 4:59 AM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

> On Mon, Jun 2, 2014 at 3:19 PM, Rik Cabanier <caba...@gmail.com> wrote:
>
>> isIdentity() indeed suffers from rounding errors but since it's useful,
>> I'm
>> hesitant to remove it.
>> In our rendering libraries at Adobe, we check if a matrix is *almost*
>> identity. Maybe we can do the same here?
>>
>
> One option would be to make "isIdentity" and "is2D" state bits in the
> object rather than predicates on the matrix coefficients. Then for each
> matrix operation, we would define how it affects the isIdentity and is2D
> bits. For example we could say translate(tx, ty, tz)'s result isIdentity if
> and only if the source matrix isIdentity and tx, ty and tz are all exactly
> 0.0, and the result is2D if and only if the source matrix is2D and tz is
> exactly 0.0.
>
> With that approach, isIdentity and is2D would be much less sensitive to
> precision issues. In particular they'd be independent of the precision used
> to compute and store store matrix elements, which would be helpful I think.
>

That would work for me. The constructors would still need to test to make
sure that the matrix is 2D and Identity but that wouldn't suffer from the
rounding issues that Benoit brought up.

Rik Cabanier

unread,
Jun 2, 2014, 11:53:34 AM6/2/14
to Martin Thomson, Benoit Jacob, dev-pl...@lists.mozilla.org
it conveys that this is a 2d matrix and that you can ignore the 3d
components.

Nick Alexander

unread,
Jun 2, 2014, 12:05:04 PM6/2/14
to dev-pl...@lists.mozilla.org
On 2014-06-02, 4:59 AM, Robert O'Callahan wrote:
> On Mon, Jun 2, 2014 at 3:19 PM, Rik Cabanier <caba...@gmail.com> wrote:
>
>> isIdentity() indeed suffers from rounding errors but since it's useful, I'm
>> hesitant to remove it.
>> In our rendering libraries at Adobe, we check if a matrix is *almost*
>> identity. Maybe we can do the same here?
>>
>
> One option would be to make "isIdentity" and "is2D" state bits in the
> object rather than predicates on the matrix coefficients. Then for each
> matrix operation, we would define how it affects the isIdentity and is2D
> bits. For example we could say translate(tx, ty, tz)'s result isIdentity if
> and only if the source matrix isIdentity and tx, ty and tz are all exactly
> 0.0, and the result is2D if and only if the source matrix is2D and tz is
> exactly 0.0.
>
> With that approach, isIdentity and is2D would be much less sensitive to
> precision issues. In particular they'd be independent of the precision used
> to compute and store store matrix elements, which would be helpful I think.

I agree that most mathematical ways of determining a matrix (as a
rotation, or a translation, etc) come with isIdentity for free; but are
most matrices derived from some underlying transformation, or are they
given as a list of coefficients?

If the latter, the isIdentity flag needs to be determined by the
constructor, or fed as a parameter. Exactly how does the constructor
determine the parameter? Exactly how does the user?

Nick

Martin Thomson

unread,
Jun 2, 2014, 12:24:30 PM6/2/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org

On 2014-06-02, at 08:53, Rik Cabanier <caba...@gmail.com> wrote:

> it conveys that this is a 2d matrix and that you can ignore the 3d components.

Maybe you misunderstood what I was implying. You are describing an intended application of the matrix to 2d or 3d graphics. The problem is that the is2D() method is applicable to what appears to be a generic object. That object has a name “DOMMatrix” which implies a general capability that isn’t present.

However, when someone says matrix [1], I think matrix. My understanding of matrices extends beyond 4x4 and 2x3. It’s understandable perhaps that the matrix object is 2-dimensional only, because that is highly useful for the application you have in mind, and a lot more besides.

I think that a lot of this sort of confusion would be remedied by having a different name, in both cases. CSSMatrix is heaps better (but there I might be demonstrating ignorance of “CSS”), and is2x3() would also help.

—Martin

[1] ...here a DOM prefix has been rendered effectively meaningless through overuse.

Rik Cabanier

unread,
Jun 2, 2014, 12:54:10 PM6/2/14
to Martin Thomson, Benoit Jacob, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 9:24 AM, Martin Thomson <m...@mozilla.com> wrote:

>
> On 2014-06-02, at 08:53, Rik Cabanier <caba...@gmail.com> wrote:
>
> > it conveys that this is a 2d matrix and that you can ignore the 3d
> components.
>
> Maybe you misunderstood what I was implying. You are describing an
> intended application of the matrix to 2d or 3d graphics. The problem is
> that the is2D() method is applicable to what appears to be a generic
> object. That object has a name “DOMMatrix” which implies a general
> capability that isn’t present.
>
> However, when someone says matrix [1], I think matrix. My understanding
> of matrices extends beyond 4x4 and 2x3. It’s understandable perhaps that
> the matrix object is 2-dimensional only, because that is highly useful for
> the application you have in mind, and a lot more besides.
>

The DOM can only represent 2x3 and 4x4 matrices. If there comes a day that
it goes higher, we will extend the DOMMatrix class.


> I think that a lot of this sort of confusion would be remedied by having a
> different name, in both cases. CSSMatrix is heaps better (but there I
> might be demonstrating ignorance of “CSS”), and is2x3() would also help.
>

We went over CSSMatrix before, but the object is available outside CSS as
well. (Canvas 2D and SVG)
In addition, we have DOMPoint and DOMQuad that are part of the same spec
and already landed in Firefox.

Rik Cabanier

unread,
Jun 2, 2014, 12:59:25 PM6/2/14
to Nick Alexander, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 9:05 AM, Nick Alexander <nalex...@mozilla.com>
wrote:

> On 2014-06-02, 4:59 AM, Robert O'Callahan wrote:
>
>> On Mon, Jun 2, 2014 at 3:19 PM, Rik Cabanier <caba...@gmail.com> wrote:
>>
>> isIdentity() indeed suffers from rounding errors but since it's useful,
>>> I'm
>>> hesitant to remove it.
>>> In our rendering libraries at Adobe, we check if a matrix is *almost*
>>> identity. Maybe we can do the same here?
>>>
>>>
>> One option would be to make "isIdentity" and "is2D" state bits in the
>> object rather than predicates on the matrix coefficients. Then for each
>> matrix operation, we would define how it affects the isIdentity and is2D
>> bits. For example we could say translate(tx, ty, tz)'s result isIdentity
>> if
>> and only if the source matrix isIdentity and tx, ty and tz are all exactly
>> 0.0, and the result is2D if and only if the source matrix is2D and tz is
>> exactly 0.0.
>>
>> With that approach, isIdentity and is2D would be much less sensitive to
>> precision issues. In particular they'd be independent of the precision
>> used
>> to compute and store store matrix elements, which would be helpful I
>> think.
>>
>
> I agree that most mathematical ways of determining a matrix (as a
> rotation, or a translation, etc) come with isIdentity for free; but are
> most matrices derived from some underlying transformation, or are they
> given as a list of coefficients?
>

You can do it either way. Here are the constructors:
http://dev.w3.org/fxtf/geometry/#dom-dommatrix-dommatrix

So you can do:

var m = new DOMMatrix(); // identity = true, 2d = true
var m = new DOMMatrix("translate(20 20) scale(4 4) skewX"); // identity =
depends, 2d = depends
var m = new DOMMatrix(otherdommatrix; // identity = inherited, 2d =
inherited
var m = new DOMMatrix([a b c d e f]); // identity = depends, 2d = true
var m = new DOMMatrix([m11 m12... m44]); // identity = depends, 2d = depends



> If the latter, the isIdentity flag needs to be determined by the
> constructor, or fed as a parameter. Exactly how does the constructor
> determine the parameter? Exactly how does the user?


The constructor would check the incoming parameters as defined:

http://dev.w3.org/fxtf/geometry/#dom-dommatrixreadonly-is2d
http://dev.w3.org/fxtf/geometry/#dom-dommatrixreadonly-isidentity

Nick Alexander

unread,
Jun 2, 2014, 1:56:35 PM6/2/14
to Rik Cabanier, dev-pl...@lists.mozilla.org
Thanks for providing these references. As an aside -- it worries me
that these are defined rather differently: is2d says "are equal to 0",
while isIdentity says "are '0'". Is this a syntactic or a semantic
difference?

But, to the point, the idea of "carrying around the isIdentity flag" is
looking bad, because we either have that A*A.inverse() will never have
isIdentity() == true; or we promote the idiom that to check for
identity, one always creates a new DOMMatrix, so that the constructor
determines isIdentity, and then we query it. This is no better than
just having isIdentity do the (badly-rounded) check.

Nick

Benoit Jacob

unread,
Jun 2, 2014, 2:06:38 PM6/2/14
to Nick Alexander, dev-pl...@lists.mozilla.org, Rik Cabanier
The way that propagating an "is identity" flag is better than determining
that from the matrix coefficients, is that it's predictable. People are
going to have matrices that are the result of various arithmetic
operations, that are close to identity but most of the time not exactly
identity. On these matrices, I would like isIdentity() to consistently
return false, instead of returning false 99.99% of the time and then
suddenly accidentally returning true when a little miracle happens and a
matrix happens to be exactly identity.

Benoit



>
> Nick

Rik Cabanier

unread,
Jun 2, 2014, 2:06:58 PM6/2/14
to Nick Alexander, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 10:56 AM, Nick Alexander <nalex...@mozilla.com>
wrote:
It looks like an oversight. I'll ask Dirk to update it.


> But, to the point, the idea of "carrying around the isIdentity flag" is
> looking bad, because we either have that A*A.inverse() will never have
> isIdentity() == true; or we promote the idiom that to check for identity,
> one always creates a new DOMMatrix, so that the constructor determines
> isIdentity, and then we query it. This is no better than just having
> isIdentity do the (badly-rounded) check.
>
> Nick
>

Benoit Jacob

unread,
Jun 2, 2014, 2:08:29 PM6/2/14
to Nick Alexander, dev-pl...@lists.mozilla.org, Rik Cabanier
2014-06-02 14:06 GMT-04:00 Benoit Jacob <jacob.b...@gmail.com>:

>
>
>
> 2014-06-02 13:56 GMT-04:00 Nick Alexander <nalex...@mozilla.com>:
>
>> But, to the point, the idea of "carrying around the isIdentity flag" is
>> looking bad, because we either have that A*A.inverse() will never have
>> isIdentity() == true; or we promote the idiom that to check for identity,
>> one always creates a new DOMMatrix, so that the constructor determines
>> isIdentity, and then we query it. This is no better than just having
>> isIdentity do the (badly-rounded) check.
>>
>
> The way that propagating an "is identity" flag is better than determining
> that from the matrix coefficients, is that it's predictable. People are
> going to have matrices that are the result of various arithmetic
> operations, that are close to identity but most of the time not exactly
> identity. On these matrices, I would like isIdentity() to consistently
> return false, instead of returning false 99.99% of the time and then
> suddenly accidentally returning true when a little miracle happens and a
> matrix happens to be exactly identity.
>

...but, to not lose sight of what I really want: I am still not convinced
that we should have a isIdentity() method at all, and by default I would
prefer no such method to exist. I was only saying the above _if_ we must
have a isIdentity method.

Benoit

Rik Cabanier

unread,
Jun 2, 2014, 5:13:52 PM6/2/14
to Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 11:08 AM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

>
>
>
Scanning through the mozilla codebase, IsIdentity is used to make decisions
if objects were transformed. This seems to match how we use Identity()
internally.
Since this seems useful for native applications, there's no reason why this
wouldn't be the case for the web platform (aka blink's "rational web
platform principle"). If for some reason the author *really* wants to know
if the matrix is identity, he can calculate it manually.

I would be fine with keeping this as an internal flag and defining this
behavior normative.

Robert O'Callahan

unread,
Jun 2, 2014, 6:02:54 PM6/2/14
to Martin Thomson, Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier
On Tue, Jun 3, 2014 at 4:24 AM, Martin Thomson <m...@mozilla.com> wrote:

> > it conveys that this is a 2d matrix and that you can ignore the 3d
> components.
>
> Maybe you misunderstood what I was implying. You are describing an
> intended application of the matrix to 2d or 3d graphics. The problem is
> that the is2D() method is applicable to what appears to be a generic
> object. That object has a name “DOMMatrix” which implies a general
> capability that isn’t present.
>
> However, when someone says matrix [1], I think matrix. My understanding
> of matrices extends beyond 4x4 and 2x3. It’s understandable perhaps that
> the matrix object is 2-dimensional only, because that is highly useful for
> the application you have in mind, and a lot more besides.


The DOM prefix is present because we don't want to squat on "Matrix" and
various different DOM APIs need this object. The most general thing those
APIs need is a matrix representation of 3D projective transforms, so that's
what DOMMatrix currently provides. I find it hard to imagine needing to go
beyond that; I cannot forsee Web APIs needing to interface with a general
linear algebra package. If they do, extending DOMMatrix and creating an
entirely new type (GeneralMatrix?) are both viable options. And keep in
mind that in Web development the name of an interface type rarely shows up
in application code (generally just constructors and instanceof).

Benoit Jacob

unread,
Jun 2, 2014, 6:03:12 PM6/2/14
to Rik Cabanier, Nick Alexander, dev-pl...@lists.mozilla.org
Gecko's existing code really isn't authoritative on matrix design issues!!
Please don't use it as an argument either way in this discussion --- just
because it uses isIdentity() doesn't imply even that isIdentity is actually
useful to it. It could just be shooting itself in the feet.

(not to pick on any code in particular --- I haven't looked. Just
generically saying I've seen more bad code than good code in this
department).

Benoit

Rik Cabanier

unread,
Jun 2, 2014, 6:16:05 PM6/2/14
to Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 3:03 PM, Benoit Jacob <jacob.b...@gmail.com>
Sure. My argument was that if this is useful for applications and they can
use it successfully, why not expose it to the web platform?
I looked at the WebKit and Blink codebases and they also use this API a
lot.

Robert O'Callahan

unread,
Jun 2, 2014, 10:07:36 PM6/2/14
to Rik Cabanier, Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org
Off the top of my head, the places in Gecko I know of that use isIdentity
or is2D fall into two categories:
1) math performance optimizations
2) (is2D only) we're going to take an implementation approach that only
works for 2D affine transforms, and either a) there is no support for 3D
perspective transforms at all, or b) that support is implemented very
differently (e.g. transforming Bezier control points vs rendering to a
bitmap and applying 3D transform to that).

For category #1 we can perhaps avoid having Web developers call
isIdentity/is2D, by optimizing internally. We simply haven't bothered to do
those optimizations in Gecko matrix classes, we let the callers do it (but
perhaps we should reconsider that).
For category #2, I can't see a way around exposing is2D to the Web in some
form.

Rik Cabanier

unread,
Jun 2, 2014, 11:28:19 PM6/2/14
to Robert O'Callahan, Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 7:07 PM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

> Off the top of my head, the places in Gecko I know of that use isIdentity
> or is2D fall into two categories:
> 1) math performance optimizations
> 2) (is2D only) we're going to take an implementation approach that only
> works for 2D affine transforms, and either a) there is no support for 3D
> perspective transforms at all, or b) that support is implemented very
> differently (e.g. transforming Bezier control points vs rendering to a
> bitmap and applying 3D transform to that).
>
> For category #1 we can perhaps avoid having Web developers call
> isIdentity/is2D, by optimizing internally. We simply haven't bothered to do
> those optimizations in Gecko matrix classes, we let the callers do it (but
> perhaps we should reconsider that).
>

Yes, isIdentity is used as an indication that nothing needs to be done or
that the transform hasn't changed.
Maybe we should rename it to isDefault, isInitial or isNoOp?

Robert O'Callahan

unread,
Jun 2, 2014, 11:32:50 PM6/2/14
to Rik Cabanier, Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org
On Tue, Jun 3, 2014 at 3:28 PM, Rik Cabanier <caba...@gmail.com> wrote:

> Yes, isIdentity is used as an indication that nothing needs to be done or
> that the transform hasn't changed.
> Maybe we should rename it to isDefault, isInitial or isNoOp?
>

I think isIdentity is the right name.

Glancing through Gecko I see places where we're able to entirely skip
possibly-expensive transformation steps if we have an identity matrix, so I
guess isIdentity is useful to have since even if we make
multiplication-by-identity free, checking isIdentity might mean you can
completely avoid traversing some application data structure.

Rik Cabanier

unread,
Jun 2, 2014, 11:45:59 PM6/2/14
to Robert O'Callahan, Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org
To recap I think the following points have been resolved:
- remove determinant (unless someone comes up with a strong use case)
- change is2D() so it's a flag instead of calculated on the fly
- change isIdentity() so it's a flag.
- update constructors so they set/copy the flags appropriately

Still up for discussion:
- rename isIdentity
- come up with better way for the in-place transformations as opposed to
"by"
- is premultiply needed?

K. Gadd

unread,
Jun 2, 2014, 11:45:54 PM6/2/14
to Robert O'Callahan, Benoit Jacob, dev-pl...@lists.mozilla.org, Nick Alexander, Rik Cabanier
Minor spec suggestion: This looks like a great primitive, but having
to create GC pressure to multiply values by the matrix seems like a
real mistake. transformPoint should have an overload that accepts a
Float64Array and mutates it in-place, or maybe a 'in, out' pair of
arrays. Probably also accept offsets into each array so that you can
use it to transform a series of points by the matrix (a fairly common
graphics/geometry operation).

Rik Cabanier

unread,
Jun 2, 2014, 11:49:46 PM6/2/14
to Robert O'Callahan, Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org
On Mon, Jun 2, 2014 at 8:32 PM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

> On Tue, Jun 3, 2014 at 3:28 PM, Rik Cabanier <caba...@gmail.com> wrote:
>
>> Yes, isIdentity is used as an indication that nothing needs to be done or
>> that the transform hasn't changed.
>> Maybe we should rename it to isDefault, isInitial or isNoOp?
>>
>
> I think isIdentity is the right name.
>
> Glancing through Gecko I see places where we're able to entirely skip
> possibly-expensive transformation steps if we have an identity matrix, so I
> guess isIdentity is useful to have since even if we make
> multiplication-by-identity free, checking isIdentity might mean you can
> completely avoid traversing some application data structure.
>

Yes, that's what I'm seeing in WebKit and Blink as well.
For instance:
const AffineTransform transform = context->getCTM();
if (m_shadowsIgnoreTransforms && !transform.isIdentity()) {
FloatQuad transformedPolygon =
transform.mapQuad(FloatQuad(shadowedRect));
transformedPolygon.move(m_offset);
layerRect =
transform.inverse().mapQuad(transformedPolygon).boundingBox();
} else {
layerRect = shadowedRect;
layerRect.move(m_offset);
}


and:
if (!currentTransform.isIdentity()) {
FloatPoint3D absoluteAnchorPoint(anchorPoint());
absoluteAnchorPoint.scale(size().width(), size().height(), 1);
transform.translate3d(absoluteAnchorPoint.x(),
absoluteAnchorPoint.y(), absoluteAnchorPoint.z());
transform.multiply(currentTransform);
transform.translate3d(-absoluteAnchorPoint.x(),
-absoluteAnchorPoint.y(), -absoluteAnchorPoint.z());
}

Dirk Schulze

unread,
Jun 3, 2014, 3:34:47 AM6/3/14
to Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier

On Jun 2, 2014, at 12:11 AM, Benoit Jacob <jacob.b...@gmail.com> wrote:

> Objection #6:
>
> The determinant() method, being in this API the only easy way to get
> something that looks roughly like a measure of invertibility, will probably
> be (mis-)used as a measure of invertibility. So I'm quite confident that it
> has a strong mis-use case. Does it have a strong good use case? Does it
> outweigh that? Note that if the intent is precisely to offer some kind of
> measure of invertibility, then that is yet another thing that would be best
> done with a singular values decomposition (along with solving, and with
> computing a polar decomposition, useful for interpolating matrices), by
> returning the ratio between the lowest and the highest singular value.

Looking at use cases, then determinant() is indeed often used for:

* Checking if a matrix is invertible.
* Part of actually inverting the matrix.
* Part of some decomposing algorithms as the one in CSS Transforms.

I should note that the determinant is the most common way to check for invertibility of a matrix and part of actually inverting the matrix. Even Cairo Graphics, Skia and Gecko’s representation of matrix3x3 do use the determinant for these operations.

Greetings,
Dirk

Neil

unread,
Jun 3, 2014, 5:35:44 AM6/3/14
to
Rik Cabanier wrote:

>Still up for discussion:
>- rename isIdentity
>
My understanding is that you want to use isIdentity/is2D as an
optimisation for known classes of matrix, and what you're really
interested in is if the matrix has had any 2D or 3D transforms applied
to it, even if those transforms should mathematically cancel each other
out. (Which is fair enough.) This leads me to think that you could call
the properties isTransformed and isTransformed3D. Presumably only new
DOMMatrix() and new DOMMatrix().multiply(new DOMMatrix()) (and other
similarly trivial constructs) will return a matrix where isTransformed
is false.

--
Warning: May contain traces of nuts.

Benoit Jacob

unread,
Jun 3, 2014, 9:06:53 AM6/3/14
to Dirk Schulze, dev-pl...@lists.mozilla.org, Rik Cabanier
I didn't say that determinant had no good use case. I said that it had more
bad use cases than it had good ones. If its only use case if checking
whether the cofactors formula will succeed in computing the inverse, then
make that part of the inversion API so you don't compute the determinant
twice.

Here is a good use case of determinant, except it's bad because it computes
the determinant twice:

if (matrix.determinant() != 0) { // once
result = matrix.inverse(); // twice
}

If that's the only thing we use the determinant for, then we're better
served by an API like this, allowing to query success status:

var matrixInversionResult = matrix.inverse(); // once
if (matrixInversionResult.invertible()) {
result = matrixInversionResult.inverse();
}

Typical bad uses of the determinant as "measures of invertibility"
typically occur in conjunction with people thinking they do the right thing
with "fuzzy compares", like this typical bad pattern:

if (matrix.determinant() < 1e-6) {
return error;
}
result = matrix.inverse();

Multiple things are wrong here:

1. First, as mentioned above, the determinant is being computed twice here.

2. Second, floating-point scale invariance is broken: floating point
computations should generally work for all values across the whole exponent
range, which for doubles goes from 1e-300 to 1e+300 roughly. Take the
matrix that's 0.01*identity, and suppose we're dealing with 4x4 matrices.
The determinant of that matrix is 1e-8, so that matrix is incorrectly
treated as non-invertible here.

3. Third, if the primary use for the determinant is invertibility and
inversion is implemented by cofactors (as it would be for 4x4 matrices)
then in that case only an exact comparison of the determinant to 0 is
relevant. That's a case where no fuzzy comparison is meaningful. If one
wanted to guard against cancellation-induced imprecision, one would have to
look at cofactors themselves, not just at the determinant.

In full generality, the determinant is just the volume of the unit cube
under the matrix transformation. It is exactly zero if and only if the
matrix is singular. That doesn't by itself give any interpretation of other
nonzero values of the determinant, not even "very small" ones.

For special classes of matrices, things are different. Some classes of
matrices have a specific determinant, for example rotations have
determinant one, which can be used to do useful things. So in a
sufficiently advanced or specialized matrix API, the determinant is useful
to expose. DOMMatrix is special in that it is not advanced and not
specialized.

Benoit


> Greetings,
> Dirk

Benoit Jacob

unread,
Jun 3, 2014, 9:13:30 AM6/3/14
to Rik Cabanier, Nick Alexander, dev-pl...@lists.mozilla.org, Robert O'Callahan
2014-06-02 23:45 GMT-04:00 Rik Cabanier <caba...@gmail.com>:

> To recap I think the following points have been resolved:
> - remove determinant (unless someone comes up with a strong use case)
> - change is2D() so it's a flag instead of calculated on the fly
> - change isIdentity() so it's a flag.
> - update constructors so they set/copy the flags appropriately
>
> Still up for discussion:
> - rename isIdentity
> - come up with better way for the in-place transformations as opposed to
> "by"
> - is premultiply needed?
>
>

This list misses some of the points that I care more about:
- Should DOMMatrix really try to be both 3D projective transformations and
2D affine transformations or should that be split into separate classes?
- Should we really take SVG's matrix and other existing bad matrix APIs
and bless them and engrave them in the marble of The New HTML5 That Is Good
By Definition?

Benoit

Rik Cabanier

unread,
Jun 3, 2014, 1:21:50 PM6/3/14
to Benoit Jacob, Nick Alexander, dev-pl...@lists.mozilla.org, Robert O'Callahan
On Tue, Jun 3, 2014 at 6:13 AM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

>
>
>
> 2014-06-02 23:45 GMT-04:00 Rik Cabanier <caba...@gmail.com>:
>
> To recap I think the following points have been resolved:
>> - remove determinant (unless someone comes up with a strong use case)
>> - change is2D() so it's a flag instead of calculated on the fly
>> - change isIdentity() so it's a flag.
>> - update constructors so they set/copy the flags appropriately
>>
>> Still up for discussion:
>> - rename isIdentity
>> - come up with better way for the in-place transformations as opposed to
>> "by"
>> - is premultiply needed?
>>
>>
>
> This list misses some of the points that I care more about:
> - Should DOMMatrix really try to be both 3D projective transformations
> and 2D affine transformations or should that be split into separate classes?
>

Yes, DOMMatrix reflects the transform of DOM elements so it should contain
both.
I think the underlying implementation should move to use a 2d or 3d matrix
so it avoids the pitfalls you mentioned.


> - Should we really take SVG's matrix and other existing bad matrix APIs
> and bless them and engrave them in the marble of The New HTML5 That Is Good
> By Definition?
>

The platform is not helped by having multiple objects doing the same thing.
We *could* support but deprecate the old API if people feel that having
better names is worth the effort.

Rik Cabanier

unread,
Jun 3, 2014, 1:23:06 PM6/3/14
to Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Tue, Jun 3, 2014 at 6:06 AM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

>
>
>
> 2014-06-03 3:34 GMT-04:00 Dirk Schulze <dsch...@adobe.com>:
>
>
>> On Jun 2, 2014, at 12:11 AM, Benoit Jacob <jacob.b...@gmail.com>
I agree with your points. Let's drop determinant for now.
If authors start to demand it, we can add it back in later.

Benoit Jacob

unread,
Jun 3, 2014, 3:52:42 PM6/3/14
to Rik Cabanier, Ehsan Akhgari, Dirk Schulze, dev-pl...@lists.mozilla.org
I also think that now that determinant() is being removed, is a good time
to revisit my Objection #4 which I don't think has been addressed at all:
please remove inverse() too.

Indeed, without its companion determinant() method, the inverse() method is
now standing out as by far the most advanced and footgun-ish feature in
this API, and the concerns that I expressed about it in Objection #4
earlier in this thread still stand.

With inverse() removed, the feature set would look more consistent as it
would then purely be about creating and composing (multiplying)
transformations.

Benoit

K. Gadd

unread,
Jun 3, 2014, 4:00:01 PM6/3/14
to Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org, Ehsan Akhgari, Rik Cabanier
Inverses get used *a lot*. I would argue that they are only 'advanced'
in that there are many lines of code in an implementation - they are a
common operation when setting up transforms or working with
transforms. For example, reverse-projecting from an onscreen point
into a point on the surface of a transformed object. If you drop them
from this matrix object, users of the matrix object will just end up
implementing determinants themselves.

I will agree that the m.inverse().transformPoint() pattern is
inefficient, but in any scenario where many points are being
transformed, can't the user do the inverse once and then transform all
the points by it? Maybe I'm misunderstanding and you are talking about
non-rendering scenarios.

Rik Cabanier

unread,
Jun 3, 2014, 4:10:39 PM6/3/14
to Benoit Jacob, Dirk Schulze, Ehsan Akhgari, dev-pl...@lists.mozilla.org
On Tue, Jun 3, 2014 at 12:52 PM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

> I also think that now that determinant() is being removed, is a good time
> to revisit my Objection #4 which I don't think has been addressed at all:
> please remove inverse() too.
>
> Indeed, without its companion determinant() method, the inverse() method
> is now standing out as by far the most advanced and footgun-ish feature in
> this API, and the concerns that I expressed about it in Objection #4
> earlier in this thread still stand.
>
> With inverse() removed, the feature set would look more consistent as it
> would then purely be about creating and composing (multiplying)
> transformations.
>

inverse() is one of the methods from SVGMatrix so it can't be removed.
In addition, it's a matrix method that is used quite often (and not just to
transform points) in the real world.

We could remove invert() or make the name less confusing.

Rik Cabanier

unread,
Jun 3, 2014, 4:20:57 PM6/3/14
to Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
This seems to be the main use case for Determinant(). Any objections if we
add isInvertible to DOMMatrixReadOnly?
> Benoit
>
>
>> Greetings,
>> Dirk
>
>
>

Benoit Jacob

unread,
Jun 3, 2014, 5:34:28 PM6/3/14
to Rik Cabanier, Dirk Schulze, dev-pl...@lists.mozilla.org
Can you give an example of how this API would be used and how it would
*not* force the implementation to compute the determinant twice if people
call isInvertible() and then inverse() ?

Benoit

Benoit Jacob

unread,
Jun 3, 2014, 5:40:55 PM6/3/14
to Rik Cabanier, Dirk Schulze, dev-pl...@lists.mozilla.org
Actually, inverse() is already spec'd to throw if the inversion fails. In
that case (assuming we keep it that way) there is no need at all for any
isInvertible kind of method. Note that in floating-point arithmetic there
is no absolute notion of invertibility; there just are different matrix
inversion algorithms each failing on different matrices, so "invertibility"
only makes sense with respect to one inversion algorithm, so it is actually
better to keep the current exception-throwing API than to introduce a
separate isInvertible getter.

Benoit

Rik Cabanier

unread,
Jun 3, 2014, 6:21:17 PM6/3/14
to Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Tue, Jun 3, 2014 at 2:34 PM, Benoit Jacob <jacob.b...@gmail.com>
I can not.
Calculating the determinant is fast though. I bet crossing the DOM boundary
is more expensive.

Robert O'Callahan

unread,
Jun 3, 2014, 6:23:12 PM6/3/14
to Benoit Jacob, dev-pl...@lists.mozilla.org, Nick Alexander, Rik Cabanier
On Wed, Jun 4, 2014 at 1:13 AM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

> This list misses some of the points that I care more about:
> - Should DOMMatrix really try to be both 3D projective transformations
> and 2D affine transformations or should that be split into separate classes?
>

I raised this issue too a while ago, but now I think a single interface is
better. It makes it easier to write code that will "just work" for both 2D
and 3D cases. Since 3D is pretty common, it simplifies things for authors
to only have one interface instead of two. Sure, we could have two
interfaces that are consistent, but then we'd need a way to upgrade a 2D
matrix to 3D and/or have some methods on the 3D matrix overloaded to take
2D matrix parameters. With a reliable is2D method, and internal
optimizations to special-case 2D vs 3D, I think we'll be in a good place.
The only real advantage of a separate 2D interface is that WebIDL could
express the constraint that a matrix is 2D, but I suspect that's not very
important.

Rik Cabanier

unread,
Jun 3, 2014, 6:26:28 PM6/3/14
to Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Tue, Jun 3, 2014 at 2:40 PM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

>
>
>
> 2014-06-03 17:34 GMT-04:00 Benoit Jacob <jacob.b...@gmail.com>:
>
>
>>
>>
>> 2014-06-03 16:20 GMT-04:00 Rik Cabanier <caba...@gmail.com>:
>>
>>
>>>
>>>
>>> On Tue, Jun 3, 2014 at 6:06 AM, Benoit Jacob <jacob.b...@gmail.com>
>>> wrote:
>>>
>>>>
>>>>
>>>>
>>>> 2014-06-03 3:34 GMT-04:00 Dirk Schulze <dsch...@adobe.com>:
>>>>
>>>>
>>>>> On Jun 2, 2014, at 12:11 AM, Benoit Jacob <jacob.b...@gmail.com>
> Actually, inverse() is already spec'd to throw if the inversion fails. In
> that case (assuming we keep it that way) there is no need at all for any
> isInvertible kind of method. Note that in floating-point arithmetic there
> is no absolute notion of invertibility; there just are different matrix
> inversion algorithms each failing on different matrices, so "invertibility"
> only makes sense with respect to one inversion algorithm, so it is actually
> better to keep the current exception-throwing API than to introduce a
> separate isInvertible getter.
>

That would require try/catch around all the "invert()" calls. This is ugly
but more importantly, it will significantly slow down javascript execution.
I'd prefer that we don't throw at all but we have to because SVGMatrix did.

Robert O'Callahan

unread,
Jun 3, 2014, 6:28:26 PM6/3/14
to Benoit Jacob, dev-pl...@lists.mozilla.org, Nick Alexander, Rik Cabanier
On Wed, Jun 4, 2014 at 10:23 AM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

> On Wed, Jun 4, 2014 at 1:13 AM, Benoit Jacob <jacob.b...@gmail.com>
> wrote:
>
>> This list misses some of the points that I care more about:
>> - Should DOMMatrix really try to be both 3D projective transformations
>> and 2D affine transformations or should that be split into separate classes?
>>
>
> I raised this issue too a while ago, but now I think a single interface is
> better. It makes it easier to write code that will "just work" for both 2D
> and 3D cases. Since 3D is pretty common, it simplifies things for authors
> to only have one interface instead of two. Sure, we could have two
> interfaces that are consistent, but then we'd need a way to upgrade a 2D
> matrix to 3D and/or have some methods on the 3D matrix overloaded to take
> 2D matrix parameters. With a reliable is2D method, and internal
> optimizations to special-case 2D vs 3D, I think we'll be in a good place.
> The only real advantage of a separate 2D interface is that WebIDL could
> express the constraint that a matrix is 2D, but I suspect that's not very
> important.
>

Actually, it might be possible to have separate DOM2DMatrix and DOMMatrix
interfaces that offer identical API and use WebIDL tricks to return the
right type of matrix. For example to have DOM2DMatrix.translate overloaded
so the 2-param version returns a DOM2DMatrix and the 3-param version
returns a DOM3DMatrix. With enough effort we might be able to get rid of
is2D and have the 2D state fully encoded in the WebIDL type. However, it
would get complicated, especially because we'd need DOM2DMatrixReadOnly and
DOMMatrixReadOnly types too. I think I prefer the simpler approach with
fewer interfaces.

Benoit Jacob

unread,
Jun 3, 2014, 6:28:51 PM6/3/14
to Rik Cabanier, Dirk Schulze, dev-pl...@lists.mozilla.org
2014-06-03 18:26 GMT-04:00 Rik Cabanier <caba...@gmail.com>:

>
>
>
> On Tue, Jun 3, 2014 at 2:40 PM, Benoit Jacob <jacob.b...@gmail.com>
> wrote:
>
>>
>>
>>
>> 2014-06-03 17:34 GMT-04:00 Benoit Jacob <jacob.b...@gmail.com>:
>>
>>
>>>
>>>
>>> 2014-06-03 16:20 GMT-04:00 Rik Cabanier <caba...@gmail.com>:
>>>
>>>
>>>>
>>>>
>>>> On Tue, Jun 3, 2014 at 6:06 AM, Benoit Jacob <jacob.b...@gmail.com>
>>>> wrote:
>>>>
>>>>>
>>>>>
>>>>>
>>>>> 2014-06-03 3:34 GMT-04:00 Dirk Schulze <dsch...@adobe.com>:
>>>>>
>>>>>
>>>>>> On Jun 2, 2014, at 12:11 AM, Benoit Jacob <jacob.b...@gmail.com>
So, if we have to have inverse() throw, do you agree that this removes the
need for any isInvertible() kind of method? For the reason I explained
above (invertibility is relative to a particular inversion algorithm) I
would rather have inversion and invertibility-checking be provided by a
single function. If we do have the option of not throwing, then that could
be a single function returning both the inverse and a boolean.

Benoit

Robert O'Callahan

unread,
Jun 3, 2014, 6:29:50 PM6/3/14
to Rik Cabanier, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Wed, Jun 4, 2014 at 10:26 AM, Rik Cabanier <caba...@gmail.com> wrote:

> That would require try/catch around all the "invert()" calls. This is ugly
> but more importantly, it will significantly slow down javascript execution.
> I'd prefer that we don't throw at all but we have to because SVGMatrix did.
>

Are you sure that returning a special value (e.g. all NaNs) would not fix
more code than it would break?

I think returning all NaNs instead of throwing would be much better
behavior.

Benoit Jacob

unread,
Jun 3, 2014, 6:35:04 PM6/3/14
to Robert O'Callahan, Dirk Schulze, dev-pl...@lists.mozilla.org, Rik Cabanier
2014-06-03 18:29 GMT-04:00 Robert O'Callahan <rob...@ocallahan.org>:

> On Wed, Jun 4, 2014 at 10:26 AM, Rik Cabanier <caba...@gmail.com> wrote:
>
>> That would require try/catch around all the "invert()" calls. This is ugly
>> but more importantly, it will significantly slow down javascript
>> execution.
>> I'd prefer that we don't throw at all but we have to because SVGMatrix
>> did.
>>
>
> Are you sure that returning a special value (e.g. all NaNs) would not fix
> more code than it would break?
>
> I think returning all NaNs instead of throwing would be much better
> behavior.
>

FWIW, I totally agree! That is exaclty what NaN is there for, and floating
point would be a nightmare if division-by-zero threw.

To summarize, my order of preference is:

1. (my first choice) have no inverse() / invert() / isInvertible()
methods at all.

2. (second choice) have inverse() returning NaN on non-invertible
matrices and possibly somehow returning a second boolean return value (e.g.
an out-parameter or a structured return value) to indicate whether the
matrix was invertible. Do not have a separate isInvertible().

3. (worst case #1) keep inverse() throwing. Do not have a separate
isInvertible().

4. (worst case #2) offer isInvertible() method separate from inverse().

Benoit

Rik Cabanier

unread,
Jun 3, 2014, 6:42:46 PM6/3/14
to Robert O'Callahan, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Tue, Jun 3, 2014 at 3:29 PM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

> On Wed, Jun 4, 2014 at 10:26 AM, Rik Cabanier <caba...@gmail.com> wrote:
>
>> That would require try/catch around all the "invert()" calls. This is ugly
>> but more importantly, it will significantly slow down javascript
>> execution.
>> I'd prefer that we don't throw at all but we have to because SVGMatrix
>> did.
>>
>
> Are you sure that returning a special value (e.g. all NaNs) would not fix
> more code than it would break?
>

No, I'm not sure :-)
It is very likely that people are just calling invert and don't check for
the exception. Returning NaN might indeed make thing more stable.

I think returning all NaNs instead of throwing would be much better
> behavior.
>

I completely agree.
Going with Benoit's suggestion, we can change the idl for invert to:

bool invert();

and change inverse to return a matrix with NaN for all its elements.

Robert O'Callahan

unread,
Jun 3, 2014, 6:45:14 PM6/3/14
to Rik Cabanier, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Wed, Jun 4, 2014 at 10:42 AM, Rik Cabanier <caba...@gmail.com> wrote:

> Going with Benoit's suggestion, we can change the idl for invert to:
>
> bool invert();
>
> and change inverse to return a matrix with NaN for all its elements.
>

Make it so!

Till Schneidereit

unread,
Jun 3, 2014, 6:48:40 PM6/3/14
to Rik Cabanier, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Wed, Jun 4, 2014 at 12:26 AM, Rik Cabanier <caba...@gmail.com> wrote:

> > Actually, inverse() is already spec'd to throw if the inversion fails. In
> > that case (assuming we keep it that way) there is no need at all for any
> > isInvertible kind of method. Note that in floating-point arithmetic there
> > is no absolute notion of invertibility; there just are different matrix
> > inversion algorithms each failing on different matrices, so
> "invertibility"
> > only makes sense with respect to one inversion algorithm, so it is
> actually
> > better to keep the current exception-throwing API than to introduce a
> > separate isInvertible getter.
> >
>
> That would require try/catch around all the "invert()" calls. This is ugly
> but more importantly, it will significantly slow down javascript execution.
> I'd prefer that we don't throw at all but we have to because SVGMatrix did.
>

That isn't really true in modern engines. Just having a try/catch doesn't
meaningfully slow down code anymore. If an exception is actually thrown, a
(very) slow path is taken, but otherwise things are good.

(I can only say this with certainty about SpiderMonkey and V8, but would
assume that other engines behave similarly. And even if not, it doesn't
make sense to make decisions like this based on their current performance
characteristics.)

Rik Cabanier

unread,
Jun 3, 2014, 7:17:31 PM6/3/14
to Till Schneidereit, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
Interesting!
I wrote a small experiment: http://jsfiddle.net/G83mW/14/
Gecko is indeed impervious but Chrome, Safari and IE are not. V8 is between
4 and 6 times slower if there's a try/catch.

I agree that we shouldn't make decision on the current state. (FWIW I think
that exceptions should only be used for "exceptional" cases.)

Dirk Schulze

unread,
Jun 4, 2014, 3:21:51 AM6/4/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan

On Jun 4, 2014, at 12:42 AM, Rik Cabanier <caba...@gmail.com> wrote:

>
>
>
> On Tue, Jun 3, 2014 at 3:29 PM, Robert O'Callahan <rob...@ocallahan.org> wrote:
> On Wed, Jun 4, 2014 at 10:26 AM, Rik Cabanier <caba...@gmail.com> wrote:
> That would require try/catch around all the "invert()" calls. This is ugly
> but more importantly, it will significantly slow down javascript execution.
> I'd prefer that we don't throw at all but we have to because SVGMatrix did.
>
> Are you sure that returning a special value (e.g. all NaNs) would not fix more code than it would break?
>
> No, I'm not sure :-)
> It is very likely that people are just calling invert and don't check for the exception. Returning NaN might indeed make thing more stable.
>
> I think returning all NaNs instead of throwing would be much better behavior.
>
> I completely agree.
> Going with Benoit's suggestion, we can change the idl for invert to:
> bool invert();
> and change inverse to return a matrix with NaN for all its elements.

I don’t think that this is really getting the point. You seem to have the assumption that this is the most common pattern:

if (matrix.isInvertible())
matrix.invert();

It isn’t in browser engines and I don’t think it will be in web applications. The actual use case would be to stop complex computations and graphical drawing operations right away if the author knows that nothing will be drawn anyway.

function drawComplexStuff() {
if (matrix.isInvertible())
return; // Stop here before doing complex stuff.
… complex stuff...
}

There was an argument that:

if (matrix.isInvertible())
matrix.invert();

would force UAs to compute the determinant twice. Actually, UAs can be very smart about that. The determinant is a simple double. It can be stored and invalidated as needed internally. (If it even turns out to be an issue.)
I don't think that the argument about numerical stability counts either. If the determinant is not exactly 0, then the matrix is invertible. It doesn’t really matter if it is a result of numerical precision or not.

To get back to

bool invert()
DOMMatrix inverse()

invert() does a matrix inversion in place. So it is not particularly useful as a simple check for singularity.
inverse() currently throws an exception. If it doesn’t anymore, then authors need to know that they need to check the elements of DOMMatrix for NaN. On the other hand, relying on exception checking isn’t great either.
Both is making the live more difficult for authors.

So I am not arguing that inverse() must throw and I dot argue that invert() should return a boolean. Changing this is fine with me. I am arguing that isInvertible() makes a lot of sense. Why wouldn’t it on the web platform if it is useful in our engines? determinant() is a way to check for singularity. Having either determinant() or isInvertible() or both makes a lot of sense to me. determinant() will be used internally a lot anyway. Being smarter and store the result of determinant() should solve some of the concerns.

Greetings,
Dirk

Neil

unread,
Jun 4, 2014, 4:42:59 AM6/4/14
to
Dirk Schulze wrote:

>There was an argument that:
>
>if (matrix.isInvertible())
> matrix.invert();
>
>would force UAs to compute the determinant twice. Actually, UAs can be very smart about that. The determinant is a simple double. It can be stored and invalidated as needed internally. (If it even turns out to be an issue.)
>
Maybe not even invalidated, but just kept up-to-date (e.g. determinant
of product = product of determinants)?

Till Schneidereit

unread,
Jun 4, 2014, 9:20:14 AM6/4/14
to Rik Cabanier, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Wed, Jun 4, 2014 at 1:17 AM, Rik Cabanier <caba...@gmail.com> wrote:

>
>
>
> On Tue, Jun 3, 2014 at 3:48 PM, Till Schneidereit <
> ti...@tillschneidereit.net> wrote:
>
>> On Wed, Jun 4, 2014 at 12:26 AM, Rik Cabanier <caba...@gmail.com> wrote:
>>
>>> > Actually, inverse() is already spec'd to throw if the inversion fails.
>>> In
>>> > that case (assuming we keep it that way) there is no need at all for
>>> any
>>> > isInvertible kind of method. Note that in floating-point arithmetic
>>> there
>>> > is no absolute notion of invertibility; there just are different matrix
>>> > inversion algorithms each failing on different matrices, so
>>> "invertibility"
>>> > only makes sense with respect to one inversion algorithm, so it is
>>> actually
>>> > better to keep the current exception-throwing API than to introduce a
>>> > separate isInvertible getter.
>>> >
>>>
>>> That would require try/catch around all the "invert()" calls. This is
>>> ugly
>>> but more importantly, it will significantly slow down javascript
>>> execution.
>>> I'd prefer that we don't throw at all but we have to because SVGMatrix
>>> did.
>>>
>>
>> That isn't really true in modern engines. Just having a try/catch doesn't
>> meaningfully slow down code anymore. If an exception is actually thrown, a
>> (very) slow path is taken, but otherwise things are good.
>>
>> (I can only say this with certainty about SpiderMonkey and V8, but would
>> assume that other engines behave similarly. And even if not, it doesn't
>> make sense to make decisions like this based on their current performance
>> characteristics.)
>>
>
> Interesting!
> I wrote a small experiment: http://jsfiddle.net/G83mW/14/
> Gecko is indeed impervious but Chrome, Safari and IE are not. V8 is
> between 4 and 6 times slower if there's a try/catch.
>

Ah, I stand corrected on V8, then. I know that they have some optimizations
in place for try/catch, but they're apparently less effective than ours.
I'm sure it's only a matter of time until this stops causing slowdowns in
any engine.


>
> I agree that we shouldn't make decision on the current state. (FWIW I
> think that exceptions should only be used for "exceptional" cases.)
>

That's true, yes. Also, given that you all would rather not have exceptions
here for other reasons, this seems to all be moot anyway. :)

Milan Sreckovic

unread,
Jun 4, 2014, 5:20:08 PM6/4/14
to Rik Cabanier, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
In general, is “this is how it worked with SVGMatrix” one of the design principles?

I was hoping this would be the time matrix rotate() method goes to radians, like the canvas rotate, and unlike SVGMatrix version that takes degrees...

--
- Milan

On Jun 3, 2014, at 18:26 , Rik Cabanier <caba...@gmail.com> wrote:

>> ...

Cameron McCormack

unread,
Jun 4, 2014, 8:28:35 PM6/4/14
to Milan Sreckovic, Rik Cabanier, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On 05/06/14 07:20, Milan Sreckovic wrote:
> In general, is �this is how it worked with SVGMatrix� one of the
> design principles?
>
> I was hoping this would be the time matrix rotate() method goes to
> radians, like the canvas rotate, and unlike SVGMatrix version that
> takes degrees...

By the way, in the SVG Working Group we have been discussing (but
haven't decided yet) whether to perform a wholesale overhaul of the SVG DOM.

http://dev.w3.org/SVG/proposals/improving-svg-dom/

If we go through with that, then we could drop SVGMatrix and use
DOMMatrix (which wouldn't then need to be compatible with SVGMatrix) for
all the SVG DOM methods we wanted to retain that deal with matrices.
I'm hoping we'll resolve whether to go ahead with this at our next
meeting, in August.

Benoit Jacob

unread,
Jun 4, 2014, 8:47:34 PM6/4/14
to Cameron McCormack, Dirk Schulze, Milan Sreckovic, Rik Cabanier, dev-pl...@lists.mozilla.org
2014-06-04 20:28 GMT-04:00 Cameron McCormack <c...@mcc.id.au>:

> On 05/06/14 07:20, Milan Sreckovic wrote:
>
>> In general, is “this is how it worked with SVGMatrix” one of the
>> design principles?
>>
>> I was hoping this would be the time matrix rotate() method goes to
>> radians, like the canvas rotate, and unlike SVGMatrix version that
>> takes degrees...
>>
>
> By the way, in the SVG Working Group we have been discussing (but haven't
> decided yet) whether to perform a wholesale overhaul of the SVG DOM.
>
> http://dev.w3.org/SVG/proposals/improving-svg-dom/
>
> If we go through with that, then we could drop SVGMatrix and use DOMMatrix
> (which wouldn't then need to be compatible with SVGMatrix) for all the SVG
> DOM methods we wanted to retain that deal with matrices. I'm hoping we'll
> resolve whether to go ahead with this at our next meeting, in August.
>

Thanks, that's very interesting input in this thread, as the entire
conversation here has been based on the axiom that we have to keep
compatibility with SVGMatrix....

Benoit

Dirk Schulze

unread,
Jun 5, 2014, 12:43:58 AM6/5/14
to Cameron McCormack, Benoit Jacob, Milan Sreckovic, Rik Cabanier, dev-pl...@lists.mozilla.org

On Jun 5, 2014, at 2:28 AM, Cameron McCormack <c...@mcc.id.au> wrote:

> On 05/06/14 07:20, Milan Sreckovic wrote:
>> In general, is “this is how it worked with SVGMatrix” one of the
>> design principles?
>>
>> I was hoping this would be the time matrix rotate() method goes to
>> radians, like the canvas rotate, and unlike SVGMatrix version that
>> takes degrees...
>
> By the way, in the SVG Working Group we have been discussing (but haven't decided yet) whether to perform a wholesale overhaul of the SVG DOM.
>
> http://dev.w3.org/SVG/proposals/improving-svg-dom/
>
> If we go through with that, then we could drop SVGMatrix and use DOMMatrix (which wouldn't then need to be compatible with SVGMatrix) for all the SVG DOM methods we wanted to retain that deal with matrices. I'm hoping we'll resolve whether to go ahead with this at our next meeting, in August.

The SVG WG already decided that it will replace SVGMatrix with DOMMatrix in Sydney 2013. And the WG already decided that DOMMatrix has to be compatible to SVGMatrix since there is content relying on it. SVG2 already replaced all existence of SVGMatrix with DOMMatrix/DOMMatrixReadOnly.

Greetings,
Dirk

Dirk Schulze

unread,
Jun 5, 2014, 12:44:30 AM6/5/14
to Benoit Jacob, Cameron McCormack, Milan Sreckovic, Rik Cabanier, dev-pl...@lists.mozilla.org

On Jun 5, 2014, at 2:47 AM, Benoit Jacob <jacob.b...@gmail.com> wrote:

>
>
>
> 2014-06-04 20:28 GMT-04:00 Cameron McCormack <c...@mcc.id.au>:
> On 05/06/14 07:20, Milan Sreckovic wrote:
> In general, is “this is how it worked with SVGMatrix” one of the
> design principles?
>
> I was hoping this would be the time matrix rotate() method goes to
> radians, like the canvas rotate, and unlike SVGMatrix version that
> takes degrees...
>
> By the way, in the SVG Working Group we have been discussing (but haven't decided yet) whether to perform a wholesale overhaul of the SVG DOM.
>
> http://dev.w3.org/SVG/proposals/improving-svg-dom/
>
> If we go through with that, then we could drop SVGMatrix and use DOMMatrix (which wouldn't then need to be compatible with SVGMatrix) for all the SVG DOM methods we wanted to retain that deal with matrices. I'm hoping we'll resolve whether to go ahead with this at our next meeting, in August.
>
> Thanks, that's very interesting input in this thread, as the entire conversation here has been based on the axiom that we have to keep compatibility with SVGMatrix….

That is correct and still the case.

Greetings,
Dirk

>
> Benoit

Rik Cabanier

unread,
Jun 5, 2014, 2:42:19 AM6/5/14
to Benoit Jacob, Cameron McCormack, Milan Sreckovic, Dirk Schulze, dev-pl...@lists.mozilla.org
On Wed, Jun 4, 2014 at 5:47 PM, Benoit Jacob <jacob.b...@gmail.com>
> compatibility with SVGMatrix...
>

As Dirk says, we can't throw SVGMatrix away.
The rewrite of SVG is just a proposal from Cameron at the moment. Nobody
has signed off on its implementation and we don't know if other browsers
will buy into implementing a new interface while maintaining the old one.

Rik Cabanier

unread,
Jun 5, 2014, 2:48:30 AM6/5/14
to Milan Sreckovic, Benoit Jacob, Dirk Schulze, dev-pl...@lists.mozilla.org
On Wed, Jun 4, 2014 at 2:20 PM, Milan Sreckovic <msrec...@mozilla.com>
wrote:

> In general, is “this is how it worked with SVGMatrix” one of the design
> principles?
>
> I was hoping this would be the time matrix rotate() method goes to
> radians, like the canvas rotate, and unlike SVGMatrix version that takes
> degrees...
>

"degrees" is easier to understand for authors.
With the new DOMMatrix constructor, you can specify radians:

var m = new DOMMatrix('rotate(1.75rad)' ;

Not specifying the unit will make it default to degrees (like angles in SVG)

Benoit Jacob

unread,
Jun 5, 2014, 8:05:16 AM6/5/14
to Rik Cabanier, Dirk Schulze, Milan Sreckovic, dev-pl...@lists.mozilla.org
The situation isn't symmetric: radians are inherently simpler to implement
(thus slightly faster), basically because only in radians is it true that
sin(x) ~= x for small x.

I also doubt that degrees are simpler to understand, and if anything you
might just want to provide a simple name for the constant 2*pi:

var turn = Math.PI * 2;

Now, what is easier to understand:

rotate(turn / 5)

or

rotate(72)

?

Benoit

Rik Cabanier

unread,
Jun 5, 2014, 9:08:42 AM6/5/14
to Benoit Jacob, Dirk Schulze, Milan Sreckovic, dev-pl...@lists.mozilla.org
On Thu, Jun 5, 2014 at 5:05 AM, Benoit Jacob <jacob.b...@gmail.com>
wrote:

>
>
>
The numbers don't lie :-)
Just do a google search for "CSS transform rotate". I went over 20 pages of
results and they all used "deg".

Benoit Jacob

unread,
Jun 5, 2014, 10:08:39 AM6/5/14
to Rik Cabanier, Dirk Schulze, Milan Sreckovic, dev-pl...@lists.mozilla.org
The other problem is that outside of SVG, other parts of the platform that
are being proposed to use SVGMatrix were using radians. For example, the
Canvas 2D context uses radians

http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#dom-context-2d-rotate

Not to mention that JavaScript also uses radians, e.g. in Math.cos().

Benoit

Rik Cabanier

unread,
Jun 5, 2014, 10:23:24 AM6/5/14
to Benoit Jacob, Dirk Schulze, Milan Sreckovic, dev-pl...@lists.mozilla.org
On Thu, Jun 5, 2014 at 7:08 AM, Benoit Jacob <jacob.b...@gmail.com>
DOMMatrix is designed for interaction with CSS and SVG, both of which use
degrees predominantly.
It's a bit weird that Canvas 2D decided to use radians since it's not
consistent with the platform. Google "canvas rotate radians" to see all the
stackoverflow and blog post on how to use it with degrees.

Rik Cabanier

unread,
Jun 5, 2014, 4:51:52 PM6/5/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan
On Wed, Jun 4, 2014 at 12:21 AM, Dirk Schulze <dsch...@adobe.com> wrote:

>
> On Jun 4, 2014, at 12:42 AM, Rik Cabanier <caba...@gmail.com> wrote:
>
> >
> >
> >
> > On Tue, Jun 3, 2014 at 3:29 PM, Robert O'Callahan <rob...@ocallahan.org>
> wrote:
> > On Wed, Jun 4, 2014 at 10:26 AM, Rik Cabanier <caba...@gmail.com>
> wrote:
> > That would require try/catch around all the "invert()" calls. This is
> ugly
> > but more importantly, it will significantly slow down javascript
> execution.
> > I'd prefer that we don't throw at all but we have to because SVGMatrix
> did.
> >
> > Are you sure that returning a special value (e.g. all NaNs) would not
> fix more code than it would break?
> >
> > No, I'm not sure :-)
> > It is very likely that people are just calling invert and don't check
> for the exception. Returning NaN might indeed make thing more stable.
> >
> > I think returning all NaNs instead of throwing would be much better
> behavior.
> >
> > I completely agree.
> > Going with Benoit's suggestion, we can change the idl for invert to:
> > bool invert();
> > and change inverse to return a matrix with NaN for all its elements.
>
> I don’t think that this is really getting the point. You seem to have the
> assumption that this is the most common pattern:
>
> if (matrix.isInvertible())
> matrix.invert();
>
> It isn’t in browser engines and I don’t think it will be in web
> applications. The actual use case would be to stop complex computations and
> graphical drawing operations right away if the author knows that nothing
> will be drawn anyway.
>
> function drawComplexStuff() {
> if (matrix.isInvertible())
> return; // Stop here before doing complex stuff.
> … complex stuff...
> }
>

I think the argument is that you just do the complex logic regardless if
the matrix is invertible.
I did some sleuthing on github [1] on how people use 'inverse' and could
find very few places that actual check if a matrix is invertible. It seems
the vast majority don't catch the exception so the program crashes.

I only found 2 instances where invertibility is checked.
One is in Google's closure library [2] and the other is in another library.
I could not find any instances of people actually calling these methods.
mozilla's codebase doesn't seem to do anything special for non-invertible
matrices. WebKit does what you describe though (mainly in the canvas code)

Given this, let's stay with the decision to leave 'isInvertible()'
People can polyfill it and we can always add it later if needed.


> There was an argument that:
>
> if (matrix.isInvertible())
> matrix.invert();
>
> would force UAs to compute the determinant twice. Actually, UAs can be
> very smart about that. The determinant is a simple double. It can be stored
> and invalidated as needed internally. (If it even turns out to be an issue.)
> I don't think that the argument about numerical stability counts either.
> If the determinant is not exactly 0, then the matrix is invertible. It
> doesn’t really matter if it is a result of numerical precision or not.
>

Caching the determinant will be much slower because it will force us to add
an internal flag that will need to be checked every time you change the
matrix.
It would also make the DOMMatrix object bigger by the size of the flag and
a double.


> To get back to
>
> bool invert()
> DOMMatrix inverse()
>
> invert() does a matrix inversion in place. So it is not particularly
> useful as a simple check for singularity.
> inverse() currently throws an exception. If it doesn’t anymore, then
> authors need to know that they need to check the elements of DOMMatrix for
> NaN. On the other hand, relying on exception checking isn’t great either.
> Both is making the live more difficult for authors.
>
> So I am not arguing that inverse() must throw and I dot argue that
> invert() should return a boolean. Changing this is fine with me. I am
> arguing that isInvertible() makes a lot of sense. Why wouldn’t it on the
> web platform if it is useful in our engines? determinant() is a way to
> check for singularity. Having either determinant() or isInvertible() or
> both makes a lot of sense to me. determinant() will be used internally a
> lot anyway. Being smarter and store the result of determinant() should
> solve some of the concerns.
>

1:
https://github.com/search?l=JavaScript&p=1&q=svg+matrix+inverse&ref=advsearch&type=Code

2: https://github.com/google/closure-library

Rik Cabanier

unread,
Jun 5, 2014, 5:07:35 PM6/5/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan
It seems like we're getting to agreement. (Please tell me if I'm wrong
about this)
There are 2 things that I have questions about:
1. isIdentity()
We settled that this should mean that the matrix was never changed to a non
identity state.
This means that the following code:

var m = new DOMMatrix();

m.rotate(0);

m.isIdentity() == false; //!

Given this, I feel that maybe we should rename it to hasChanged or
isInitial,

2. xxxby
DOMMatrix contains a bunch of xxxby methods (ie translateBy, rotateBy) that
apply the transformation to the object itself.
Benoit was confused by it and I agree that the name is not ideal. Should we
rename it to "InPlace' ?

Thoughts?

Dirk Schulze

unread,
Jun 5, 2014, 5:14:13 PM6/5/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan

On Jun 5, 2014, at 11:07 PM, Rik Cabanier <caba...@gmail.com> wrote:

> It seems like we're getting to agreement. (Please tell me if I'm wrong about this)
> There are 2 things that I have questions about:
> 1. isIdentity()
> We settled that this should mean that the matrix was never changed to a non identity state.
> This means that the following code:
> var m = new DOMMatrix();
> m.rotate(0);
> m.isIdentity() == false; //!
> Given this, I feel that maybe we should rename it to hasChanged or isInitial,

How would that be useful for authors? hasChanged or isInital wouldn’t reveal any information. The idea of isIdentity is to know if the transformation matrix will have any effect. If we should not be able to check this then it should definitely not be named isIdentity but more over: it seems to be irrelevant.

>
> 2. xxxby
> DOMMatrix contains a bunch of xxxby methods (ie translateBy, rotateBy) that apply the transformation to the object itself.
> Benoit was confused by it and I agree that the name is not ideal. Should we rename it to "InPlace’ ?

It is less likely that authors are willing to write translateInPlace then translateBy IMO.

Greetings,
Dirk

>
> Thoughts?
>

Rik Cabanier

unread,
Jun 5, 2014, 5:52:13 PM6/5/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan
On Thu, Jun 5, 2014 at 2:14 PM, Dirk Schulze <dsch...@adobe.com> wrote:

>
> On Jun 5, 2014, at 11:07 PM, Rik Cabanier <caba...@gmail.com> wrote:
>
> > It seems like we're getting to agreement. (Please tell me if I'm wrong
> about this)
> > There are 2 things that I have questions about:
> > 1. isIdentity()
> > We settled that this should mean that the matrix was never changed to a
> non identity state.
> > This means that the following code:
> > var m = new DOMMatrix();
> > m.rotate(0);
> > m.isIdentity() == false; //!
> > Given this, I feel that maybe we should rename it to hasChanged or
> isInitial,
>
> How would that be useful for authors? hasChanged or isInital wouldn’t
> reveal any information.


It would. For instance:

var m = getMatrixFromCSSOM();

if(m.hasChanged())

....; // apply matrix



> The idea of isIdentity is to know if the transformation matrix will have
> any effect. If we should not be able to check this then it should
> definitely not be named isIdentity but more over: it seems to be irrelevant.


Benoit already went over this earlier in this thread:

The isIdentity() method has the same issue as was described about is2D()
above: as matrices get computed, they are going to jump unpredicably
between being exactly identity and not. People using isIdentity() to jump
between code paths are going to get unexpected jumps between code paths
i.e. typically performance cliffs, or worse if they start asserting that a
matrix should or should not be exactly identity. For that reason, I would
remove the isIdentity method.


>
> > 2. xxxby
> > DOMMatrix contains a bunch of xxxby methods (ie translateBy, rotateBy)
> that apply the transformation to the object itself.
> > Benoit was confused by it and I agree that the name is not ideal. Should
> we rename it to "InPlace’ ?
>
> It is less likely that authors are willing to write translateInPlace then
> translateBy IMO.
>

translateMe ?

Dirk Schulze

unread,
Jun 5, 2014, 5:57:59 PM6/5/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan

On Jun 5, 2014, at 11:52 PM, Rik Cabanier <caba...@gmail.com> wrote:

>
>
>
> On Thu, Jun 5, 2014 at 2:14 PM, Dirk Schulze <dsch...@adobe.com> wrote:
>
> On Jun 5, 2014, at 11:07 PM, Rik Cabanier <caba...@gmail.com> wrote:
>
> > It seems like we're getting to agreement. (Please tell me if I'm wrong about this)
> > There are 2 things that I have questions about:
> > 1. isIdentity()
> > We settled that this should mean that the matrix was never changed to a non identity state.
> > This means that the following code:
> > var m = new DOMMatrix();
> > m.rotate(0);
> > m.isIdentity() == false; //!
> > Given this, I feel that maybe we should rename it to hasChanged or isInitial,
>
> How would that be useful for authors? hasChanged or isInital wouldn’t reveal any information.
>
> It would. For instance:
> var m = getMatrixFromCSSOM();
> if(m.hasChanged())
> ....; // apply matrix

You just got the matrix, who would have changed it in the meantime? I suppose you would still want to check for identity? That is not reflected by the name though. Same for isInitial().

>
> The idea of isIdentity is to know if the transformation matrix will have any effect. If we should not be able to check this then it should definitely not be named isIdentity but more over: it seems to be irrelevant.
>
> Benoit already went over this earlier in this thread:
> The isIdentity() method has the same issue as was described about is2D() above: as matrices get computed, they are going to jump unpredicably between being exactly identity and not. People using isIdentity() to jump between code paths are going to get unexpected jumps between code paths i.e. typically performance cliffs, or worse if they start asserting that a matrix should or should not be exactly identity. For that reason, I would remove the isIdentity method.
>
> >
> > 2. xxxby
> > DOMMatrix contains a bunch of xxxby methods (ie translateBy, rotateBy) that apply the transformation to the object itself.
> > Benoit was confused by it and I agree that the name is not ideal. Should we rename it to "InPlace’ ?
>
> It is less likely that authors are willing to write translateInPlace then translateBy IMO.
>
> translateMe ?

:) would be short enough I guess. But doesn’t sound serious enough.

Dirk

Robert O'Callahan

unread,
Jun 5, 2014, 6:28:08 PM6/5/14
to Rik Cabanier, Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org
On Fri, Jun 6, 2014 at 9:07 AM, Rik Cabanier <caba...@gmail.com> wrote:

> There are 2 things that I have questions about:
> 1. isIdentity()
> We settled that this should mean that the matrix was never changed to a non
> identity state.
> This means that the following code:
>
> var m = new DOMMatrix();
>
> m.rotate(0);
>
> m.isIdentity() == false; //!
>
> Given this, I feel that maybe we should rename it to hasChanged or
> isInitial,
>

We can define "rotate(v)" to set isIdentity to false if v != 0.0 (and
similarly for other methods such as translate). Then, in your case,
isIdentity would still be true. That was my original intent.

Then there's this case:
var m = new DOMMatrix();
m.translate(-1,-1);
m.translate(1,1);
m.isIdentity() == false

I'm OK with that. Maybe we do need a better name though. Invert the meaning
and call it "maybeHasTransform()"?

Robert O'Callahan

unread,
Jun 5, 2014, 6:28:43 PM6/5/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier
On Fri, Jun 6, 2014 at 9:57 AM, Dirk Schulze <dsch...@adobe.com> wrote:

> :) would be short enough I guess. But doesn’t sound serious enough.
>

translateSelf?

Robert O'Callahan

unread,
Jun 5, 2014, 6:29:12 PM6/5/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier
On Fri, Jun 6, 2014 at 10:28 AM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

> On Fri, Jun 6, 2014 at 9:57 AM, Dirk Schulze <dsch...@adobe.com> wrote:
>
>> :) would be short enough I guess. But doesn’t sound serious enough.
>>
>
> translateSelf?
>

Or translateThis of course.

Rik Cabanier

unread,
Jun 5, 2014, 6:34:19 PM6/5/14
to Robert O'Callahan, Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org
On Thu, Jun 5, 2014 at 3:28 PM, Robert O'Callahan <rob...@ocallahan.org>
wrote:

> On Fri, Jun 6, 2014 at 9:07 AM, Rik Cabanier <caba...@gmail.com> wrote:
>
>> There are 2 things that I have questions about:
>> 1. isIdentity()
>> We settled that this should mean that the matrix was never changed to a
>> non
>> identity state.
>> This means that the following code:
>>
>> var m = new DOMMatrix();
>>
>> m.rotate(0);
>>
>> m.isIdentity() == false; //!
>>
>> Given this, I feel that maybe we should rename it to hasChanged or
>> isInitial,
>>
>
> We can define "rotate(v)" to set isIdentity to false if v != 0.0 (and
> similarly for other methods such as translate). Then, in your case,
> isIdentity would still be true. That was my original intent.
>

Works for me. This is how I implemented it in mozilla (except for the
rotate part which I will address next)


> Then there's this case:
> var m = new DOMMatrix();
> m.translate(-1,-1);
> m.translate(1,1);
> m.isIdentity() == false
>
> I'm OK with that. Maybe we do need a better name though. Invert the
> meaning and call it "maybeHasTransform()"?
>

That sounds good to me.

Matt Woodrow

unread,
Jun 5, 2014, 6:59:07 PM6/5/14
to Benoit Jacob, Rik Cabanier, Dirk Schulze, Milan Sreckovic, dev-pl...@lists.mozilla.org
On 6/06/14 12:05 am, Benoit Jacob wrote:
>
> The situation isn't symmetric: radians are inherently simpler to implement
> (thus slightly faster), basically because only in radians is it true that
> sin(x) ~= x for small x.
>
> I also doubt that degrees are simpler to understand, and if anything you
> might just want to provide a simple name for the constant 2*pi:
>
> var turn = Math.PI * 2;
>
> Now, what is easier to understand:
>
> rotate(turn / 5)
>
> or
>
> rotate(72)
>
> ?
>
>

I don't think this is a fair comparison, you used a fraction of a
constant for one and a raw number for the other.

Which is easier to understand:

var turn = 360;

rotate(turn / 5)

or

rotate(1.25663706143592)

?


I realize that radians make more sense mathematically, but for people
who haven't studied it I think degrees are the more 'natural' way of
thinking about angles/rotations. This is reflected in the number of
authors currently using degrees instead of radians for CSS transforms.

- Matt

Benoit Jacob

unread,
Jun 5, 2014, 7:05:07 PM6/5/14
to ma...@mozilla.com, Dirk Schulze, Milan Sreckovic, Rik Cabanier, dev-pl...@lists.mozilla.org
2014-06-05 18:59 GMT-04:00 Matt Woodrow <mwoo...@mozilla.com>:

> On 6/06/14 12:05 am, Benoit Jacob wrote:
>
>>
>> The situation isn't symmetric: radians are inherently simpler to implement
>> (thus slightly faster), basically because only in radians is it true that
>> sin(x) ~= x for small x.
>>
>> I also doubt that degrees are simpler to understand, and if anything you
>> might just want to provide a simple name for the constant 2*pi:
>>
>> var turn = Math.PI * 2;
>>
>> Now, what is easier to understand:
>>
>> rotate(turn / 5)
>>
>> or
>>
>> rotate(72)
>>
>> ?
>>
>>
>>
> I don't think this is a fair comparison, you used a fraction of a constant
> for one and a raw number for the other.
>
> Which is easier to understand:
>
> var turn = 360;
>
> rotate(turn / 5)
>
> or
>
> rotate(1.25663706143592)
>
> ?
>
>
I just meant that neither radians nor degrees are significantly easier than
the other, since in practice this is just changing the value for the "turn"
constant that people shouldn't be writing manually, i.e. even in degrees
people should IMHO write turn/4 instead of 90.

Benoit

Dirk Schulze

unread,
Jun 6, 2014, 12:22:37 AM6/6/14
to rob...@ocallahan.org, Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier

On Jun 6, 2014, at 12:28 AM, Robert O'Callahan <rob...@ocallahan.org> wrote:

> On Fri, Jun 6, 2014 at 9:57 AM, Dirk Schulze <dsch...@adobe.com> wrote:
> :) would be short enough I guess. But doesn’t sound serious enough.
>
> translateSelf?
>
> Rob
> --
> Jtehsauts tshaei dS,o n" Wohfy Mdaon yhoaus eanuttehrotraiitny eovni le atrhtohu gthot sf oirng iyvoeu rs ihnesa.r"t sS?o Whhei csha iids teoa stiheer :p atroa lsyazye,d 'mYaonu,r "sGients uapr,e tfaokreg iyvoeunr, 'm aotr atnod sgaoy ,h o'mGee.t" uTph eann dt hwea lmka'n? gBoutt uIp waanndt wyeonut thoo mken.o w

On Jun 6, 2014, at 12:28 AM, Robert O'Callahan <rob...@ocallahan.org> wrote:

> On Fri, Jun 6, 2014 at 9:57 AM, Dirk Schulze <dsch...@adobe.com> wrote:
> :) would be short enough I guess. But doesn’t sound serious enough.
>
> translateSelf?

On Jun 6, 2014, at 12:29 AM, Robert O'Callahan <rob...@ocallahan.org> wrote:

> On Fri, Jun 6, 2014 at 10:28 AM, Robert O'Callahan <rob...@ocallahan.org> wrote:
> On Fri, Jun 6, 2014 at 9:57 AM, Dirk Schulze <dsch...@adobe.com> wrote:
> :) would be short enough I guess. But doesn’t sound serious enough.
>
> translateSelf?
>
> Or translateThis of course.

Do you mean transform instead of translate? After all, the proposal seems to be that we check all functions if they modify the matrix or not?

Beside the name, there seems to be another open question. The default constructor

DOMMatrix();

is identity and we can flag it as that. What about

DOMMatrix(1,0,0,1,0,0) or
DOMMatrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)

Do we check the values and determine if the matrix is identity or not? If we do, then authors could write DOMMatrix(other.a, other.b, other.c, other.d, other.e, other.f) and check any kind of matrix after transforming for identity. In this case, a real isIdentity check wouldn’t be worst IMO.

Greetings,
Dirk

Robert O'Callahan

unread,
Jun 6, 2014, 12:27:20 AM6/6/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier
On Fri, Jun 6, 2014 at 4:22 PM, Dirk Schulze <dsch...@adobe.com> wrote:

> What about
>
> DOMMatrix(1,0,0,1,0,0) or
> DOMMatrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)
>
> Do we check the values and determine if the matrix is identity or not? If
> we do, then authors could write DOMMatrix(other.a, other.b, other.c,
> other.d, other.e, other.f) and check any kind of matrix after transforming
> for identity. In this case, a real isIdentity check wouldn’t be worst IMO.
>

I would lean towards just setting isIdentity to false for that case, but I
could go either way. If authors try really hard to shoot themselves in the
foot, they can.

Dirk Schulze

unread,
Jun 6, 2014, 12:40:29 AM6/6/14
to rob...@ocallahan.org, Benoit Jacob, dev-pl...@lists.mozilla.org, Rik Cabanier

On Jun 6, 2014, at 6:27 AM, Robert O'Callahan <rob...@ocallahan.org> wrote:

> On Fri, Jun 6, 2014 at 4:22 PM, Dirk Schulze <dsch...@adobe.com> wrote:
> What about
>
> DOMMatrix(1,0,0,1,0,0) or
> DOMMatrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)
>
> Do we check the values and determine if the matrix is identity or not? If we do, then authors could write DOMMatrix(other.a, other.b, other.c, other.d, other.e, other.f) and check any kind of matrix after transforming for identity. In this case, a real isIdentity check wouldn’t be worst IMO.
>
> I would lean towards just setting isIdentity to false for that case, but I could go either way. If authors try really hard to shoot themselves in the foot, they can.
>
> Rob

Just as comparison: Gecko checks for IsIdentity 75 times (exclusive the definitions in matrix and matrix4x4). Every time the values are simply checked for 0 and 1. Means Gecko is shooting itself in the foot quite often :P. (In WebKit it is about ~70 times as well.)

Greetings,
Dirk

Rik Cabanier

unread,
Jun 6, 2014, 12:52:28 AM6/6/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, rob...@ocallahan.org
On Thu, Jun 5, 2014 at 9:40 PM, Dirk Schulze <dsch...@adobe.com> wrote:

>
> On Jun 6, 2014, at 6:27 AM, Robert O'Callahan <rob...@ocallahan.org>
> wrote:
>
> > On Fri, Jun 6, 2014 at 4:22 PM, Dirk Schulze <dsch...@adobe.com> wrote:
> > What about
> >
> > DOMMatrix(1,0,0,1,0,0) or
> > DOMMatrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)
> >
> > Do we check the values and determine if the matrix is identity or not?
> If we do, then authors could write DOMMatrix(other.a, other.b, other.c,
> other.d, other.e, other.f) and check any kind of matrix after transforming
> for identity. In this case, a real isIdentity check wouldn’t be worst IMO.
> >
> > I would lean towards just setting isIdentity to false for that case, but
> I could go either way. If authors try really hard to shoot themselves in
> the foot, they can.
> >
> > Rob
>
> Just as comparison: Gecko checks for IsIdentity 75 times (exclusive the
> definitions in matrix and matrix4x4). Every time the values are simply
> checked for 0 and 1. Means Gecko is shooting itself in the foot quite often
> :P. (In WebKit it is about ~70 times as well.)


The question is not that 'isIdentity' is bad. Benoit's issue was that
checking for 'isIdentity' after doing transformations might cause jittery
results (ie switch to true or false depending on the conditions).
Quickle scanning mozilla's codebase, our current definition of 'isIdentity'
would return the correct result in all cases.

Dirk Schulze

unread,
Jun 6, 2014, 12:58:19 AM6/6/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org, rob...@ocallahan.org
Just take the first result of many:

static PathInterpolationResult
CanInterpolate(const SVGPathDataAndInfo& aStart,
const SVGPathDataAndInfo& aEnd)
{
if (aStart.IsIdentity()) {
return eCanInterpolate;
}


Where can you guarantee that you don’t see jittering? aStart could be modified.

Greetings,
Dirk

Rik Cabanier

unread,
Jun 6, 2014, 1:59:29 AM6/6/14
to Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, rob...@ocallahan.org
That one does not check for an identity matrix:

/**
* Returns true if this object is an "identity" value, from the
perspective
* of SMIL. In other words, returns true until the initial value set up in
* SVGPathSegListSMILType::Init() has been changed with a SetElement()
call.
*/
bool IsIdentity() const {
if (!mElement) {
NS_ABORT_IF_FALSE(IsEmpty(), "target element propagation failure");
return true;
}
return false;
}

Maybe you and I should take this offline...

Dirk Schulze

unread,
Jun 6, 2014, 2:18:43 AM6/6/14
to Rik Cabanier, Benoit Jacob, dev-pl...@lists.mozilla.org, rob...@ocallahan.org

On Jun 6, 2014, at 8:00 AM, "Rik Cabanier" <caba...@gmail.com<mailto:caba...@gmail.com>> wrote:




On Thu, Jun 5, 2014 at 9:58 PM, Dirk Schulze <dsch...@adobe.com<mailto:dsch...@adobe.com>> wrote:

On Jun 6, 2014, at 6:52 AM, Rik Cabanier <caba...@gmail.com<mailto:caba...@gmail.com>> wrote:

>
>
>
> On Thu, Jun 5, 2014 at 9:40 PM, Dirk Schulze <dsch...@adobe.com<mailto:dsch...@adobe.com>> wrote:
>
> On Jun 6, 2014, at 6:27 AM, Robert O'Callahan <rob...@ocallahan.org<mailto:rob...@ocallahan.org>> wrote:
>
> > On Fri, Jun 6, 2014 at 4:22 PM, Dirk Schulze <dsch...@adobe.com<mailto:dsch...@adobe.com>> wrote:
> > What about
> >
> > DOMMatrix(1,0,0,1,0,0) or
> > DOMMatrix(1,0,0,0,0,1,0,0,0,0,1,0,0,0,0,1)
> >
> > Do we check the values and determine if the matrix is identity or not? If we do, then authors could write DOMMatrix(other.a, other.b, other.c, other.d, other.e, other.f) and check any kind of matrix after transforming for identity. In this case, a real isIdentity check wouldn't be worst IMO.
> >
> > I would lean towards just setting isIdentity to false for that case, but I could go either way. If authors try really hard to shoot themselves in the foot, they can.
> >
> > Rob
>
> Just as comparison: Gecko checks for IsIdentity 75 times (exclusive the definitions in matrix and matrix4x4). Every time the values are simply checked for 0 and 1. Means Gecko is shooting itself in the foot quite often :P. (In WebKit it is about ~70 times as well.)
>
> The question is not that 'isIdentity' is bad. Benoit's issue was that checking for 'isIdentity' after doing transformations might cause jittery results (ie switch to true or false depending on the conditions).
> Quickle scanning mozilla's codebase, our current definition of 'isIdentity' would return the correct result in all cases.
>

Just take the first result of many:

static PathInterpolationResult
CanInterpolate(const SVGPathDataAndInfo& aStart,
const SVGPathDataAndInfo& aEnd)
{
if (aStart.IsIdentity()) {
return eCanInterpolate;
}
...

Where can you guarantee that you don't see jittering? aStart could be modified

That one does not check for an identity matrix:
/**
* Returns true if this object is an "identity" value, from the perspective
* of SMIL. In other words, returns true until the initial value set up in
* SVGPathSegListSMILType::Init() has been changed with a SetElement() call.
*/
bool IsIdentity() const {
if (!mElement) {
NS_ABORT_IF_FALSE(IsEmpty(), "target element propagation failure");
return true;
}
return false;
}

Right, as I noted on IRC I accidentally copied the wrong example. But there are still a lot of examples where the identity of a matrix is checked and used as a condition to perform or no to perform actions.


Maybe you and I should take this offline...

I think this is very much related to the discussion and demonstrates that real world applications are indeed using isIdentity() in the way you would like to deny for web application writers.

Greetings
Dirk

Milan Sreckovic

unread,
Jun 6, 2014, 11:57:33 AM6/6/14
to Rik Cabanier, Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan
On Jun 5, 2014, at 18:34 , Rik Cabanier <caba...@gmail.com> wrote:

> On Thu, Jun 5, 2014 at 3:28 PM, Robert O'Callahan <rob...@ocallahan.org>
> wrote:
>
>> On Fri, Jun 6, 2014 at 9:07 AM, Rik Cabanier <caba...@gmail.com> wrote:
>>
>>> ...
>
>
>> Then there's this case:
>> var m = new DOMMatrix();
>> m.translate(-1,-1);
>> m.translate(1,1);
>> m.isIdentity() == false
>>
>> I'm OK with that. Maybe we do need a better name though. Invert the
>> meaning and call it "maybeHasTransform()"?
>>
>
> That sounds good to me.

That just feels very wrong. I understand not having an isIdentity() method as Benoit proposes. The argument being “is identity question is more complicated than you think, so we won’t let you ask it, and instead you have to do it manually, which means you understand what’s going on”.

I don’t understand having isIdentity() method and having it return false when you actually have an identity transform. If it was “hasBeenModified()” or some such, I can understand having it behave that way.

I’d much rather have “isIdentityExactly()” or "isCloseToIdentity(float tolerance)” for a given definition of tolerance. Or not have it at all and write the JS utility myself.

--
- Milan

Rik Cabanier

unread,
Jun 6, 2014, 12:12:36 PM6/6/14
to Milan Sreckovic, Dirk Schulze, Benoit Jacob, dev-pl...@lists.mozilla.org, Robert O'Callahan
On Fri, Jun 6, 2014 at 8:57 AM, Milan Sreckovic <msrec...@mozilla.com>
wrote:

> On Jun 5, 2014, at 18:34 , Rik Cabanier <caba...@gmail.com> wrote:
>
> On Thu, Jun 5, 2014 at 3:28 PM, Robert O'Callahan <rob...@ocallahan.org>
> wrote:
>
> On Fri, Jun 6, 2014 at 9:07 AM, Rik Cabanier <caba...@gmail.com> wrote:
>
> ...
>
>
>
> Then there's this case:
> var m = new DOMMatrix();
> m.translate(-1,-1);
> m.translate(1,1);
> m.isIdentity() == false
>
> I'm OK with that. Maybe we do need a better name though. Invert the
> meaning and call it "maybeHasTransform()"?
>
>
> That sounds good to me.
>
>
> That just feels very wrong. I understand not having an isIdentity()
> method as Benoit proposes. The argument being “is identity question is
> more complicated than you think, so we won’t let you ask it, and instead
> you have to do it manually, which means you understand what’s going on”.
>
> I don’t understand having isIdentity() method and having it return false
> when you actually have an identity transform. If it was
> “hasBeenModified()” or some such, I can understand having it behave that
> way.
>

I could live with that name as well. The problem is what "modified" means.

var m = DOMMatrix(2,0,0,1,0,0) ;

m. hasBeenModified(); //?


I've been thinking more and I'm leaning back towards isIdentity.


> I’d much rather have “isIdentityExactly()” or "isCloseToIdentity(float
> tolerance)” for a given definition of tolerance. Or not have it at all and
> write the JS utility myself.
>

Yes, you can do this yourself. You should ask yourself though if you would
really need to do this... As Benoit said, this might cause inconsistent
behavior.
Moreover, non-identity matrices are very rare so you should ask yourself if
the fixed cost of always checking for true identity is worth it.

Dirk Schulze

unread,
Jun 6, 2014, 12:49:46 PM6/6/14
to Rik Cabanier, Benoit Jacob, Milan Sreckovic, dev-pl...@lists.mozilla.org, Robert O'Callahan

On Jun 6, 2014, at 6:12 PM, Rik Cabanier <caba...@gmail.com> wrote:

>
>
>
> On Fri, Jun 6, 2014 at 8:57 AM, Milan Sreckovic <msrec...@mozilla.com> wrote:
> On Jun 5, 2014, at 18:34 , Rik Cabanier <caba...@gmail.com> wrote:
>
>> On Thu, Jun 5, 2014 at 3:28 PM, Robert O'Callahan <rob...@ocallahan.org>
>> wrote:
>>
>>> On Fri, Jun 6, 2014 at 9:07 AM, Rik Cabanier <caba...@gmail.com> wrote:
>>>
>>>> ...
>>
>>
>>> Then there's this case:
>>> var m = new DOMMatrix();
>>> m.translate(-1,-1);
>>> m.translate(1,1);
>>> m.isIdentity() == false
>>>
>>> I'm OK with that. Maybe we do need a better name though. Invert the
>>> meaning and call it "maybeHasTransform()"?
>>>
>>
>> That sounds good to me.
>
> That just feels very wrong. I understand not having an isIdentity() method as Benoit proposes. The argument being “is identity question is more complicated than you think, so we won’t let you ask it, and instead you have to do it manually, which means you understand what’s going on”.
>
> I don’t understand having isIdentity() method and having it return false when you actually have an identity transform. If it was “hasBeenModified()” or some such, I can understand having it behave that way.
>
> I could live with that name as well. The problem is what "modified" means.
> var m = DOMMatrix(2,0,0,1,0,0) ;
> m. hasBeenModified(); //?

isInitialisedIdentity()
isInitialisedToIdentity()
isInitialisedAndIdentity()
initialisedWithIdentity()

All three above seem to assume that the boolean never changed.

transformedNotIdentity()
transformedOrNotIdentity()
isUnmodifiedIdentity()
notTransformedIdentity()
isModifiedNotIdentity()
unmodifiedIdentity()

Definitely not isIdentity(). This just leads to wrong assumptions. Also, if we do not add real isIdentity checks, authors will extend DOMMatrix. And then they should be able to use isIdentity.


>
> I've been thinking more and I'm leaning back towards isIdentity.
>
> I’d much rather have “isIdentityExactly()” or "isCloseToIdentity(float tolerance)” for a given definition of tolerance. Or not have it at all and write the JS utility myself.
>
> Yes, you can do this yourself. You should ask yourself though if you would really need to do this... As Benoit said, this might cause inconsistent behavior.
> Moreover, non-identity matrices are very rare so you should ask yourself if the fixed cost of always checking for true identity is worth it.

It is a good point that checking all 16 elements every time is costy. But that is exactly what authors would expect the UA to do.

I still don’t buy the argument with unexpected results though. We never can guarantee exact results. 1 divided by 3 doesn’t give exact results but at least interoperable results as long as platforms follow IEEE. This is not the case for trigonometric functions. It is not possible to guarantee that sin(Math.PI/3) is the same on all platforms since implementations vary across platforms. This of course affects DOMMatrix when one uses rotate. So none of the values can be guaranteed to be interoperable across all platforms. That means that isIdentity might not be guaranteed to give exact results either. And this usually is fine. If isIdentity does return false, well then the engine has to do a bit more work and can’t return earlier… That is what isIdentity is used for anyway. Make sure that engines don’t do unnecessary transformations.

It is good that DOMMatrix can be extended by users to add this basic functionality that all drawing engines and browser engines use under the hood already.

Greetings,
Dirk

Kip Gilbert

unread,
Jun 6, 2014, 3:18:08 PM6/6/14
to dev-pl...@lists.mozilla.org
Hello,

From a game programmer's perspective, isIdentity would normally be used
to cull out work. In these cases, it is expected that isIdentity will
return true only when the matrix is exactly equal to the identity
matrix. Due to the nature of floating point, the isIdentity will only
likely be true when it has been initialized or assigned identity
directly. This is what occurs in existing game / math libraries.

If we allow some amount of tolerance in the comparison, the issue is of
how much tolerance is right for a particular application. One
application may benefit from having small amount of variance as it may
be rotating items around a pivot that is close to their origins with
units that are screen space coordinates; however, another application
may use a pivot / origin that has a real-world relation to the objects
represented in a scene. The same amount of variance that would allow an
unnoticeable sub-pixel difference in the first case would result in an
object not appearing at all in the second case. IMHO, acceptable level
of tolerance is something that the platform should never dictate and
that users of the library would never expect. It is considered safe to
error on the side of returning false but never safe to return true when
the value is not exactly identity.

Another use case is physics calculation. The vast majority of simulated
objects will be at their resting position until they are hit by a
collider in which case their transform becomes non-identity. The moving
objects live for a short time until they "respawn" in which case their
transform is set back to the origin with the assignment of an identity
matrix. Expensive calculations such as IK (Inverse Kinematics) chains
are executed only on the objects that are not at rest and thus are
transformed by a matrix that is not identity.

tl;dr.. I would only see real-world benefit in a simple IsIdentity
function which returns true only when the matrix is exactly identity.

- Kip
> It is a good point that checking all 16 elements every time is costy. But that is exactly what authors would expect the UA to do.
>
> I still don�t buy the argument with unexpected results though. We never can guarantee exact results. 1 divided by 3 doesn�t give exact results but at least interoperable results as long as platforms follow IEEE. This is not the case for trigonometric functions. It is not possible to guarantee that sin(Math.PI/3) is the same on all platforms since implementations vary across platforms. This of course affects DOMMatrix when one uses rotate. So none of the values can be guaranteed to be interoperable across all platforms. That means that isIdentity might not be guaranteed to give exact results either. And this usually is fine. If isIdentity does return false, well then the engine has to do a bit more work and can�t return earlier� That is what isIdentity is used for anyway. Make sure that engines don�t do unnecessary transformations.
>
> It is good that DOMMatrix can be extended by users to add this basic functionality that all drawing engines and browser engines use under the hood already.
>
> Greetings,
> Dirk
>
> _______________________________________________
> dev-platform mailing list
> dev-pl...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-platform

Rik Cabanier

unread,
Jun 6, 2014, 4:23:50 PM6/6/14
to Kip Gilbert, dev-pl...@lists.mozilla.org
On Fri, Jun 6, 2014 at 12:18 PM, Kip Gilbert <kgil...@mozilla.com> wrote:

> Hello,
>
> From a game programmer's perspective, isIdentity would normally be used to
> cull out work. In these cases, it is expected that isIdentity will return
> true only when the matrix is exactly equal to the identity matrix. Due to
> the nature of floating point, the isIdentity will only likely be true when
> it has been initialized or assigned identity directly. This is what occurs
> in existing game / math libraries.
>

Yes, this is why storing it as an internal flag is the correct solution.


> If we allow some amount of tolerance in the comparison, the issue is of
> how much tolerance is right for a particular application. One application
> may benefit from having small amount of variance as it may be rotating
> items around a pivot that is close to their origins with units that are
> screen space coordinates; however, another application may use a pivot /
> origin that has a real-world relation to the objects represented in a
> scene. The same amount of variance that would allow an unnoticeable
> sub-pixel difference in the first case would result in an object not
> appearing at all in the second case. IMHO, acceptable level of tolerance
> is something that the platform should never dictate and that users of the
> library would never expect. It is considered safe to error on the side of
> returning false but never safe to return true when the value is not exactly
> identity.
>
> Another use case is physics calculation. The vast majority of simulated
> objects will be at their resting position until they are hit by a collider
> in which case their transform becomes non-identity. The moving objects
> live for a short time until they "respawn" in which case their transform is
> set back to the origin with the assignment of an identity matrix.
> Expensive calculations such as IK (Inverse Kinematics) chains are executed
> only on the objects that are not at rest and thus are transformed by a
> matrix that is not identity.
>
> tl;dr.. I would only see real-world benefit in a simple IsIdentity
> function which returns true only when the matrix is exactly identity.


I agree. At this point, it's clear that isIdentity() is too confusing and
doesn't do what its name implies.
Let's go with roc's proposal and replace the API with 'maybeHasTransform'.


>
> It is a good point that checking all 16 elements every time is costy. But
>> that is exactly what authors would expect the UA to do.
>>
>> I still don’t buy the argument with unexpected results though. We never
>> can guarantee exact results. 1 divided by 3 doesn’t give exact results but
>> at least interoperable results as long as platforms follow IEEE. This is
>> not the case for trigonometric functions. It is not possible to guarantee
>> that sin(Math.PI/3) is the same on all platforms since implementations vary
>> across platforms. This of course affects DOMMatrix when one uses rotate. So
>> none of the values can be guaranteed to be interoperable across all
>> platforms. That means that isIdentity might not be guaranteed to give exact
>> results either. And this usually is fine. If isIdentity does return false,
>> well then the engine has to do a bit more work and can’t return earlier…
>> That is what isIdentity is used for anyway. Make sure that engines don’t do

Dirk Schulze

unread,
Jun 6, 2014, 4:31:53 PM6/6/14
to Rik Cabanier, Kip Gilbert, dev-pl...@lists.mozilla.org
You can not say you agree and turn the comment around by 180 degree (or PI). The comment was:

“"
tl;dr.. I would only see real-world benefit in a simple IsIdentity
function which returns true only when the matrix is exactly identity.
“"

This is exactly what I wrote.

Greetings,
Dirk

Kip Gilbert

unread,
Jun 6, 2014, 4:52:29 PM6/6/14
to dev-pl...@lists.mozilla.org

On 2014-06-06, 1:23 PM, Rik Cabanier wrote:
>
>
>
> On Fri, Jun 6, 2014 at 12:18 PM, Kip Gilbert <kgil...@mozilla.com
> <mailto:kgil...@mozilla.com>> wrote:
>
> Hello,
>
> From a game programmer's perspective, isIdentity would normally be
> used to cull out work. In these cases, it is expected that
> isIdentity will return true only when the matrix is exactly equal
> to the identity matrix. Due to the nature of floating point, the
> isIdentity will only likely be true when it has been initialized
> or assigned identity directly. This is what occurs in existing
> game / math libraries.
>
>
> Yes, this is why storing it as an internal flag is the correct solution.
Perhaps you wish to use an internal flag as an optimization? This is
usually not necessary as the comparison function will usually early-out
after the first row of comparisons. If the matrix class is implemented
with SIMD instructions, the comparison becomes even cheaper. There is
nothing inherently wrong with mirroring the equality with a separate
flag; however, this is potentially unneeded complexity.
I don't believe isIdentity to be confusing. For example, the Unity3D
Matrix4x4 class also has an "isIdentity" function:

http://docs.unity3d.com/ScriptReference/Matrix4x4-isIdentity.html

Given the estimated 2 million developers using Unity, there seems to be
a lack of issues raised about the "isIdentity" function.

- Kip

Neil

unread,
Jun 6, 2014, 5:10:18 PM6/6/14
to
Rik Cabanier wrote:

>1. isIdentity()
>We settled that this should mean that the matrix was never changed to a non identity state.
>
Are you doing something similar for the 2d/3d case?

--
Warning: May contain traces of nuts.
It is loading more messages.
0 new messages