| <!DOCTYPE html> |
| <meta charset="UTF-8"> |
| <script src="../resources/testharness.js"></script> |
| <script src="../resources/testharnessreport.js"></script> |
| <div id="target"></div> |
| <script> |
| // These tests target post multiplication interpolation behaviour of the transform property. |
| // https://drafts.csswg.org/css-transforms-1/#interpolation-of-transforms |
| |
| function assertPostMultiplication(start, end) { |
| test(() => { |
| assert_true(interpolationUsesPostMultiplication(start, end)); |
| }, 'Animating transform from ' + start + ' to ' + end + ' should use post multiplication'); |
| } |
| |
| function assertNoPostMultiplication(start, end) { |
| test(() => { |
| assert_false(interpolationUsesPostMultiplication(start, end)); |
| }, 'Animating transform from ' + start + ' to ' + end + ' should not use post multiplication'); |
| } |
| |
| function interpolationUsesPostMultiplication(start, end) { |
| // This value suffix will cause post multiplication to interpolate differently than pairwise |
| // interpolation. Rotating by 370 degrees is equivalent to rotating by 10 degrees in the matrix |
| // representation. |
| var testStart = start + ' rotate(370deg)'; |
| var testEnd = end + ' rotate(0deg)'; |
| |
| var animation = target.animate({transform: [toMatrix(testStart), toMatrix(testEnd)]}, 1); |
| animation.currentTime = 0.5; |
| var postMultipliedInterpolation = getComputedStyle(target).transform; |
| animation.cancel(); |
| |
| animation = target.animate({transform: [testStart, testEnd]}, 1); |
| animation.currentTime = 0.5; |
| var interpolation = getComputedStyle(target).transform; |
| animation.cancel(); |
| |
| return matricesApproxEqual(interpolation, postMultipliedInterpolation, 0.01); |
| } |
| |
| function toMatrix(transform) { |
| target.style.transform = transform; |
| var matrix = getComputedStyle(target).transform; |
| target.style.transform = ''; |
| return matrix; |
| } |
| |
| function matricesApproxEqual(actualMatrix, expectedMatrix, epsilon) { |
| var extractmatrix = function(matrixStr) { |
| var list = []; |
| var regex = /[+\-]?[0-9]+[.]?[0-9]*(e[+/-][0-9]+)?/g; |
| var match = undefined; |
| do { |
| match = regex.exec(matrixStr); |
| if (match) { |
| list.push(parseFloat(match[0])); |
| } |
| } while (match); |
| return list; |
| } |
| var actualNumbers = extractmatrix(actualMatrix); |
| var expectedNumbers = extractmatrix(expectedMatrix); |
| if (actualNumbers.length !== expectedNumbers.length) { |
| return false; |
| } |
| for (var i = 0; i < actualNumbers.length; i++) { |
| if (Math.abs(actualNumbers[i] - expectedNumbers[i]) > epsilon) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // Verify that the transform prefix generates different interpolations based on matrix and pairwise |
| // interpolation. |
| assertNoPostMultiplication('', ''); |
| |
| // Transforms are not of the same type: fallback to 4x4 matrix. |
| assertPostMultiplication('translateX(10px)', 'matrix(1, 1, 0, 1, 1, 1)'); |
| assertPostMultiplication('translateX(10px)', 'rotate(90deg)'); |
| assertPostMultiplication('skewX(45deg)', 'translateX(10px)'); |
| assertPostMultiplication( |
| 'matrix(1, 0, 0, 1, 0, 0)', |
| 'matrix3d(2, 0, 0, 0, 0, 3, 0, 0, 0, 0, 4, 0, 0, 0, 0, 1)'); |
| |
| // TODO(kevers): Investigate if skewX(a) and skewY(b) should map to skew(a, 0) and skew(0, b), |
| // respectively. If correct, then pairwise interpolation should be used. |
| assertPostMultiplication('skewX(15deg)', 'skewY(15deg)'); |
| assertPostMultiplication('skew(15deg, 0deg)', 'skewY(15deg)'); |
| |
| // Transform pairs can be expressed in the form of a common primitive. |
| assertNoPostMultiplication('translate(10px, 20px)', 'translateX(100px)'); |
| assertNoPostMultiplication('translateX(10px)', 'translateY(100px)'); |
| assertNoPostMultiplication('translateX(10px)', 'translateZ(100px)'); |
| assertNoPostMultiplication('translateZ(10px)', 'translate3d(100px, 20px, 30px)'); |
| assertNoPostMultiplication('scaleX(2)', 'scaleY(1)'); |
| assertNoPostMultiplication('scaleX(2)', 'scaleZ(1)'); |
| assertNoPostMultiplication('scaleX(2)', 'scale(1, 2)'); |
| assertNoPostMultiplication('scaleX(2)', 'scale3d(1, 2, 3)'); |
| assertNoPostMultiplication('skewY(10deg)', 'skewY(15deg)'); |
| assertNoPostMultiplication('skew(10deg, 0)', 'skew(10deg, 0)'); |
| assertNoPostMultiplication('rotate(10deg)', 'rotate(90deg)'); |
| assertNoPostMultiplication('rotateY(10deg)', 'rotateY(90deg)'); |
| assertNoPostMultiplication('rotateX(90deg)', 'rotateY(90deg)'); |
| assertNoPostMultiplication('rotate(10deg)', 'rotate3d(1, 2, 1, 90deg)'); |
| assertNoPostMultiplication('rotate(10deg)', 'rotateZ(90deg)'); |
| assertNoPostMultiplication('rotate(10deg)', 'rotate3d(0, 0, 1, 90deg)'); |
| assertNoPostMultiplication('rotate(10deg)', 'rotate3d(0, 0, 2, 90deg)'); |
| assertNoPostMultiplication('rotateX(10deg)', 'rotate3d(1, 0, 0, 100deg)'); |
| assertNoPostMultiplication('perspective(10px)', 'perspective(100px)'); |
| assertNoPostMultiplication('matrix(1, 0, 0, 1, 0, 0)', 'matrix(2, 0, 0, 2, 0, 0)'); |
| </script> |