Bug 67695

Summary: (animated?) rotate and rotate3d improperly handle values over 180 degrees
Product: WebKit Reporter: John Schulz <webkit.org>
Component: CSSAssignee: Dean Jackson <dino>
Status: NEW ---    
Severity: Normal CC: cmarrin, dino, paulirish, simon.fraser
Priority: P2    
Version: 528+ (Nightly build)   
Hardware: Mac   
OS: OS X 10.6   
URL: https://spreadsheets.google.com/spreadsheet/pub?hl=en_US&hl=en_US&key=0AojtvjY4aEBDdDNsTUpGZ2ZsemZuRTBVSm5CWlEwYkE&single=true&gid=0&output=html

Description John Schulz 2011-09-06 21:26:04 PDT
What steps will reproduce the problem?
1. Go to https://spreadsheets.google.com/spreadsheet/pub?hl=en_US&hl=en_US&key=0AojtvjY4aEBDdDNsTUpGZ2ZsemZuRTBVSm5CWlEwYkE&single=true&gid=0&output=html
2. Go to any of the various example URLs
3. Observe

What is the expected result?
An animation should occur in which the target is rotated the from the start point and rotation to the end point and rotation

What happens instead?
For values over 180 degrees, the rotation is not correct. It's as though the calculation becomes "(distance % 180) - 180" under certain conditions.
Comment 1 Simon Fraser (smfr) 2011-09-07 09:09:59 PDT
Can you be more specific about what you're seeing? Those animations look fine to me (Mac Safari 5.1). What OS and browser are you testing with?

Please also just have one test page, not lots. <http://jsbin.com/omedam/3/edit#preview> seems to be the simplest.
Comment 2 John Schulz 2011-09-07 10:04:21 PDT
I'm observing these issues in Safari 5.1 (as well as Chrome stable) on Mac OS 10.6.8. I put notes in the Notes column where the behaviors differ between the two browsers.

Sorry the observed behaviors weren't clear. In short, there are times when values over 180 degrees will cause the animations to misbehave. I tried to detail what was happening via the expected / actual rotation, correct direction, etc columns.

For example, http://jsbin.com/omedam/1/edit#html,live should rotate 540 degrees, but instead it only rotates 180 degrees: http://screencast.com/t/V2rzyADiDqB The direction of the rotation is correct, but the amount is incorrect.

However, in http://jsbin.com/omedam/21/edit#html,live both the direction and the amount of rotation are incorrect. The image should rotate 270 clockwise but, instead, only rotates 90 degrees counterclockwise.  This video shows how a value of 180deg will behave as expected, where a value of 181deg will cause the direction of the animation to change.

There are also examples where transformations which seem to be the same will exhibit different behavior. http://jsbin.com/omedam/2/edit#html,live goes from rotateY(0deg) to rotateY(540deg) and behaves as expected. Where http://jsbin.com/omedam/33/edit#html,live goes from rotate3d(0,1,0,0deg) to rotate3d(0,1,0,540deg) and will only rotate 180 degrees, but in the correct direction.

http://jsbin.com/omedam/2/edit#html,live has an identity function of  rotateY(0deg) and a transform function of rotateY(540deg) and behaves as expected. However, http://jsbin.com/omedam/1/edit#html,live has an identity function of rotate(0deg) and a transform function of rotateY(540deg) and exhibits the 'correct direction but incorrect amount' misbehavior. Perhaps the identity and transform functions must be same but I didn't see that in the spec http://www.w3.org/TR/css3-3d-transforms/. And, even if they should be the same, I think not rotating at all is less confusing than rotating an incorrect amount.

