Home | History | Annotate | Download | only in transforms
      1 /*
      2  * Copyright (C) 2005, 2006 Apple Computer, Inc.  All rights reserved.
      3  *               2010 Dirk Schulze <krit (at) webkit.org>
      4  *
      5  * Redistribution and use in source and binary forms, with or without
      6  * modification, are permitted provided that the following conditions
      7  * are met:
      8  * 1. Redistributions of source code must retain the above copyright
      9  *    notice, this list of conditions and the following disclaimer.
     10  * 2. Redistributions in binary form must reproduce the above copyright
     11  *    notice, this list of conditions and the following disclaimer in the
     12  *    documentation and/or other materials provided with the distribution.
     13  *
     14  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     15  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     17  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     18  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     19  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     20  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     21  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     22  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     23  * (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.
     25  */
     26 
     27 #include "config.h"
     28 #include "AffineTransform.h"
     29 
     30 #include "FloatConversion.h"
     31 #include "FloatQuad.h"
     32 #include "FloatRect.h"
     33 #include "IntRect.h"
     34 
     35 #include <wtf/MathExtras.h>
     36 
     37 namespace WebCore {
     38 
     39 static void affineTransformDecompose(const AffineTransform& matrix, double sr[9])
     40 {
     41     AffineTransform m(matrix);
     42 
     43     // Compute scaling factors
     44     double sx = matrix.xScale();
     45     double sy = matrix.yScale();
     46 
     47     // Compute cross product of transformed unit vectors. If negative,
     48     // one axis was flipped.
     49     if (m.a() * m.d() - m.c() * m.b() < 0.0) {
     50         // Flip axis with minimum unit vector dot product
     51         if (m.a() < m.d())
     52             sx = -sx;
     53         else
     54             sy = -sy;
     55     }
     56 
     57     // Remove scale from matrix
     58     m.scale(1.0 / sx, 1.0 / sy);
     59 
     60     // Compute rotation
     61     double angle = atan2(m.b(), m.a());
     62 
     63     // Remove rotation from matrix
     64     m.rotate(rad2deg(-angle));
     65 
     66     // Return results
     67     sr[0] = sx;
     68     sr[1] = sy;
     69     sr[2] = angle;
     70     sr[3] = m.a();
     71     sr[4] = m.b();
     72     sr[5] = m.c();
     73     sr[6] = m.d();
     74     sr[7] = m.e();
     75     sr[8] = m.f();
     76 }
     77 
     78 static void affineTransformCompose(AffineTransform& m, const double sr[9])
     79 {
     80     m.setA(sr[3]);
     81     m.setB(sr[4]);
     82     m.setC(sr[5]);
     83     m.setD(sr[6]);
     84     m.setE(sr[7]);
     85     m.setF(sr[8]);
     86     m.rotate(rad2deg(sr[2]));
     87     m.scale(sr[0], sr[1]);
     88 }
     89 
     90 AffineTransform::AffineTransform()
     91 {
     92     setMatrix(1, 0, 0, 1, 0, 0);
     93 }
     94 
     95 AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
     96 {
     97     setMatrix(a, b, c, d, e, f);
     98 }
     99 
    100 void AffineTransform::makeIdentity()
    101 {
    102     setMatrix(1, 0, 0, 1, 0, 0);
    103 }
    104 
    105 void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
    106 {
    107     m_transform[0] = a;
    108     m_transform[1] = b;
    109     m_transform[2] = c;
    110     m_transform[3] = d;
    111     m_transform[4] = e;
    112     m_transform[5] = f;
    113 }
    114 
    115 bool AffineTransform::isIdentity() const
    116 {
    117     return (m_transform[0] == 1 && m_transform[1] == 0
    118          && m_transform[2] == 0 && m_transform[3] == 1
    119          && m_transform[4] == 0 && m_transform[5] == 0);
    120 }
    121 
    122 double AffineTransform::xScale() const
    123 {
    124     return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
    125 }
    126 
    127 double AffineTransform::yScale() const
    128 {
    129     return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
    130 }
    131 
    132 double AffineTransform::det() const
    133 {
    134     return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2];
    135 }
    136 
    137 bool AffineTransform::isInvertible() const
    138 {
    139     return det() != 0.0;
    140 }
    141 
    142 AffineTransform AffineTransform::inverse() const
    143 {
    144     double determinant = det();
    145     if (determinant == 0.0)
    146         return AffineTransform();
    147 
    148     AffineTransform result;
    149     if (isIdentityOrTranslation()) {
    150         result.m_transform[4] = -m_transform[4];
    151         result.m_transform[5] = -m_transform[5];
    152         return result;
    153     }
    154 
    155     result.m_transform[0] = m_transform[3] / determinant;
    156     result.m_transform[1] = -m_transform[1] / determinant;
    157     result.m_transform[2] = -m_transform[2] / determinant;
    158     result.m_transform[3] = m_transform[0] / determinant;
    159     result.m_transform[4] = (m_transform[2] * m_transform[5]
    160                            - m_transform[3] * m_transform[4]) / determinant;
    161     result.m_transform[5] = (m_transform[1] * m_transform[4]
    162                            - m_transform[0] * m_transform[5]) / determinant;
    163 
    164     return result;
    165 }
    166 
    167 
    168 // Multiplies this AffineTransform by the provided AffineTransform - i.e.
    169 // this = this * other;
    170 AffineTransform& AffineTransform::multiply(const AffineTransform& other)
    171 {
    172     AffineTransform trans;
    173 
    174     trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
    175     trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
    176     trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
    177     trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
    178     trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
    179     trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
    180 
    181     setMatrix(trans.m_transform);
    182     return *this;
    183 }
    184 
    185 AffineTransform& AffineTransform::rotate(double a)
    186 {
    187     // angle is in degree. Switch to radian
    188     a = deg2rad(a);
    189     double cosAngle = cos(a);
    190     double sinAngle = sin(a);
    191     AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
    192 
    193     multiply(rot);
    194     return *this;
    195 }
    196 
    197 AffineTransform& AffineTransform::scale(double s)
    198 {
    199     return scale(s, s);
    200 }
    201 
    202 AffineTransform& AffineTransform::scale(double sx, double sy)
    203 {
    204     m_transform[0] *= sx;
    205     m_transform[1] *= sx;
    206     m_transform[2] *= sy;
    207     m_transform[3] *= sy;
    208     return *this;
    209 }
    210 
    211 // *this = *this * translation
    212 AffineTransform& AffineTransform::translate(double tx, double ty)
    213 {
    214     if (isIdentityOrTranslation()) {
    215         m_transform[4] += tx;
    216         m_transform[5] += ty;
    217         return *this;
    218     }
    219 
    220     m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
    221     m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
    222     return *this;
    223 }
    224 
    225 AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
    226 {
    227     return scale(sx, sy);
    228 }
    229 
    230 AffineTransform& AffineTransform::rotateFromVector(double x, double y)
    231 {
    232     return rotate(rad2deg(atan2(y, x)));
    233 }
    234 
    235 AffineTransform& AffineTransform::flipX()
    236 {
    237     return scale(-1, 1);
    238 }
    239 
    240 AffineTransform& AffineTransform::flipY()
    241 {
    242     return scale(1, -1);
    243 }
    244 
    245 AffineTransform& AffineTransform::shear(double sx, double sy)
    246 {
    247     double a = m_transform[0];
    248     double b = m_transform[1];
    249 
    250     m_transform[0] += sy * m_transform[2];
    251     m_transform[1] += sy * m_transform[3];
    252     m_transform[2] += sx * a;
    253     m_transform[3] += sx * b;
    254 
    255     return *this;
    256 }
    257 
    258 AffineTransform& AffineTransform::skew(double angleX, double angleY)
    259 {
    260     return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
    261 }
    262 
    263 AffineTransform& AffineTransform::skewX(double angle)
    264 {
    265     return shear(tan(deg2rad(angle)), 0);
    266 }
    267 
    268 AffineTransform& AffineTransform::skewY(double angle)
    269 {
    270     return shear(0, tan(deg2rad(angle)));
    271 }
    272 
    273 AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
    274 {
    275     AffineTransform transform;
    276     transform.translate(dest.x() - source.x(), dest.y() - source.y());
    277     transform.scale(dest.width() / source.width(), dest.height() / source.height());
    278     return transform;
    279 }
    280 
    281 void AffineTransform::map(double x, double y, double& x2, double& y2) const
    282 {
    283     x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
    284     y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
    285 }
    286 
    287 IntPoint AffineTransform::mapPoint(const IntPoint& point) const
    288 {
    289     double x2, y2;
    290     map(point.x(), point.y(), x2, y2);
    291 
    292     // Round the point.
    293     return IntPoint(lround(x2), lround(y2));
    294 }
    295 
    296 FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
    297 {
    298     double x2, y2;
    299     map(point.x(), point.y(), x2, y2);
    300 
    301     return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
    302 }
    303 
    304 IntRect AffineTransform::mapRect(const IntRect &rect) const
    305 {
    306     return enclosingIntRect(mapRect(FloatRect(rect)));
    307 }
    308 
    309 FloatRect AffineTransform::mapRect(const FloatRect& rect) const
    310 {
    311     if (isIdentityOrTranslation()) {
    312         FloatRect mappedRect(rect);
    313         mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
    314         return mappedRect;
    315     }
    316 
    317     FloatQuad result;
    318     result.setP1(mapPoint(rect.location()));
    319     result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
    320     result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
    321     result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
    322     return result.boundingBox();
    323 }
    324 
    325 FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
    326 {
    327     if (isIdentityOrTranslation()) {
    328         FloatQuad mappedQuad(q);
    329         mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
    330         return mappedQuad;
    331     }
    332 
    333     FloatQuad result;
    334     result.setP1(mapPoint(q.p1()));
    335     result.setP2(mapPoint(q.p2()));
    336     result.setP3(mapPoint(q.p3()));
    337     result.setP4(mapPoint(q.p4()));
    338     return result;
    339 }
    340 
    341 void AffineTransform::blend(const AffineTransform& from, double progress)
    342 {
    343     double srA[9], srB[9];
    344 
    345     affineTransformDecompose(from, srA);
    346     affineTransformDecompose(*this, srB);
    347 
    348     // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
    349     if ((srA[0] < 0 && srB[1] < 0) || (srA[1] < 0 &&  srB[0] < 0)) {
    350         srA[0] = -srA[0];
    351         srA[1] = -srA[1];
    352         srA[2] += srA[2] < 0 ? piDouble : -piDouble;
    353     }
    354 
    355     // Don't rotate the long way around.
    356     srA[2] = fmod(srA[2], 2.0 * piDouble);
    357     srB[2] = fmod(srB[2], 2.0 * piDouble);
    358 
    359     if (fabs(srA[2] - srB[2]) > piDouble) {
    360         if (srA[2] > srB[2])
    361             srA[2] -= piDouble * 2.0;
    362         else
    363             srB[2] -= piDouble * 2.0;
    364     }
    365 
    366     for (int i = 0; i < 9; i++)
    367         srA[i] = srA[i] + progress * (srB[i] - srA[i]);
    368 
    369     affineTransformCompose(*this, srA);
    370 }
    371 
    372 TransformationMatrix AffineTransform::toTransformationMatrix() const
    373 {
    374     return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
    375                                 m_transform[3], m_transform[4], m_transform[5]);
    376 }
    377 
    378 }
    379