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