I created multiple pages because there multiple types of misbehavior (wrong direction and/or wrong amount) and multiple functions (rotate, rotateX, rotateY, rotateZ, rotate3d) are affected. I wanted to provide both examples of both success and error conditions in an effort to determine the underlying cause.
Comment 3 Simon Fraser (smfr) 2011-09-07 10:40:06 PDT
Some perspective make it easier to see <http://jsbin.com/omedam/34/edit>
Comment 4 John Schulz 2011-09-07 10:41:40 PDT
The video that corresponds to http://jsbin.com/omedam/21/edit#html,live (and shows how exceeding 180 deg changes orientation direction) is http://screencast.com/t/t2eGXXKCc
Comment 5 Simon Fraser (smfr) 2011-09-07 11:45:36 PDT
> exceeding 180 deg changes orientation direction
It flips over and you see the back. Isn't that what you expect?
Comment 6 Simon Fraser (smfr) 2011-09-07 12:01:14 PDT
I see the issue. You're animating from rotate(0deg) to rotateY(540deg), which is effectively going between rotateZ() and rotateY(). Because your starting and ending transform lists are mismatched, we fall back to converting both to matrices, and interpolating the matrices. This causes loss of information, but is expected behavior. See <http://www.w3.org/TR/css3-3d-transforms/#animation>
Comment 7 John Schulz 2011-09-07 12:05:01 PDT
> > exceeding 180 deg changes orientation direction
> It flips over and you see the back. Isn't that what you expect?

No. It's rotating around the Z axis so there should be no "back". Z axis rotation is like a clock or a steering wheel.

