Changeset 156553 in webkit


Ignore:
Timestamp:
Sep 27, 2013 10:26:05 AM (11 years ago)
Author:
dino@apple.com
Message:

Provide 2D Matrix decomposition for animation
https://bugs.webkit.org/show_bug.cgi?id=112824
<rdar://problem/15091882>

Reviewed by Eric Carlson (and Ian Henderson offline).

Source/WebCore:

Implement a new 2d matrix blend, which is triggered
when animating between two affine 3d matrices. This
is intended to be the official algorithm that gets
put into the W3C Transforms specification.

The old code is renamed with a 4 prefix (indicating
it is a blend between 3d matrices using quaternions),
and new methods and structures for 2d blending were added.

I also took the opportunity to clean up a lot of
bad WebKit style.

  • platform/graphics/ca/GraphicsLayerCA.cpp:

(WebCore::maxScaleFromTransform): Use 3d decomposition.

  • platform/graphics/transforms/PerspectiveTransformOperation.cpp:

(WebCore::PerspectiveTransformOperation::blend): Ditto.

  • platform/graphics/transforms/RotateTransformOperation.cpp:

(WebCore::RotateTransformOperation::blend): Ditto.

  • platform/graphics/transforms/TransformationMatrix.cpp:

(WebCore::decompose2): New method to decompose an affine 3d matrix
into X/Y scale + translate, a rotation angle, plus some extracted
a,b,c,d fields from the affine section.
(WebCore::decompose4): New name for the old function.
(WebCore::TransformationMatrix::blend2): Perform linear interpolation
between two 2d decompositions.
(WebCore::TransformationMatrix::blend4): New name for the old function.
(WebCore::TransformationMatrix::blend): Call blend2 or blend4 depending
on the type of matrix.
(WebCore::TransformationMatrix::decompose2): Calls into the decompose2
method above.
(WebCore::TransformationMatrix::decompose4): New name.
(WebCore::TransformationMatrix::recompose2): Recomposes a 3d matrix from
a 2d decomposition.
(WebCore::TransformationMatrix::recompose4): New name.

  • platform/graphics/transforms/TransformationMatrix.h: All the changes

for the new methods above.

LayoutTests:

This test was only exercising the fact that our
software decomposition did not match our hardware
decomposition (although that required visual inspection).
Now that our 2d decomposition is correct, update the
test and its expected result.

  • animations/transform-non-accelerated-expected.txt:
  • animations/transform-non-accelerated.html:
Location:
trunk
Files:
9 edited

Legend:

