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 "core/platform/graphics/transforms/AffineTransform.h"
     30 
     31 #include "core/platform/FloatConversion.h"
     32 #include "core/platform/graphics/FloatQuad.h"
     33 #include "core/platform/graphics/FloatRect.h"
     34 #include "core/platform/graphics/IntRect.h"
     35 #include "core/platform/graphics/skia/SkiaUtils.h"
     36 
     37 #include "wtf/MathExtras.h"
     38 
     39 namespace WebCore {
     40 
     41 AffineTransform::AffineTransform()
     42 {
     43     setMatrix(1, 0, 0, 1, 0, 0);
     44 }
     45 
     46 AffineTransform::AffineTransform(double a, double b, double c, double d, double e, double f)
     47 {
     48     setMatrix(a, b, c, d, e, f);
     49 }
     50 
     51 void AffineTransform::makeIdentity()
     52 {
     53     setMatrix(1, 0, 0, 1, 0, 0);
     54 }
     55 
     56 void AffineTransform::setMatrix(double a, double b, double c, double d, double e, double f)
     57 {
     58     m_transform[0] = a;
     59     m_transform[1] = b;
     60     m_transform[2] = c;
     61     m_transform[3] = d;
     62     m_transform[4] = e;
     63     m_transform[5] = f;
     64 }
     65 
     66 bool AffineTransform::isIdentity() const
     67 {
     68     return (m_transform[0] == 1 && m_transform[1] == 0
     69          && m_transform[2] == 0 && m_transform[3] == 1
     70          && m_transform[4] == 0 && m_transform[5] == 0);
     71 }
     72 
     73 double AffineTransform::xScale() const
     74 {
     75     return sqrt(m_transform[0] * m_transform[0] + m_transform[1] * m_transform[1]);
     76 }
     77 
     78 double AffineTransform::yScale() const
     79 {
     80     return sqrt(m_transform[2] * m_transform[2] + m_transform[3] * m_transform[3]);
     81 }
     82 
     83 double AffineTransform::det() const
     84 {
     85     return m_transform[0] * m_transform[3] - m_transform[1] * m_transform[2];
     86 }
     87 
     88 bool AffineTransform::isInvertible() const
     89 {
     90     return det() != 0.0;
     91 }
     92 
     93 AffineTransform AffineTransform::inverse() const
     94 {
     95     double determinant = det();
     96     if (determinant == 0.0)
     97         return AffineTransform();
     98 
     99     AffineTransform result;
    100     if (isIdentityOrTranslation()) {
    101         result.m_transform[4] = -m_transform[4];
    102         result.m_transform[5] = -m_transform[5];
    103         return result;
    104     }
    105 
    106     result.m_transform[0] = m_transform[3] / determinant;
    107     result.m_transform[1] = -m_transform[1] / determinant;
    108     result.m_transform[2] = -m_transform[2] / determinant;
    109     result.m_transform[3] = m_transform[0] / determinant;
    110     result.m_transform[4] = (m_transform[2] * m_transform[5]
    111                            - m_transform[3] * m_transform[4]) / determinant;
    112     result.m_transform[5] = (m_transform[1] * m_transform[4]
    113                            - m_transform[0] * m_transform[5]) / determinant;
    114 
    115     return result;
    116 }
    117 
    118 
    119 // Multiplies this AffineTransform by the provided AffineTransform - i.e.
    120 // this = this * other;
    121 AffineTransform& AffineTransform::multiply(const AffineTransform& other)
    122 {
    123     AffineTransform trans;
    124 
    125     trans.m_transform[0] = other.m_transform[0] * m_transform[0] + other.m_transform[1] * m_transform[2];
    126     trans.m_transform[1] = other.m_transform[0] * m_transform[1] + other.m_transform[1] * m_transform[3];
    127     trans.m_transform[2] = other.m_transform[2] * m_transform[0] + other.m_transform[3] * m_transform[2];
    128     trans.m_transform[3] = other.m_transform[2] * m_transform[1] + other.m_transform[3] * m_transform[3];
    129     trans.m_transform[4] = other.m_transform[4] * m_transform[0] + other.m_transform[5] * m_transform[2] + m_transform[4];
    130     trans.m_transform[5] = other.m_transform[4] * m_transform[1] + other.m_transform[5] * m_transform[3] + m_transform[5];
    131 
    132     setMatrix(trans.m_transform);
    133     return *this;
    134 }
    135 
    136 AffineTransform& AffineTransform::rotate(double a)
    137 {
    138     // angle is in degree. Switch to radian
    139     a = deg2rad(a);
    140     double cosAngle = cos(a);
    141     double sinAngle = sin(a);
    142     AffineTransform rot(cosAngle, sinAngle, -sinAngle, cosAngle, 0, 0);
    143 
    144     multiply(rot);
    145     return *this;
    146 }
    147 
    148 AffineTransform& AffineTransform::scale(double s)
    149 {
    150     return scale(s, s);
    151 }
    152 
    153 AffineTransform& AffineTransform::scale(double sx, double sy)
    154 {
    155     m_transform[0] *= sx;
    156     m_transform[1] *= sx;
    157     m_transform[2] *= sy;
    158     m_transform[3] *= sy;
    159     return *this;
    160 }
    161 
    162 // *this = *this * translation
    163 AffineTransform& AffineTransform::translate(double tx, double ty)
    164 {
    165     if (isIdentityOrTranslation()) {
    166         m_transform[4] += tx;
    167         m_transform[5] += ty;
    168         return *this;
    169     }
    170 
    171     m_transform[4] += tx * m_transform[0] + ty * m_transform[2];
    172     m_transform[5] += tx * m_transform[1] + ty * m_transform[3];
    173     return *this;
    174 }
    175 
    176 AffineTransform& AffineTransform::scaleNonUniform(double sx, double sy)
    177 {
    178     return scale(sx, sy);
    179 }
    180 
    181 AffineTransform& AffineTransform::rotateFromVector(double x, double y)
    182 {
    183     return rotate(rad2deg(atan2(y, x)));
    184 }
    185 
    186 AffineTransform& AffineTransform::flipX()
    187 {
    188     return scale(-1, 1);
    189 }
    190 
    191 AffineTransform& AffineTransform::flipY()
    192 {
    193     return scale(1, -1);
    194 }
    195 
    196 AffineTransform& AffineTransform::shear(double sx, double sy)
    197 {
    198     double a = m_transform[0];
    199     double b = m_transform[1];
    200 
    201     m_transform[0] += sy * m_transform[2];
    202     m_transform[1] += sy * m_transform[3];
    203     m_transform[2] += sx * a;
    204     m_transform[3] += sx * b;
    205 
    206     return *this;
    207 }
    208 
    209 AffineTransform& AffineTransform::skew(double angleX, double angleY)
    210 {
    211     return shear(tan(deg2rad(angleX)), tan(deg2rad(angleY)));
    212 }
    213 
    214 AffineTransform& AffineTransform::skewX(double angle)
    215 {
    216     return shear(tan(deg2rad(angle)), 0);
    217 }
    218 
    219 AffineTransform& AffineTransform::skewY(double angle)
    220 {
    221     return shear(0, tan(deg2rad(angle)));
    222 }
    223 
    224 AffineTransform makeMapBetweenRects(const FloatRect& source, const FloatRect& dest)
    225 {
    226     AffineTransform transform;
    227     transform.translate(dest.x() - source.x(), dest.y() - source.y());
    228     transform.scale(dest.width() / source.width(), dest.height() / source.height());
    229     return transform;
    230 }
    231 
    232 void AffineTransform::map(double x, double y, double& x2, double& y2) const
    233 {
    234     x2 = (m_transform[0] * x + m_transform[2] * y + m_transform[4]);
    235     y2 = (m_transform[1] * x + m_transform[3] * y + m_transform[5]);
    236 }
    237 
    238 IntPoint AffineTransform::mapPoint(const IntPoint& point) const
    239 {
    240     double x2, y2;
    241     map(point.x(), point.y(), x2, y2);
    242 
    243     // Round the point.
    244     return IntPoint(lround(x2), lround(y2));
    245 }
    246 
    247 FloatPoint AffineTransform::mapPoint(const FloatPoint& point) const
    248 {
    249     double x2, y2;
    250     map(point.x(), point.y(), x2, y2);
    251 
    252     return FloatPoint(narrowPrecisionToFloat(x2), narrowPrecisionToFloat(y2));
    253 }
    254 
    255 IntSize AffineTransform::mapSize(const IntSize& size) const
    256 {
    257     double width2 = size.width() * xScale();
    258     double height2 = size.height() * yScale();
    259 
    260     return IntSize(lround(width2), lround(height2));
    261 }
    262 
    263 FloatSize AffineTransform::mapSize(const FloatSize& size) const
    264 {
    265     double width2 = size.width() * xScale();
    266     double height2 = size.height() * yScale();
    267 
    268     return FloatSize(narrowPrecisionToFloat(width2), narrowPrecisionToFloat(height2));
    269 }
    270 
    271 IntRect AffineTransform::mapRect(const IntRect &rect) const
    272 {
    273     return enclosingIntRect(mapRect(FloatRect(rect)));
    274 }
    275 
    276 FloatRect AffineTransform::mapRect(const FloatRect& rect) const
    277 {
    278     if (isIdentityOrTranslation()) {
    279         FloatRect mappedRect(rect);
    280         mappedRect.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
    281         return mappedRect;
    282     }
    283 
    284     FloatQuad result;
    285     result.setP1(mapPoint(rect.location()));
    286     result.setP2(mapPoint(FloatPoint(rect.maxX(), rect.y())));
    287     result.setP3(mapPoint(FloatPoint(rect.maxX(), rect.maxY())));
    288     result.setP4(mapPoint(FloatPoint(rect.x(), rect.maxY())));
    289     return result.boundingBox();
    290 }
    291 
    292 FloatQuad AffineTransform::mapQuad(const FloatQuad& q) const
    293 {
    294     if (isIdentityOrTranslation()) {
    295         FloatQuad mappedQuad(q);
    296         mappedQuad.move(narrowPrecisionToFloat(m_transform[4]), narrowPrecisionToFloat(m_transform[5]));
    297         return mappedQuad;
    298     }
    299 
    300     FloatQuad result;
    301     result.setP1(mapPoint(q.p1()));
    302     result.setP2(mapPoint(q.p2()));
    303     result.setP3(mapPoint(q.p3()));
    304     result.setP4(mapPoint(q.p4()));
    305     return result;
    306 }
    307 
    308 void AffineTransform::blend(const AffineTransform& from, double progress)
    309 {
    310     DecomposedType srA, srB;
    311 
    312     from.decompose(srA);
    313     this->decompose(srB);
    314 
    315     // If x-axis of one is flipped, and y-axis of the other, convert to an unflipped rotation.
    316     if ((srA.scaleX < 0 && srB.scaleY < 0) || (srA.scaleY < 0 &&  srB.scaleX < 0)) {
    317         srA.scaleX = -srA.scaleX;
    318         srA.scaleY = -srA.scaleY;
    319         srA.angle += srA.angle < 0 ? piDouble : -piDouble;
    320     }
    321 
    322     // Don't rotate the long way around.
    323     srA.angle = fmod(srA.angle, 2 * piDouble);
    324     srB.angle = fmod(srB.angle, 2 * piDouble);
    325 
    326     if (fabs(srA.angle - srB.angle) > piDouble) {
    327         if (srA.angle > srB.angle)
    328             srA.angle -= piDouble * 2;
    329         else
    330             srB.angle -= piDouble * 2;
    331     }
    332 
    333     srA.scaleX += progress * (srB.scaleX - srA.scaleX);
    334     srA.scaleY += progress * (srB.scaleY - srA.scaleY);
    335     srA.angle += progress * (srB.angle - srA.angle);
    336     srA.remainderA += progress * (srB.remainderA - srA.remainderA);
    337     srA.remainderB += progress * (srB.remainderB - srA.remainderB);
    338     srA.remainderC += progress * (srB.remainderC - srA.remainderC);
    339     srA.remainderD += progress * (srB.remainderD - srA.remainderD);
    340     srA.translateX += progress * (srB.translateX - srA.translateX);
    341     srA.translateY += progress * (srB.translateY - srA.translateY);
    342 
    343     this->recompose(srA);
    344 }
    345 
    346 TransformationMatrix AffineTransform::toTransformationMatrix() const
    347 {
    348     return TransformationMatrix(m_transform[0], m_transform[1], m_transform[2],
    349                                 m_transform[3], m_transform[4], m_transform[5]);
    350 }
    351 
    352 AffineTransform::operator SkMatrix() const
    353 {
    354     SkMatrix result;
    355 
    356     result.setScaleX(WebCoreDoubleToSkScalar(a()));
    357     result.setSkewX(WebCoreDoubleToSkScalar(c()));
    358     result.setTranslateX(WebCoreDoubleToSkScalar(e()));
    359 
    360     result.setScaleY(WebCoreDoubleToSkScalar(d()));
    361     result.setSkewY(WebCoreDoubleToSkScalar(b()));
    362     result.setTranslateY(WebCoreDoubleToSkScalar(f()));
    363 
    364     // FIXME: Set perspective properly.
    365     result.setPerspX(0);
    366     result.setPerspY(0);
    367     result.set(SkMatrix::kMPersp2, SK_Scalar1);
    368 
    369     return result;
    370 }
    371 
    372 bool AffineTransform::decompose(DecomposedType& decomp) const
    373 {
    374     AffineTransform m(*this);
    375 
    376     // Compute scaling factors
    377     double sx = xScale();
    378     double sy = yScale();
    379 
    380     // Compute cross product of transformed unit vectors. If negative,
    381     // one axis was flipped.
    382     if (m.a() * m.d() - m.c() * m.b() < 0) {
    383         // Flip axis with minimum unit vector dot product
    384         if (m.a() < m.d())
    385             sx = -sx;
    386         else
    387             sy = -sy;
    388     }
    389 
    390     // Remove scale from matrix
    391     m.scale(1 / sx, 1 / sy);
    392 
    393     // Compute rotation
    394     double angle = atan2(m.b(), m.a());
    395 
    396     // Remove rotation from matrix
    397     m.rotate(rad2deg(-angle));
    398 
    399     // Return results
    400     decomp.scaleX = sx;
    401     decomp.scaleY = sy;
    402     decomp.angle = angle;
    403     decomp.remainderA = m.a();
    404     decomp.remainderB = m.b();
    405     decomp.remainderC = m.c();
    406     decomp.remainderD = m.d();
    407     decomp.translateX = m.e();
    408     decomp.translateY = m.f();
    409 
    410     return true;
    411 }
    412 
    413 void AffineTransform::recompose(const DecomposedType& decomp)
    414 {
    415     this->setA(decomp.remainderA);
    416     this->setB(decomp.remainderB);
    417     this->setC(decomp.remainderC);
    418     this->setD(decomp.remainderD);
    419     this->setE(decomp.translateX);
    420     this->setF(decomp.translateY);
    421     this->rotate(rad2deg(decomp.angle));
    422     this->scale(decomp.scaleX, decomp.scaleY);
    423 }
    424 
    425 }
    426