Regardless of the axis of rotation, the direction shouldn't change just be incrementing the value. Positive and negative values are used to control the direction of rotation.
Comment 8 John Schulz 2011-09-07 12:06:03 PDT
(In reply to comment #6)
> I see the issue. You're animating from rotate(0deg) to rotateY(540deg), which is effectively going between rotateZ() and rotateY(). Because your starting and ending transform lists are mismatched, we fall back to converting both to matrices, and interpolating the matrices. This causes loss of information, but is expected behavior. See <http://www.w3.org/TR/css3-3d-transforms/#animation>

That is simply one case. What about the others I detailed? They are not covered by that explanation.
Comment 9 Dean Jackson 2011-09-08 13:09:55 PDT
(In reply to comment #8)
> (In reply to comment #6)
> > I see the issue. You're animating from rotate(0deg) to rotateY(540deg), which is effectively going between rotateZ() and rotateY(). Because your starting and ending transform lists are mismatched, we fall back to converting both to matrices, and interpolating the matrices. This causes loss of information, but is expected behavior. See <http://www.w3.org/TR/css3-3d-transforms/#animation>
> 
> That is simply one case. What about the others I detailed? They are not covered by that explanation.

Sorry, I think they are. http://www.w3.org/TR/css3-3d-transforms/#animation

- The first three tests you give fail all the rules given in the spec, in particular the 2nd last one "If both the ‘from’ and ‘to’ transforms have the same number of transform functions and corresponding functions in each transform list are of the same type". rotate() doesn't match rotateX(), rotateY() or rotateZ().

- The rest of the tests are between rotate3d() values. See the 2nd sub-clause of the first rule: "For perspective, matrix, matrix3d and rotate3d: the values are first converted to a 4x4 matrix...". That conversion to a matrix will lose the fact that 360deg is different from 0deg.

I'll also note that rotate3d(0,0,0, anything) doesn't make sense. The spec says "A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied". 

I'm going to take this bug though, because it seems that Chrome is applying rotation where it shouldn't. I expect this is because the WebKit software animator is doing the wrong thing (Safari uses another engine for 3d). Unfortunately this means "fixing" the bug in the opposite manner to which you're asking.
Comment 10 John Schulz 2011-09-08 13:35:09 PDT
(In reply to comment #9)
> (In reply to comment #8)
> > (In reply to comment #6)
> > > I see the issue. You're animating from rotate(0deg) to rotateY(540deg), which is effectively going between rotateZ() and rotateY(). Because your starting and ending transform lists are mismatched, we fall back to converting both to matrices, and interpolating the matrices. This causes loss of information, but is expected behavior. See <http://www.w3.org/TR/css3-3d-transforms/#animation>
> > 
> > That is simply one case. What about the others I detailed? They are not covered by that explanation.
> 
> Sorry, I think they are. http://www.w3.org/TR/css3-3d-transforms/#animation
> 
> - in particular the 2nd last one "If both the ‘from’ and ‘to’ transforms have the same number of transform functions and corresponding functions in each transform list are of the same type". rotate() doesn't match rotateX(), rotateY() or rotateZ().
  Ah, indeed.

> I'll also note that rotate3d(0,0,0, anything) doesn't make sense. The spec says "A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied". 
  Oh, right, good catch. Thanks. I completely missed that http://jsbin.com/omedam/21/edit#html,live had 0,0,0 as the start transform.

> - The rest of the tests are between rotate3d() values. See the 2nd sub-clause of the first rule: "For perspective, matrix, matrix3d and rotate3d: the values are first converted to a 4x4 matrix...". That conversion to a matrix will lose the fact that 360deg is different from 0deg.
>
> I'm going to take this bug though, because it seems that Chrome is applying rotation where it shouldn't. I expect this is because the WebKit software animator is doing the wrong thing (Safari uses another engine for 3d). Unfortunately this means "fixing" the bug in the opposite manner to which you're asking.
  This is confusing/disappointing. Is there any way to rotate more than 1 revolution?

  "rotate an element X degrees/turns/rads in Y seconds using the Z timing function" seems like a valid, and quite common, use case. Is this really not possible according to the spec or is my approach/syntax incorrect?
Comment 11 Dean Jackson 2011-09-08 17:45:38 PDT
(In reply to comment #10)

>   This is confusing/disappointing. Is there any way to rotate more than 1 revolution?
> 
>   "rotate an element X degrees/turns/rads in Y seconds using the Z timing function" seems like a valid, and quite common, use case. Is this really not possible according to the spec or is my approach/syntax incorrect?

You can rotate any number of turns as long as you use rotate(), rotateX(), rotateY() or rotateZ() and have the functions match on the from and to states.

rotateY(0turn) -> rotateY(5turn) will spin 5 times.

We could maybe add another clause for detecting if the rotate3d() has the same rotation vector on both sides. This would have to be proposed on www-style.
Comment 12 John Schulz 2011-09-09 08:24:39 PDT
(In reply to comment #11)
> You can rotate any number of turns as long as you use rotate(), rotateX(), rotateY() or rotateZ() and have the functions match on the from and to states.
> 
> rotateY(0turn) -> rotateY(5turn) will spin 5 times.
> 
> We could maybe add another clause for detecting if the rotate3d() has the same rotation vector on both sides. This would have to be proposed on www-style.

  That would be great. My initial goal was to rotate multiple times around a line which went through the X and Y planes, e.g. animate from rotate3d(1, -1, 0, 0deg) to rotate3d(1, -1, 0, 540deg)
Comment 13 John Schulz 2011-09-22 12:26:14 PDT
> > We could maybe add another clause for detecting if the rotate3d() has the same rotation vector on both sides. This would have to be proposed on www-style.
> 
>   That would be great. My initial goal was to rotate multiple times around a line which went through the X and Y planes, e.g. animate from rotate3d(1, -1, 0, 0deg) to rotate3d(1, -1, 0, 540deg)

Has this been proposed on www-style? I looked on https://lists.webkit.org/pipermail/webkit-dev/2011-September/thread.html but didn't see anything that seemed related.

Just following up. Thanks for your help with this.
Comment 14 Dean Jackson 2011-09-22 16:39:50 PDT
> Has this been proposed on www-style? I looked on https://lists.webkit.org/pipermail/webkit-dev/2011-September/thread.html but didn't see anything that seemed related.
> 
> Just following up. Thanks for your help with this.

Just sent! 

http://lists.w3.org/Archives/Public/www-style/2011Sep/0398.html

If/when I see some agreement from other browsers, I'll update the spec and then webkit.