Unmodified
Added
Removed
  • trunk/LayoutTests/ChangeLog

    r156551 r156553  
     12013-09-26  Dean Jackson  <dino@apple.com>
     2
     3        Provide 2D Matrix decomposition for animation
     4        https://bugs.webkit.org/show_bug.cgi?id=112824
     5        <rdar://problem/15091882>
     6
     7        Reviewed by Eric Carlson (and Ian Henderson offline).
     8
     9        This test was only exercising the fact that our
     10        software decomposition did not match our hardware
     11        decomposition (although that required visual inspection).
     12        Now that our 2d decomposition is correct, update the
     13        test and its expected result.
     14
     15        * animations/transform-non-accelerated-expected.txt:
     16        * animations/transform-non-accelerated.html:
     17
    1182013-09-27  Mario Sanchez Prada  <mario.prada@samsung.com>
    219
  • trunk/LayoutTests/animations/transform-non-accelerated-expected.txt

    r156506 r156553  
    11During the animation, the box should flip in the horizontal axis. It should not disappear into a single point (i.e. the visual width should not change).
    22
    3 PASS - "webkitTransform" property for "box" element at 0.5s saw something close to: 0,0,0,0,0,0
     3PASS - "webkitTransform" property for "box" element at 0.5s saw something close to: 1,0,0,0,0,0
    44
  • trunk/LayoutTests/animations/transform-non-accelerated.html

    r156506 r156553  
    3030const expectedValues = [
    3131  // [animation-name, time, element-id, property, expected-value, tolerance]
    32   ["flip", 0.5, "box", "webkitTransform", [0, 0, 0, 0, 0, 0], 0.3],
     32  ["flip", 0.5, "box", "webkitTransform", [1, 0, 0, 0, 0, 0], 0.3],
    3333];
    3434
  • trunk/Source/WebCore/ChangeLog

    r156550 r156553  
     12013-09-26  Dean Jackson  <dino@apple.com>
     2
     3        Provide 2D Matrix decomposition for animation
     4        https://bugs.webkit.org/show_bug.cgi?id=112824
     5        <rdar://problem/15091882>
     6
     7        Reviewed by Eric Carlson (and Ian Henderson offline).
     8
     9        Implement a new 2d matrix blend, which is triggered
     10        when animating between two affine 3d matrices. This
     11        is intended to be the official algorithm that gets
     12        put into the W3C Transforms specification.
     13
     14        The old code is renamed with a 4 prefix (indicating
     15        it is a blend between 3d matrices using quaternions),
     16        and new methods and structures for 2d blending were added.
     17
     18        I also took the opportunity to clean up a lot of
     19        bad WebKit style.
     20
     21        * platform/graphics/ca/GraphicsLayerCA.cpp:
     22        (WebCore::maxScaleFromTransform): Use 3d decomposition.
     23        * platform/graphics/transforms/PerspectiveTransformOperation.cpp:
     24        (WebCore::PerspectiveTransformOperation::blend): Ditto.
     25        * platform/graphics/transforms/RotateTransformOperation.cpp:
     26        (WebCore::RotateTransformOperation::blend): Ditto.
     27
     28        * platform/graphics/transforms/TransformationMatrix.cpp:
     29        (WebCore::decompose2): New method to decompose an affine 3d matrix
     30        into X/Y scale + translate, a rotation angle, plus some extracted
     31        a,b,c,d fields from the affine section.
     32        (WebCore::decompose4): New name for the old function.
     33        (WebCore::TransformationMatrix::blend2): Perform linear interpolation
     34        between two 2d decompositions.
     35        (WebCore::TransformationMatrix::blend4): New name for the old function.
     36        (WebCore::TransformationMatrix::blend): Call blend2 or blend4 depending
     37        on the type of matrix.
     38        (WebCore::TransformationMatrix::decompose2): Calls into the decompose2
     39        method above.
     40        (WebCore::TransformationMatrix::decompose4): New name.
     41        (WebCore::TransformationMatrix::recompose2): Recomposes a 3d matrix from
     42        a 2d decomposition.
     43        (WebCore::TransformationMatrix::recompose4): New name.
     44        * platform/graphics/transforms/TransformationMatrix.h: All the changes
     45        for the new methods above.
     46
    1472013-09-26  Darin Adler  <darin@apple.com>
    248
  • trunk/Source/WebCore/platform/graphics/ca/GraphicsLayerCA.cpp

    r156301 r156553  
    257257        return 1;
    258258
    259     TransformationMatrix::DecomposedType decomposeData;
    260     t.decompose(decomposeData);
     259    TransformationMatrix::Decomposed4Type decomposeData;
     260    t.decompose4(decomposeData);
    261261    return std::max(fabsf(decomposeData.scaleX), fabsf(decomposeData.scaleY));
    262262}
  • trunk/Source/WebCore/platform/graphics/transforms/PerspectiveTransformOperation.cpp

    r111126 r156553  
    5454    toT.applyPerspective(floatValueForLength(toP, 1));
    5555    toT.blend(fromT, progress);
    56     TransformationMatrix::DecomposedType decomp;
    57     toT.decompose(decomp);
     56    TransformationMatrix::Decomposed4Type decomp;
     57    toT.decompose4(decomp);
    5858
    5959    if (decomp.perspectiveZ) {
  • trunk/Source/WebCore/platform/graphics/transforms/RotateTransformOperation.cpp

    r136964 r156553  
    7171   
    7272    // Extract the result as a quaternion
    73     TransformationMatrix::DecomposedType decomp;
    74     toT.decompose(decomp);
     73    TransformationMatrix::Decomposed4Type decomp;
     74    toT.decompose4(decomp);
    7575   
    7676    // Convert that to Axis/Angle form
  • trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.cpp

    r142810 r156553  
    11/*
    2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
     2 * Copyright (C) 2005, 2006, 2013 Apple Computer, Inc.  All rights reserved.
    33 * Copyright (C) 2009 Torch Mobile, Inc.
    44 *
     
    2222 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    2323 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    24  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
     24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    2525 */
    2626
     
    5555// Adapted from Matrix Inversion by Richard Carling, Graphics Gems <http://tog.acm.org/GraphicsGems/index.html>.
    5656
    57 // EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code 
    58 // as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial 
    59 // or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there 
    60 // are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or 
    61 // webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes 
     57// EULA: The Graphics Gems code is copyright-protected. In other words, you cannot claim the text of the code
     58// as your own and resell it. Using the code is permitted in any program, product, or library, non-commercial
     59// or commercial. Giving credit is not required, though is a nice gesture. The code comes as-is, and if there
     60// are any flaws or problems with any Gems code, nobody involved with Gems - authors, editors, publishers, or
     61// webmasters - are to be held responsible. Basically, don't be a jerk, and remember that anything free comes
    6262// with no guarantee.
    6363
    6464// A clarification about the storage of matrix elements
    6565//
    66 // This class uses a 2 dimensional array internally to store the elements of the matrix.  The first index into
     66// This class uses a 2 dimensional array internally to store the elements of the matrix. The first index into
    6767// the array refers to the column that the element lies in; the second index refers to the row.
    6868//
     
    8080
    8181// inverse(original_matrix, inverse_matrix)
    82 // 
     82//
    8383// calculate the inverse of a 4x4 matrix
    84 // 
    85 // -1     
     84//
     85// -1
    8686// A  = ___1__ adjoint A
    8787//       det A
    8888
    8989//  double = determinant2x2(double a, double b, double c, double d)
    90 // 
     90//
    9191//  calculate the determinant of a 2x2 matrix.
    9292
     
    9797
    9898//  double = determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3)
    99 // 
     99//
    100100//  Calculate the determinant of a 3x3 matrix
    101101//  in the form
    102 // 
     102//
    103103//      | a1,  b1,  c1 |
    104104//      | a2,  b2,  c2 |
     
    113113
    114114//  double = determinant4x4(matrix)
    115 // 
     115//
    116116//  calculate the determinant of a 4x4 matrix.
    117117
     
    122122
    123123    double a1 = m[0][0];
    124     double b1 = m[0][1]; 
     124    double b1 = m[0][1];
    125125    double c1 = m[0][2];
    126126    double d1 = m[0][3];
    127127
    128128    double a2 = m[1][0];
    129     double b2 = m[1][1]; 
     129    double b2 = m[1][1];
    130130    double c2 = m[1][2];
    131131    double d2 = m[1][3];
    132132
    133     double a3 = m[2][0]; 
     133    double a3 = m[2][0];
    134134    double b3 = m[2][1];
    135135    double c3 = m[2][2];
     
    137137
    138138    double a4 = m[3][0];
    139     double b4 = m[3][1]; 
     139    double b4 = m[3][1];
    140140    double c4 = m[3][2];
    141141    double d4 = m[3][3];
     
    155155//
    156156//    deleting the ith row and jth column from A.
    157 // 
     157//
    158158//                  i+j
    159159//   Let  b   = (-1)    a
    160160//        ij            ji
    161 // 
     161//
    162162//  The matrix B = (b  ) is the adjoint of A
    163163//                   ij
     
    168168    // selecting correct values
    169169    double a1 = matrix[0][0];
    170     double b1 = matrix[0][1]; 
     170    double b1 = matrix[0][1];
    171171    double c1 = matrix[0][2];
    172172    double d1 = matrix[0][3];
    173173
    174174    double a2 = matrix[1][0];
    175     double b2 = matrix[1][1]; 
     175    double b2 = matrix[1][1];
    176176    double c2 = matrix[1][2];
    177177    double d2 = matrix[1][3];
     
    183183
    184184    double a4 = matrix[3][0];
    185     double b4 = matrix[3][1]; 
     185    double b4 = matrix[3][1];
    186186    double c4 = matrix[3][2];
    187187    double d4 = matrix[3][3];
     
    192192    result[2][0]  =   determinant3x3(a2, a3, a4, b2, b3, b4, d2, d3, d4);
    193193    result[3][0]  = - determinant3x3(a2, a3, a4, b2, b3, b4, c2, c3, c4);
    194        
     194
    195195    result[0][1]  = - determinant3x3(b1, b3, b4, c1, c3, c4, d1, d3, d4);
    196196    result[1][1]  =   determinant3x3(a1, a3, a4, c1, c3, c4, d1, d3, d4);
    197197    result[2][1]  = - determinant3x3(a1, a3, a4, b1, b3, b4, d1, d3, d4);
    198198    result[3][1]  =   determinant3x3(a1, a3, a4, b1, b3, b4, c1, c3, c4);
    199        
     199
    200200    result[0][2]  =   determinant3x3(b1, b2, b4, c1, c2, c4, d1, d2, d4);
    201201    result[1][2]  = - determinant3x3(a1, a2, a4, c1, c2, c4, d1, d2, d4);
    202202    result[2][2]  =   determinant3x3(a1, a2, a4, b1, b2, b4, d1, d2, d4);
    203203    result[3][2]  = - determinant3x3(a1, a2, a4, b1, b2, b4, c1, c2, c4);
    204        
     204
    205205    result[0][3]  = - determinant3x3(b1, b2, b3, c1, c2, c3, d1, d2, d3);
    206206    result[1][3]  =   determinant3x3(a1, a2, a3, c1, c2, c3, d1, d2, d3);
     
    216216
    217217    // Calculate the 4x4 determinant
    218     // If the determinant is zero, 
     218    // If the determinant is zero,
    219219    // then the inverse matrix is not unique.
    220220    double det = determinant4x4(matrix);
     
    263263}
    264264
    265 static void v3Scale(Vector3 v, double desiredLength) 
     265static void v3Scale(Vector3 v, double desiredLength)
    266266{
    267267    double len = v3Length(v);
     
    274274}
    275275
    276 static double v3Dot(const Vector3 a, const Vector3 b) 
     276static double v3Dot(const Vector3 a, const Vector3 b)
    277277{
    278278    return (a[0] * b[0]) + (a[1] * b[1]) + (a[2] * b[2]);
     
    296296}
    297297
    298 static bool decompose(const TransformationMatrix::Matrix4& mat, TransformationMatrix::DecomposedType& result)
     298static bool decompose2(const TransformationMatrix::Matrix4& matrix, TransformationMatrix::Decomposed2Type& result)
     299{
     300    double row0x = matrix[0][0];
     301    double row0y = matrix[0][1];
     302    double row1x = matrix[1][0];
     303    double row1y = matrix[1][1];
     304    result.translateX = matrix[3][0];
     305    result.translateY = matrix[3][1];
     306
     307    // Compute scaling factors.
     308    result.scaleX = sqrt(row0x * row0x + row0y * row0y);
     309    result.scaleY = sqrt(row1x * row1x + row1y * row1y);
     310
     311    // If determinant is negative, one axis was flipped.
     312    double determinant = row0x * row1y - row0y * row1x;
     313    if (determinant < 0) {
     314        // Flip axis with minimum unit vector dot product.
     315        if (row0x < row1y)
     316            result.scaleX = -result.scaleX;
     317        else
     318            result.scaleY = -result.scaleY;
     319    }
     320
     321    // Renormalize matrix to remove scale.
     322    if (result.scaleX) {
     323        row0x *= 1 / result.scaleX;
     324        row0y *= 1 / result.scaleX;
     325    }
     326    if (result.scaleY) {
     327        row1x *= 1 / result.scaleY;
     328        row1y *= 1 / result.scaleY;
     329    }
     330
     331    // Compute rotation and renormalize matrix.
     332    result.angle = atan2(row0y, row0x);
     333
     334    if (result.angle) {
     335        // Rotate(-angle) = [cos(angle), sin(angle), -sin(angle), cos(angle)]
     336        //                = [row0x, -row0y, row0y, row0x]
     337        // Thanks to the normalization above.
     338        double sn = -row0y;
     339        double cs = row0x;
     340        double m11 = row0x, m12 = row0y;
     341        double m21 = row1x, m22 = row1y;
     342
     343        row0x = cs * m11 + sn * m21;
     344        row0y = cs * m12 + sn * m22;
     345        row1x = -sn * m11 + cs * m21;
     346        row1y = -sn * m12 + cs * m22;
     347    }
     348
     349    result.m11 = row0x;
     350    result.m12 = row0y;
     351    result.m21 = row1x;
     352    result.m22 = row1y;
     353
     354    // Convert into degrees because our rotation functions expect it.
     355    result.angle = rad2deg(result.angle);
     356
     357    return true;
     358}
     359
     360static bool decompose4(const TransformationMatrix::Matrix4& mat, TransformationMatrix::Decomposed4Type& result)
    299361{
    300362    TransformationMatrix::Matrix4 localMatrix;
     
    321383        return false;
    322384
    323     // First, isolate perspective.  This is the messiest.
     385    // First, isolate perspective. This is the messiest.
    324386    if (localMatrix[0][3] != 0 || localMatrix[1][3] != 0 || localMatrix[2][3] != 0) {
    325387        // rightHandSide is the right hand side of the equation.
     
    331393
    332394        // Solve the equation by inverting perspectiveMatrix and multiplying
    333         // rightHandSide by the inverse.  (This is the easiest way, not
     395        // rightHandSide by the inverse. (This is the easiest way, not
    334396        // necessarily the best.)
    335397        TransformationMatrix::Matrix4 inversePerspectiveMatrix, transposedInversePerspectiveMatrix;
     
    339401        Vector4 perspectivePoint;
    340402        v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
    341  
     403
    342404        result.perspectiveX = perspectivePoint[0];
    343405        result.perspectiveY = perspectivePoint[1];
    344406        result.perspectiveZ = perspectivePoint[2];
    345407        result.perspectiveW = perspectivePoint[3];
    346        
     408
    347409        // Clear the perspective partition
    348410        localMatrix[0][3] = localMatrix[1][3] = localMatrix[2][3] = 0;
     
    353415        result.perspectiveW = 1;
    354416    }
    355    
     417
    356418    // Next take care of translation (easy).
    357419    result.translateX = localMatrix[3][0];
     
    396458    result.skewXZ /= result.scaleZ;
    397459    result.skewYZ /= result.scaleZ;
    398  
     460
    399461    // At this point, the matrix (in rows[]) is orthonormal.
    400     // Check for a coordinate system flip.  If the determinant
     462    // Check for a coordinate system flip. If the determinant
    401463    // is -1, then negate the matrix and the scaling factors.
    402464    v3Cross(row[1], row[2], pdum3);
     
    413475        }
    414476    }
    415  
     477
    416478    // Now, get the rotations out, as described in the gem.
    417    
     479
    418480    // FIXME - Add the ability to return either quaternions (which are
    419481    // easier to recompose with) or Euler angles (rx, ry, rz), which
     
    430492    //     ret.rotateZ = 0;
    431493    // }
    432    
     494
    433495    double s, t, x, y, z, w;
    434496
     
    441503        y = (row[0][2] - row[2][0]) * s;
    442504        z = (row[1][0] - row[0][1]) * s;
    443     } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) { 
    444         s = sqrt (1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S=4*qx
     505    } else if (row[0][0] > row[1][1] && row[0][0] > row[2][2]) {
     506        s = sqrt(1.0 + row[0][0] - row[1][1] - row[2][2]) * 2.0; // S = 4 * qx.
    445507        x = 0.25 * s;
    446         y = (row[0][1] + row[1][0]) / s; 
    447         z = (row[0][2] + row[2][0]) / s; 
     508        y = (row[0][1] + row[1][0]) / s;
     509        z = (row[0][2] + row[2][0]) / s;
    448510        w = (row[2][1] - row[1][2]) / s;
    449     } else if (row[1][1] > row[2][2]) { 
    450         s = sqrt (1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S=4*qy
    451         x = (row[0][1] + row[1][0]) / s; 
     511    } else if (row[1][1] > row[2][2]) {
     512        s = sqrt(1.0 + row[1][1] - row[0][0] - row[2][2]) * 2.0; // S = 4 * qy.
     513        x = (row[0][1] + row[1][0]) / s;
    452514        y = 0.25 * s;
    453         z = (row[1][2] + row[2][1]) / s; 
     515        z = (row[1][2] + row[2][1]) / s;
    454516        w = (row[0][2] - row[2][0]) / s;
    455     } else { 
    456         s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S=4*qz
     517    } else {
     518        s = sqrt(1.0 + row[2][2] - row[0][0] - row[1][1]) * 2.0; // S = 4 * qz.
    457519        x = (row[0][2] + row[2][0]) / s;
    458         y = (row[1][2] + row[2][1]) / s; 
     520        y = (row[1][2] + row[2][1]) / s;
    459521        z = 0.25 * s;
    460522        w = (row[1][0] - row[0][1]) / s;
     
    465527    result.quaternionZ = z;
    466528    result.quaternionW = w;
    467    
     529
    468530    return true;
    469531}
    470532
    471533// Perform a spherical linear interpolation between the two
    472 // passed quaternions with 0 <= t <= 1
     534// passed quaternions with 0 <= t <= 1.
    473535static void slerp(double qa[4], const double qb[4], double t)
    474536{
     
    552614    // inverse transform to find the corresponding point in the source
    553615    // space.
    554     // 
     616    //
    555617    // Given a plane with normal Pn, and a ray starting at point R0 and
    556618    // with direction defined by the vector Rd, we can find the
    557619    // intersection point as a distance d from R0 in units of Rd by:
    558     // 
     620    //
    559621    // d = -dot (Pn', R0) / dot (Pn', Rd)
    560622    if (clamped)
     
    566628        return FloatPoint();
    567629    }
    568    
     630
    569631    double x = p.x();
    570632    double y = p.y();
     
    609671    if (clamped)
    610672        *clamped = clamped1 || clamped2 || clamped3 || clamped4;
    611        
     673
    612674    // If all points on the quad had w < 0, then the entire quad would not be visible to the projected surface.
    613675    bool everythingWasClipped = clamped1 && clamped2 && clamped3 && clamped4;
     
    716778    m_matrix[0][2] *= sx;
    717779    m_matrix[0][3] *= sx;
    718    
     780
    719781    m_matrix[1][0] *= sy;
    720782    m_matrix[1][1] *= sy;
     
    727789{
    728790    scaleNonUniform(sx, sy);
    729    
     791
    730792    m_matrix[2][0] *= sz;
    731793    m_matrix[2][1] *= sz;
     
    740802    double length = sqrt(x * x + y * y + z * z);
    741803    if (length == 0) {
    742         // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied. 
     804        // A direction vector that cannot be normalized, such as [0, 0, 0], will cause the rotation to not be applied.
    743805        return *this;
    744806    } else if (length != 1) {
     
    753815    double sinTheta = sin(angle);
    754816    double cosTheta = cos(angle);
    755    
     817
    756818    TransformationMatrix mat;
    757819
     
    828890    ry = deg2rad(ry);
    829891    rz = deg2rad(rz);
    830    
     892
    831893    TransformationMatrix mat;
    832    
     894
    833895    double sinTheta = sin(rz);
    834896    double cosTheta = cos(rz);
    835    
     897
    836898    mat.m_matrix[0][0] = cosTheta;
    837899    mat.m_matrix[0][1] = sinTheta;
     
    846908    mat.m_matrix[3][0] = mat.m_matrix[3][1] = mat.m_matrix[3][2] = 0.0;
    847909    mat.m_matrix[3][3] = 1.0;
    848    
     910
    849911    TransformationMatrix rmat(mat);
    850    
     912
    851913    sinTheta = sin(ry);
    852914    cosTheta = cos(ry);
    853    
     915
    854916    mat.m_matrix[0][0] = cosTheta;
    855917    mat.m_matrix[0][1] = 0.0;
     
    869931    sinTheta = sin(rx);
    870932    cosTheta = cos(rx);
    871    
     933
    872934    mat.m_matrix[0][0] = 1.0;
    873935    mat.m_matrix[0][1] = 0.0;
     
    9441006    sx = deg2rad(sx);
    9451007    sy = deg2rad(sy);
    946    
     1008
    9471009    TransformationMatrix mat;
    9481010    mat.m_matrix[0][1] = tan(sy); // note that the y shear goes in the first row
     
    12431305#else
    12441306    Matrix4 tmp;
    1245    
     1307
    12461308    tmp[0][0] = (mat.m_matrix[0][0] * m_matrix[0][0] + mat.m_matrix[0][1] * m_matrix[1][0]
    12471309               + mat.m_matrix[0][2] * m_matrix[2][0] + mat.m_matrix[0][3] * m_matrix[3][0]);
     
    12791341    tmp[3][3] = (mat.m_matrix[3][0] * m_matrix[0][3] + mat.m_matrix[3][1] * m_matrix[1][3]
    12801342               + mat.m_matrix[3][2] * m_matrix[2][3] + mat.m_matrix[3][3] * m_matrix[3][3]);
    1281    
     1343
    12821344    setMatrix(tmp);
    12831345#endif
     
    13221384}
    13231385
    1324 TransformationMatrix TransformationMatrix::inverse() const 
     1386TransformationMatrix TransformationMatrix::inverse() const
    13251387{
    13261388    if (isIdentityOrTranslation()) {
     
    13281390        if (m_matrix[3][0] == 0 && m_matrix[3][1] == 0 && m_matrix[3][2] == 0)
    13291391            return TransformationMatrix();
    1330        
     1392
    13311393        // translation
    13321394        return TransformationMatrix(1, 0, 0, 0,
     
    13351397                                    -m_matrix[3][0], -m_matrix[3][1], -m_matrix[3][2], 1);
    13361398    }
    1337    
     1399
    13381400    TransformationMatrix invMat;
    13391401    bool inverted = WebCore::inverse(m_matrix, invMat.m_matrix);
    13401402    if (!inverted)
    13411403        return TransformationMatrix();
    1342    
     1404
    13431405    return invMat;
    13441406}
     
    13481410    m_matrix[0][2] = 0;
    13491411    m_matrix[0][3] = 0;
    1350    
     1412
    13511413    m_matrix[1][2] = 0;
    13521414    m_matrix[1][3] = 0;
    1353    
     1415
    13541416    m_matrix[2][0] = 0;
    13551417    m_matrix[2][1] = 0;
    13561418    m_matrix[2][2] = 1;
    13571419    m_matrix[2][3] = 0;
    1358    
     1420
    13591421    m_matrix[3][2] = 0;
    13601422    m_matrix[3][3] = 1;
     
    13731435}
    13741436
    1375 void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
    1376 {
    1377     if (from.isIdentity() && isIdentity())
    1378         return;
    1379        
    1380     // decompose
    1381     DecomposedType fromDecomp;
    1382     DecomposedType toDecomp;
    1383     from.decompose(fromDecomp);
    1384     decompose(toDecomp);
    1385 
    1386     // interpolate
     1437void TransformationMatrix::blend2(const TransformationMatrix& from, double progress)
     1438{
     1439    Decomposed2Type fromDecomp;
     1440    Decomposed2Type toDecomp;
     1441    from.decompose2(fromDecomp);
     1442    decompose2(toDecomp);
     1443
     1444    // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
     1445    if ((fromDecomp.scaleX < 0 && toDecomp.scaleY < 0) || (fromDecomp.scaleY < 0 && toDecomp.scaleX < 0)) {
     1446        fromDecomp.scaleX = -fromDecomp.scaleX;
     1447        fromDecomp.scaleY = -fromDecomp.scaleY;
     1448        fromDecomp.angle += fromDecomp.angle < 0 ? 180 : -180;
     1449    }
     1450
     1451    // Don't rotate the long way around.
     1452    if (!fromDecomp.angle)
     1453        fromDecomp.angle = 360;
     1454    if (!toDecomp.angle)
     1455        toDecomp.angle = 360;
     1456
     1457    if (fabs(fromDecomp.angle - toDecomp.angle) > 180) {
     1458        if (fromDecomp.angle > toDecomp.angle)
     1459            fromDecomp.angle -= 360;
     1460        else
     1461            toDecomp.angle -= 360;
     1462    }
     1463
     1464    blendFloat(fromDecomp.m11, toDecomp.m11, progress);
     1465    blendFloat(fromDecomp.m12, toDecomp.m12, progress);
     1466    blendFloat(fromDecomp.m21, toDecomp.m21, progress);
     1467    blendFloat(fromDecomp.m22, toDecomp.m22, progress);
     1468    blendFloat(fromDecomp.translateX, toDecomp.translateX, progress);
     1469    blendFloat(fromDecomp.translateY, toDecomp.translateY, progress);
     1470    blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
     1471    blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
     1472    blendFloat(fromDecomp.angle, toDecomp.angle, progress);
     1473
     1474    recompose2(fromDecomp);
     1475}
     1476
     1477void TransformationMatrix::blend4(const TransformationMatrix& from, double progress)
     1478{
     1479    Decomposed4Type fromDecomp;
     1480    Decomposed4Type toDecomp;
     1481    from.decompose4(fromDecomp);
     1482    decompose4(toDecomp);
     1483
    13871484    blendFloat(fromDecomp.scaleX, toDecomp.scaleX, progress);
    13881485    blendFloat(fromDecomp.scaleY, toDecomp.scaleY, progress);
     
    13981495    blendFloat(fromDecomp.perspectiveZ, toDecomp.perspectiveZ, progress);
    13991496    blendFloat(fromDecomp.perspectiveW, toDecomp.perspectiveW, progress);
    1400    
     1497
    14011498    slerp(&fromDecomp.quaternionX, &toDecomp.quaternionX, progress);
    1402        
    1403     // recompose
    1404     recompose(fromDecomp);
    1405 }
    1406 
    1407 bool TransformationMatrix::decompose(DecomposedType& decomp) const
     1499
     1500    recompose4(fromDecomp);
     1501}
     1502
     1503void TransformationMatrix::blend(const TransformationMatrix& from, double progress)
     1504{
     1505    if (from.isIdentity() && isIdentity())
     1506        return;
     1507
     1508    if (from.isAffine() && isAffine())
     1509        blend2(from, progress);
     1510    else
     1511        blend4(from, progress);
     1512}
     1513
     1514bool TransformationMatrix::decompose2(Decomposed2Type& decomp) const
     1515{
     1516    if (isIdentity()) {
     1517        memset(&decomp, 0, sizeof(decomp));
     1518        decomp.scaleX = 1;
     1519        decomp.scaleY = 1;
     1520    }
     1521
     1522    return WebCore::decompose2(m_matrix, decomp);
     1523}
     1524
     1525bool TransformationMatrix::decompose4(Decomposed4Type& decomp) const
    14081526{
    14091527    if (isIdentity()) {
     
    14141532        decomp.scaleZ = 1;
    14151533    }
    1416    
    1417     if (!WebCore::decompose(m_matrix, decomp))
    1418         return false;
    1419     return true;
    1420 }
    1421 
    1422 void TransformationMatrix::recompose(const DecomposedType& decomp)
     1534
     1535    return WebCore::decompose4(m_matrix, decomp);
     1536}
     1537
     1538void TransformationMatrix::recompose2(const Decomposed2Type& decomp)
    14231539{
    14241540    makeIdentity();
    1425    
    1426     // first apply perspective
     1541
     1542    m_matrix[0][0] = decomp.m11;
     1543    m_matrix[0][1] = decomp.m12;
     1544    m_matrix[1][0] = decomp.m21;
     1545    m_matrix[1][1] = decomp.m22;
     1546
     1547    translate3d(decomp.translateX, decomp.translateY, 0);
     1548    rotate(decomp.angle);
     1549    scale3d(decomp.scaleX, decomp.scaleY, 1);
     1550}
     1551
     1552void TransformationMatrix::recompose4(const Decomposed4Type& decomp)
     1553{
     1554    makeIdentity();
     1555
     1556    // First apply perspective.
    14271557    m_matrix[0][3] = decomp.perspectiveX;
    14281558    m_matrix[1][3] = decomp.perspectiveY;
    14291559    m_matrix[2][3] = decomp.perspectiveZ;
    14301560    m_matrix[3][3] = decomp.perspectiveW;
    1431    
    1432     // now translate
     1561
     1562    // Next, translate.
    14331563    translate3d(decomp.translateX, decomp.translateY, decomp.translateZ);
    1434    
    1435     // apply rotation
     1564
     1565    // Apply rotation.
    14361566    double xx = decomp.quaternionX * decomp.quaternionX;
    14371567    double xy = decomp.quaternionX * decomp.quaternionY;
     
    14431573    double zz = decomp.quaternionZ * decomp.quaternionZ;
    14441574    double zw = decomp.quaternionZ * decomp.quaternionW;
    1445    
    1446     // Construct a composite rotation matrix from the quaternion values
    1447     TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0, 
     1575
     1576    // Construct a composite rotation matrix from the quaternion values.
     1577    TransformationMatrix rotationMatrix(1 - 2 * (yy + zz), 2 * (xy - zw), 2 * (xz + yw), 0,
    14481578                           2 * (xy + zw), 1 - 2 * (xx + zz), 2 * (yz - xw), 0,
    14491579                           2 * (xz - yw), 2 * (yz + xw), 1 - 2 * (xx + yy), 0,
    14501580                           0, 0, 0, 1);
    1451    
     1581
    14521582    multiply(rotationMatrix);
    1453    
    1454     // now apply skew
     1583
     1584    // Apply skew.
    14551585    if (decomp.skewYZ) {
    14561586        TransformationMatrix tmp;
     
    14581588        multiply(tmp);
    14591589    }
    1460    
     1590
    14611591    if (decomp.skewXZ) {
    14621592        TransformationMatrix tmp;
     
    14641594        multiply(tmp);
    14651595    }
    1466    
     1596
    14671597    if (decomp.skewXY) {
    14681598        TransformationMatrix tmp;
     
    14701600        multiply(tmp);
    14711601    }
    1472    
    1473     // finally, apply scale
     1602
     1603    // Finally, apply scale.
    14741604    scale3d(decomp.scaleX, decomp.scaleY, decomp.scaleZ);
    14751605}
  • trunk/Source/WebCore/platform/graphics/transforms/TransformationMatrix.h

    r155251 r156553  
    233233    TransformationMatrix& scaleNonUniform(double sx, double sy);
    234234    TransformationMatrix& scale3d(double sx, double sy, double sz);
    235    
     235
     236    // Angle is in degrees.
    236237    TransformationMatrix& rotate(double d) { return rotate3d(0, 0, d); }
    237238    TransformationMatrix& rotateFromVector(double x, double y);
     
    268269
    269270    // decompose the matrix into its component parts
     271    typedef struct {
     272        double scaleX, scaleY;
     273        double translateX, translateY;
     274        double angle;
     275        double m11, m12, m21, m22;
     276    } Decomposed2Type;
     277
    270278    typedef struct {
    271279        double scaleX, scaleY, scaleZ;
     
    274282        double translateX, translateY, translateZ;
    275283        double perspectiveX, perspectiveY, perspectiveZ, perspectiveW;
    276     } DecomposedType;
    277    
    278     bool decompose(DecomposedType& decomp) const;
    279     void recompose(const DecomposedType& decomp);
    280    
     284    } Decomposed4Type;
     285   
     286    bool decompose2(Decomposed2Type&) const;
     287    void recompose2(const Decomposed2Type&);
     288
     289    bool decompose4(Decomposed4Type&) const;
     290    void recompose4(const Decomposed4Type&);
     291
    281292    void blend(const TransformationMatrix& from, double progress);
     293    void blend2(const TransformationMatrix& from, double progress);
     294    void blend4(const TransformationMatrix& from, double progress);
    282295
    283296    bool isAffine() const
Note: See TracChangeset for help on using the changeset viewer.