LCOV - code coverage report
Current view: top level - gfx/skia/skia/src/core - SkMatrix.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 314 1034 30.4 %
Date: 2017-07-14 16:53:18 Functions: 32 100 32.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  * Copyright 2006 The Android Open Source Project
       3             :  *
       4             :  * Use of this source code is governed by a BSD-style license that can be
       5             :  * found in the LICENSE file.
       6             :  */
       7             : 
       8             : #include "SkFloatBits.h"
       9             : #include "SkMatrix.h"
      10             : #include "SkNx.h"
      11             : #include "SkPaint.h"
      12             : #include "SkRSXform.h"
      13             : #include "SkString.h"
      14             : #include <stddef.h>
      15             : 
      16           0 : static void normalize_perspective(SkScalar mat[9]) {
      17             :     // If it was interesting to never store the last element, we could divide all 8 other
      18             :     // elements here by the 9th, making it 1.0...
      19             :     //
      20             :     // When SkScalar was SkFixed, we would sometimes rescale the entire matrix to keep its
      21             :     // component values from getting too large. This is not a concern when using floats/doubles,
      22             :     // so we do nothing now.
      23             : 
      24             :     // Disable this for now, but it could be enabled.
      25             : #if 0
      26             :     if (0 == mat[SkMatrix::kMPersp0] && 0 == mat[SkMatrix::kMPersp1]) {
      27             :         SkScalar p2 = mat[SkMatrix::kMPersp2];
      28             :         if (p2 != 0 && p2 != 1) {
      29             :             double inv = 1.0 / p2;
      30             :             for (int i = 0; i < 6; ++i) {
      31             :                 mat[i] = SkDoubleToScalar(mat[i] * inv);
      32             :             }
      33             :             mat[SkMatrix::kMPersp2] = 1;
      34             :         }
      35             :     }
      36             : #endif
      37           0 : }
      38             : 
      39             : // In a few places, we performed the following
      40             : //      a * b + c * d + e
      41             : // as
      42             : //      a * b + (c * d + e)
      43             : //
      44             : // sdot and scross are indended to capture these compound operations into a
      45             : // function, with an eye toward considering upscaling the intermediates to
      46             : // doubles for more precision (as we do in concat and invert).
      47             : //
      48             : // However, these few lines that performed the last add before the "dot", cause
      49             : // tiny image differences, so we guard that change until we see the impact on
      50             : // chrome's layouttests.
      51             : //
      52             : #define SK_LEGACY_MATRIX_MATH_ORDER
      53             : 
      54         276 : static inline float SkDoubleToFloat(double x) {
      55         276 :     return static_cast<float>(x);
      56             : }
      57             : 
      58             : /*      [scale-x    skew-x      trans-x]   [X]   [X']
      59             :         [skew-y     scale-y     trans-y] * [Y] = [Y']
      60             :         [persp-0    persp-1     persp-2]   [1]   [1 ]
      61             : */
      62             : 
      63         286 : void SkMatrix::reset() {
      64         286 :     fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
      65         286 :     fMat[kMSkewX]  = fMat[kMSkewY] =
      66         286 :     fMat[kMTransX] = fMat[kMTransY] =
      67         286 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
      68         286 :     this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
      69         286 : }
      70             : 
      71           0 : void SkMatrix::set9(const SkScalar buffer[]) {
      72           0 :     memcpy(fMat, buffer, 9 * sizeof(SkScalar));
      73           0 :     normalize_perspective(fMat);
      74           0 :     this->setTypeMask(kUnknown_Mask);
      75           0 : }
      76             : 
      77           0 : void SkMatrix::setAffine(const SkScalar buffer[]) {
      78           0 :     fMat[kMScaleX] = buffer[kAScaleX];
      79           0 :     fMat[kMSkewX]  = buffer[kASkewX];
      80           0 :     fMat[kMTransX] = buffer[kATransX];
      81           0 :     fMat[kMSkewY]  = buffer[kASkewY];
      82           0 :     fMat[kMScaleY] = buffer[kAScaleY];
      83           0 :     fMat[kMTransY] = buffer[kATransY];
      84           0 :     fMat[kMPersp0] = 0;
      85           0 :     fMat[kMPersp1] = 0;
      86           0 :     fMat[kMPersp2] = 1;
      87           0 :     this->setTypeMask(kUnknown_Mask);
      88           0 : }
      89             : 
      90             : // this guy aligns with the masks, so we can compute a mask from a varaible 0/1
      91             : enum {
      92             :     kTranslate_Shift,
      93             :     kScale_Shift,
      94             :     kAffine_Shift,
      95             :     kPerspective_Shift,
      96             :     kRectStaysRect_Shift
      97             : };
      98             : 
      99             : static const int32_t kScalar1Int = 0x3f800000;
     100             : 
     101         394 : uint8_t SkMatrix::computePerspectiveTypeMask() const {
     102             :     // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
     103             :     // is a win, but replacing those below is not. We don't yet understand
     104             :     // that result.
     105         394 :     if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
     106             :         // If this is a perspective transform, we return true for all other
     107             :         // transform flags - this does not disable any optimizations, respects
     108             :         // the rule that the type mask must be conservative, and speeds up
     109             :         // type mask computation.
     110           0 :         return SkToU8(kORableMasks);
     111             :     }
     112             : 
     113         394 :     return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
     114             : }
     115             : 
     116        4085 : uint8_t SkMatrix::computeTypeMask() const {
     117        4085 :     unsigned mask = 0;
     118             : 
     119        4085 :     if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
     120             :         // Once it is determined that that this is a perspective transform,
     121             :         // all other flags are moot as far as optimizations are concerned.
     122           0 :         return SkToU8(kORableMasks);
     123             :     }
     124             : 
     125        4085 :     if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
     126        1416 :         mask |= kTranslate_Mask;
     127             :     }
     128             : 
     129        4085 :     int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
     130        4085 :     int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
     131        4085 :     int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
     132        4085 :     int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
     133             : 
     134        4085 :     if (m01 | m10) {
     135             :         // The skew components may be scale-inducing, unless we are dealing
     136             :         // with a pure rotation.  Testing for a pure rotation is expensive,
     137             :         // so we opt for being conservative by always setting the scale bit.
     138             :         // along with affine.
     139             :         // By doing this, we are also ensuring that matrices have the same
     140             :         // type masks as their inverses.
     141          69 :         mask |= kAffine_Mask | kScale_Mask;
     142             : 
     143             :         // For rectStaysRect, in the affine case, we only need check that
     144             :         // the primary diagonal is all zeros and that the secondary diagonal
     145             :         // is all non-zero.
     146             : 
     147             :         // map non-zero to 1
     148          69 :         m01 = m01 != 0;
     149          69 :         m10 = m10 != 0;
     150             : 
     151          69 :         int dp0 = 0 == (m00 | m11) ;  // true if both are 0
     152          69 :         int ds1 = m01 & m10;        // true if both are 1
     153             : 
     154          69 :         mask |= (dp0 & ds1) << kRectStaysRect_Shift;
     155             :     } else {
     156             :         // Only test for scale explicitly if not affine, since affine sets the
     157             :         // scale bit.
     158        4016 :         if ((m00 ^ kScalar1Int) | (m11 ^ kScalar1Int)) {
     159         431 :             mask |= kScale_Mask;
     160             :         }
     161             : 
     162             :         // Not affine, therefore we already know secondary diagonal is
     163             :         // all zeros, so we just need to check that primary diagonal is
     164             :         // all non-zero.
     165             : 
     166             :         // map non-zero to 1
     167        4016 :         m00 = m00 != 0;
     168        4016 :         m11 = m11 != 0;
     169             : 
     170             :         // record if the (p)rimary diagonal is all non-zero
     171        4016 :         mask |= (m00 & m11) << kRectStaysRect_Shift;
     172             :     }
     173             : 
     174        4085 :     return SkToU8(mask);
     175             : }
     176             : 
     177             : ///////////////////////////////////////////////////////////////////////////////
     178             : 
     179           0 : bool operator==(const SkMatrix& a, const SkMatrix& b) {
     180           0 :     const SkScalar* SK_RESTRICT ma = a.fMat;
     181           0 :     const SkScalar* SK_RESTRICT mb = b.fMat;
     182             : 
     183           0 :     return  ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
     184           0 :             ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
     185           0 :             ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
     186             : }
     187             : 
     188             : ///////////////////////////////////////////////////////////////////////////////
     189             : 
     190             : // helper function to determine if upper-left 2x2 of matrix is degenerate
     191           0 : static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
     192             :                                      SkScalar skewY,  SkScalar scaleY) {
     193           0 :     SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
     194           0 :     return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero);
     195             : }
     196             : 
     197             : ///////////////////////////////////////////////////////////////////////////////
     198             : 
     199           0 : bool SkMatrix::isSimilarity(SkScalar tol) const {
     200             :     // if identity or translate matrix
     201           0 :     TypeMask mask = this->getType();
     202           0 :     if (mask <= kTranslate_Mask) {
     203           0 :         return true;
     204             :     }
     205           0 :     if (mask & kPerspective_Mask) {
     206           0 :         return false;
     207             :     }
     208             : 
     209           0 :     SkScalar mx = fMat[kMScaleX];
     210           0 :     SkScalar my = fMat[kMScaleY];
     211             :     // if no skew, can just compare scale factors
     212           0 :     if (!(mask & kAffine_Mask)) {
     213           0 :         return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
     214             :     }
     215           0 :     SkScalar sx = fMat[kMSkewX];
     216           0 :     SkScalar sy = fMat[kMSkewY];
     217             : 
     218           0 :     if (is_degenerate_2x2(mx, sx, sy, my)) {
     219           0 :         return false;
     220             :     }
     221             : 
     222             :     // upper 2x2 is rotation/reflection + uniform scale if basis vectors
     223             :     // are 90 degree rotations of each other
     224           0 :     return (SkScalarNearlyEqual(mx, my, tol) && SkScalarNearlyEqual(sx, -sy, tol))
     225           0 :         || (SkScalarNearlyEqual(mx, -my, tol) && SkScalarNearlyEqual(sx, sy, tol));
     226             : }
     227             : 
     228           0 : bool SkMatrix::preservesRightAngles(SkScalar tol) const {
     229           0 :     TypeMask mask = this->getType();
     230             : 
     231           0 :     if (mask <= kTranslate_Mask) {
     232             :         // identity, translate and/or scale
     233           0 :         return true;
     234             :     }
     235           0 :     if (mask & kPerspective_Mask) {
     236           0 :         return false;
     237             :     }
     238             : 
     239           0 :     SkASSERT(mask & (kAffine_Mask | kScale_Mask));
     240             : 
     241           0 :     SkScalar mx = fMat[kMScaleX];
     242           0 :     SkScalar my = fMat[kMScaleY];
     243           0 :     SkScalar sx = fMat[kMSkewX];
     244           0 :     SkScalar sy = fMat[kMSkewY];
     245             : 
     246           0 :     if (is_degenerate_2x2(mx, sx, sy, my)) {
     247           0 :         return false;
     248             :     }
     249             : 
     250             :     // upper 2x2 is scale + rotation/reflection if basis vectors are orthogonal
     251             :     SkVector vec[2];
     252           0 :     vec[0].set(mx, sy);
     253           0 :     vec[1].set(sx, my);
     254             : 
     255           0 :     return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol));
     256             : }
     257             : 
     258             : ///////////////////////////////////////////////////////////////////////////////
     259             : 
     260          86 : static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
     261          86 :     return a * b + c * d;
     262             : }
     263             : 
     264           0 : static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d,
     265             :                              SkScalar e, SkScalar f) {
     266           0 :     return a * b + c * d + e * f;
     267             : }
     268             : 
     269           0 : static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
     270           0 :     return a * b - c * d;
     271             : }
     272             : 
     273         227 : void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
     274         227 :     if ((dx != 0) | (dy != 0)) {
     275         223 :         fMat[kMTransX] = dx;
     276         223 :         fMat[kMTransY] = dy;
     277             : 
     278         223 :         fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
     279         223 :         fMat[kMSkewX]  = fMat[kMSkewY] =
     280         223 :         fMat[kMPersp0] = fMat[kMPersp1] = 0;
     281             : 
     282         223 :         this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
     283             :     } else {
     284           4 :         this->reset();
     285             :     }
     286         227 : }
     287             : 
     288          53 : void SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
     289          53 :     const unsigned mask = this->getType();
     290             : 
     291          53 :     if (mask <= kTranslate_Mask) {
     292          35 :         fMat[kMTransX] += dx;
     293          35 :         fMat[kMTransY] += dy;
     294          18 :     } else if (mask & kPerspective_Mask) {
     295             :         SkMatrix    m;
     296           0 :         m.setTranslate(dx, dy);
     297           0 :         this->preConcat(m);
     298           0 :         return;
     299             :     } else {
     300          18 :         fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
     301          18 :         fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
     302             :     }
     303          53 :     this->updateTranslateMask();
     304             : }
     305             : 
     306         591 : void SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
     307         591 :     if (this->hasPerspective()) {
     308             :         SkMatrix    m;
     309           0 :         m.setTranslate(dx, dy);
     310           0 :         this->postConcat(m);
     311             :     } else {
     312         591 :         fMat[kMTransX] += dx;
     313         591 :         fMat[kMTransY] += dy;
     314         591 :         this->updateTranslateMask();
     315             :     }
     316         591 : }
     317             : 
     318             : ///////////////////////////////////////////////////////////////////////////////
     319             : 
     320           0 : void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     321           0 :     if (1 == sx && 1 == sy) {
     322           0 :         this->reset();
     323             :     } else {
     324           0 :         this->setScaleTranslate(sx, sy, px - sx * px, py - sy * py);
     325             :     }
     326           0 : }
     327             : 
     328          48 : void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
     329          48 :     if (1 == sx && 1 == sy) {
     330           0 :         this->reset();
     331             :     } else {
     332          48 :         fMat[kMScaleX] = sx;
     333          48 :         fMat[kMScaleY] = sy;
     334          48 :         fMat[kMPersp2] = 1;
     335             : 
     336          48 :         fMat[kMTransX] = fMat[kMTransY] =
     337          48 :         fMat[kMSkewX]  = fMat[kMSkewY] =
     338          48 :         fMat[kMPersp0] = fMat[kMPersp1] = 0;
     339             : 
     340          48 :         this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
     341             :     }
     342          48 : }
     343             : 
     344           0 : bool SkMatrix::setIDiv(int divx, int divy) {
     345           0 :     if (!divx || !divy) {
     346           0 :         return false;
     347             :     }
     348           0 :     this->setScale(SkScalarInvert(divx), SkScalarInvert(divy));
     349           0 :     return true;
     350             : }
     351             : 
     352           0 : void SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     353           0 :     if (1 == sx && 1 == sy) {
     354           0 :         return;
     355             :     }
     356             : 
     357             :     SkMatrix    m;
     358           0 :     m.setScale(sx, sy, px, py);
     359           0 :     this->preConcat(m);
     360             : }
     361             : 
     362           0 : void SkMatrix::preScale(SkScalar sx, SkScalar sy) {
     363           0 :     if (1 == sx && 1 == sy) {
     364           0 :         return;
     365             :     }
     366             : 
     367             :     // the assumption is that these multiplies are very cheap, and that
     368             :     // a full concat and/or just computing the matrix type is more expensive.
     369             :     // Also, the fixed-point case checks for overflow, but the float doesn't,
     370             :     // so we can get away with these blind multiplies.
     371             : 
     372           0 :     fMat[kMScaleX] *= sx;
     373           0 :     fMat[kMSkewY]  *= sx;
     374           0 :     fMat[kMPersp0] *= sx;
     375             : 
     376           0 :     fMat[kMSkewX]  *= sy;
     377           0 :     fMat[kMScaleY] *= sy;
     378           0 :     fMat[kMPersp1] *= sy;
     379             : 
     380             :     // Attempt to simplify our type when applying an inverse scale.
     381             :     // TODO: The persp/affine preconditions are in place to keep the mask consistent with
     382             :     //       what computeTypeMask() would produce (persp/skew always implies kScale).
     383             :     //       We should investigate whether these flag dependencies are truly needed.
     384           0 :     if (fMat[kMScaleX] == 1 && fMat[kMScaleY] == 1
     385           0 :         && !(fTypeMask & (kPerspective_Mask | kAffine_Mask))) {
     386           0 :         this->clearTypeMask(kScale_Mask);
     387             :     } else {
     388           0 :         this->orTypeMask(kScale_Mask);
     389             :     }
     390             : }
     391             : 
     392           0 : void SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     393           0 :     if (1 == sx && 1 == sy) {
     394           0 :         return;
     395             :     }
     396             :     SkMatrix    m;
     397           0 :     m.setScale(sx, sy, px, py);
     398           0 :     this->postConcat(m);
     399             : }
     400             : 
     401          25 : void SkMatrix::postScale(SkScalar sx, SkScalar sy) {
     402          25 :     if (1 == sx && 1 == sy) {
     403           0 :         return;
     404             :     }
     405             :     SkMatrix    m;
     406          25 :     m.setScale(sx, sy);
     407          25 :     this->postConcat(m);
     408             : }
     409             : 
     410             : // this guy perhaps can go away, if we have a fract/high-precision way to
     411             : // scale matrices
     412          17 : bool SkMatrix::postIDiv(int divx, int divy) {
     413          17 :     if (divx == 0 || divy == 0) {
     414           0 :         return false;
     415             :     }
     416             : 
     417          17 :     const float invX = 1.f / divx;
     418          17 :     const float invY = 1.f / divy;
     419             : 
     420          17 :     fMat[kMScaleX] *= invX;
     421          17 :     fMat[kMSkewX]  *= invX;
     422          17 :     fMat[kMTransX] *= invX;
     423             : 
     424          17 :     fMat[kMScaleY] *= invY;
     425          17 :     fMat[kMSkewY]  *= invY;
     426          17 :     fMat[kMTransY] *= invY;
     427             : 
     428          17 :     this->setTypeMask(kUnknown_Mask);
     429          17 :     return true;
     430             : }
     431             : 
     432             : ////////////////////////////////////////////////////////////////////////////////////
     433             : 
     434          25 : void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, SkScalar px, SkScalar py) {
     435          25 :     const SkScalar oneMinusCosV = 1 - cosV;
     436             : 
     437          25 :     fMat[kMScaleX]  = cosV;
     438          25 :     fMat[kMSkewX]   = -sinV;
     439          25 :     fMat[kMTransX]  = sdot(sinV, py, oneMinusCosV, px);
     440             : 
     441          25 :     fMat[kMSkewY]   = sinV;
     442          25 :     fMat[kMScaleY]  = cosV;
     443          25 :     fMat[kMTransY]  = sdot(-sinV, px, oneMinusCosV, py);
     444             : 
     445          25 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     446          25 :     fMat[kMPersp2] = 1;
     447             : 
     448          25 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     449          25 : }
     450             : 
     451           0 : SkMatrix& SkMatrix::setRSXform(const SkRSXform& xform) {
     452           0 :     fMat[kMScaleX]  = xform.fSCos;
     453           0 :     fMat[kMSkewX]   = -xform.fSSin;
     454           0 :     fMat[kMTransX]  = xform.fTx;
     455             : 
     456           0 :     fMat[kMSkewY]   = xform.fSSin;
     457           0 :     fMat[kMScaleY]  = xform.fSCos;
     458           0 :     fMat[kMTransY]  = xform.fTy;
     459             : 
     460           0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     461           0 :     fMat[kMPersp2] = 1;
     462             : 
     463           0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     464           0 :     return *this;
     465             : }
     466             : 
     467           0 : void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
     468           0 :     fMat[kMScaleX]  = cosV;
     469           0 :     fMat[kMSkewX]   = -sinV;
     470           0 :     fMat[kMTransX]  = 0;
     471             : 
     472           0 :     fMat[kMSkewY]   = sinV;
     473           0 :     fMat[kMScaleY]  = cosV;
     474           0 :     fMat[kMTransY]  = 0;
     475             : 
     476           0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     477           0 :     fMat[kMPersp2] = 1;
     478             : 
     479           0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     480           0 : }
     481             : 
     482           0 : void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
     483             :     SkScalar sinV, cosV;
     484           0 :     sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
     485           0 :     this->setSinCos(sinV, cosV, px, py);
     486           0 : }
     487             : 
     488           0 : void SkMatrix::setRotate(SkScalar degrees) {
     489             :     SkScalar sinV, cosV;
     490           0 :     sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
     491           0 :     this->setSinCos(sinV, cosV);
     492           0 : }
     493             : 
     494           0 : void SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
     495             :     SkMatrix    m;
     496           0 :     m.setRotate(degrees, px, py);
     497           0 :     this->preConcat(m);
     498           0 : }
     499             : 
     500           0 : void SkMatrix::preRotate(SkScalar degrees) {
     501             :     SkMatrix    m;
     502           0 :     m.setRotate(degrees);
     503           0 :     this->preConcat(m);
     504           0 : }
     505             : 
     506           0 : void SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
     507             :     SkMatrix    m;
     508           0 :     m.setRotate(degrees, px, py);
     509           0 :     this->postConcat(m);
     510           0 : }
     511             : 
     512           0 : void SkMatrix::postRotate(SkScalar degrees) {
     513             :     SkMatrix    m;
     514           0 :     m.setRotate(degrees);
     515           0 :     this->postConcat(m);
     516           0 : }
     517             : 
     518             : ////////////////////////////////////////////////////////////////////////////////////
     519             : 
     520           0 : void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     521           0 :     fMat[kMScaleX]  = 1;
     522           0 :     fMat[kMSkewX]   = sx;
     523           0 :     fMat[kMTransX]  = -sx * py;
     524             : 
     525           0 :     fMat[kMSkewY]   = sy;
     526           0 :     fMat[kMScaleY]  = 1;
     527           0 :     fMat[kMTransY]  = -sy * px;
     528             : 
     529           0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     530           0 :     fMat[kMPersp2] = 1;
     531             : 
     532           0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     533           0 : }
     534             : 
     535           0 : void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
     536           0 :     fMat[kMScaleX]  = 1;
     537           0 :     fMat[kMSkewX]   = sx;
     538           0 :     fMat[kMTransX]  = 0;
     539             : 
     540           0 :     fMat[kMSkewY]   = sy;
     541           0 :     fMat[kMScaleY]  = 1;
     542           0 :     fMat[kMTransY]  = 0;
     543             : 
     544           0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     545           0 :     fMat[kMPersp2] = 1;
     546             : 
     547           0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     548           0 : }
     549             : 
     550           0 : void SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     551             :     SkMatrix    m;
     552           0 :     m.setSkew(sx, sy, px, py);
     553           0 :     this->preConcat(m);
     554           0 : }
     555             : 
     556           0 : void SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
     557             :     SkMatrix    m;
     558           0 :     m.setSkew(sx, sy);
     559           0 :     this->preConcat(m);
     560           0 : }
     561             : 
     562           0 : void SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     563             :     SkMatrix    m;
     564           0 :     m.setSkew(sx, sy, px, py);
     565           0 :     this->postConcat(m);
     566           0 : }
     567             : 
     568           0 : void SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
     569             :     SkMatrix    m;
     570           0 :     m.setSkew(sx, sy);
     571           0 :     this->postConcat(m);
     572           0 : }
     573             : 
     574             : ///////////////////////////////////////////////////////////////////////////////
     575             : 
     576         140 : bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit align) {
     577         140 :     if (src.isEmpty()) {
     578           0 :         this->reset();
     579           0 :         return false;
     580             :     }
     581             : 
     582         140 :     if (dst.isEmpty()) {
     583           0 :         sk_bzero(fMat, 8 * sizeof(SkScalar));
     584           0 :         fMat[kMPersp2] = 1;
     585           0 :         this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
     586             :     } else {
     587         140 :         SkScalar    tx, sx = dst.width() / src.width();
     588         140 :         SkScalar    ty, sy = dst.height() / src.height();
     589         140 :         bool        xLarger = false;
     590             : 
     591         140 :         if (align != kFill_ScaleToFit) {
     592           0 :             if (sx > sy) {
     593           0 :                 xLarger = true;
     594           0 :                 sx = sy;
     595             :             } else {
     596           0 :                 sy = sx;
     597             :             }
     598             :         }
     599             : 
     600         140 :         tx = dst.fLeft - src.fLeft * sx;
     601         140 :         ty = dst.fTop - src.fTop * sy;
     602         140 :         if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
     603             :             SkScalar diff;
     604             : 
     605           0 :             if (xLarger) {
     606           0 :                 diff = dst.width() - src.width() * sy;
     607             :             } else {
     608           0 :                 diff = dst.height() - src.height() * sy;
     609             :             }
     610             : 
     611           0 :             if (align == kCenter_ScaleToFit) {
     612           0 :                 diff = SkScalarHalf(diff);
     613             :             }
     614             : 
     615           0 :             if (xLarger) {
     616           0 :                 tx += diff;
     617             :             } else {
     618           0 :                 ty += diff;
     619             :             }
     620             :         }
     621             : 
     622         140 :         this->setScaleTranslate(sx, sy, tx, ty);
     623             :     }
     624         140 :     return true;
     625             : }
     626             : 
     627             : ///////////////////////////////////////////////////////////////////////////////
     628             : 
     629         276 : static inline float muladdmul(float a, float b, float c, float d) {
     630         276 :     return SkDoubleToFloat((double)a * b + (double)c * d);
     631             : }
     632             : 
     633           0 : static inline float rowcol3(const float row[], const float col[]) {
     634           0 :     return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
     635             : }
     636             : 
     637         127 : static bool only_scale_and_translate(unsigned mask) {
     638         127 :     return 0 == (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask));
     639             : }
     640             : 
     641         843 : void SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
     642         843 :     TypeMask aType = a.getType();
     643         843 :     TypeMask bType = b.getType();
     644             : 
     645         843 :     if (a.isTriviallyIdentity()) {
     646         359 :         *this = b;
     647         484 :     } else if (b.isTriviallyIdentity()) {
     648         357 :         *this = a;
     649         127 :     } else if (only_scale_and_translate(aType | bType)) {
     650         243 :         this->setScaleTranslate(a.fMat[kMScaleX] * b.fMat[kMScaleX],
     651          81 :                                 a.fMat[kMScaleY] * b.fMat[kMScaleY],
     652          81 :                                 a.fMat[kMScaleX] * b.fMat[kMTransX] + a.fMat[kMTransX],
     653         162 :                                 a.fMat[kMScaleY] * b.fMat[kMTransY] + a.fMat[kMTransY]);
     654             :     } else {
     655             :         SkMatrix tmp;
     656             : 
     657          46 :         if ((aType | bType) & kPerspective_Mask) {
     658           0 :             tmp.fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
     659           0 :             tmp.fMat[kMSkewX]  = rowcol3(&a.fMat[0], &b.fMat[1]);
     660           0 :             tmp.fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
     661           0 :             tmp.fMat[kMSkewY]  = rowcol3(&a.fMat[3], &b.fMat[0]);
     662           0 :             tmp.fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
     663           0 :             tmp.fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
     664           0 :             tmp.fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
     665           0 :             tmp.fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
     666           0 :             tmp.fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
     667             : 
     668           0 :             normalize_perspective(tmp.fMat);
     669           0 :             tmp.setTypeMask(kUnknown_Mask);
     670             :         } else {
     671          46 :             tmp.fMat[kMScaleX] = muladdmul(a.fMat[kMScaleX],
     672          46 :                                            b.fMat[kMScaleX],
     673          46 :                                            a.fMat[kMSkewX],
     674          46 :                                            b.fMat[kMSkewY]);
     675             : 
     676          46 :             tmp.fMat[kMSkewX]  = muladdmul(a.fMat[kMScaleX],
     677          46 :                                            b.fMat[kMSkewX],
     678          46 :                                            a.fMat[kMSkewX],
     679          46 :                                            b.fMat[kMScaleY]);
     680             : 
     681          92 :             tmp.fMat[kMTransX] = muladdmul(a.fMat[kMScaleX],
     682          46 :                                            b.fMat[kMTransX],
     683          46 :                                            a.fMat[kMSkewX],
     684          92 :                                            b.fMat[kMTransY]) + a.fMat[kMTransX];
     685             : 
     686          46 :             tmp.fMat[kMSkewY]  = muladdmul(a.fMat[kMSkewY],
     687          46 :                                            b.fMat[kMScaleX],
     688          46 :                                            a.fMat[kMScaleY],
     689          46 :                                            b.fMat[kMSkewY]);
     690             : 
     691          46 :             tmp.fMat[kMScaleY] = muladdmul(a.fMat[kMSkewY],
     692          46 :                                            b.fMat[kMSkewX],
     693          46 :                                            a.fMat[kMScaleY],
     694          46 :                                            b.fMat[kMScaleY]);
     695             : 
     696          92 :             tmp.fMat[kMTransY] = muladdmul(a.fMat[kMSkewY],
     697          46 :                                            b.fMat[kMTransX],
     698          46 :                                            a.fMat[kMScaleY],
     699          92 :                                            b.fMat[kMTransY]) + a.fMat[kMTransY];
     700             : 
     701          46 :             tmp.fMat[kMPersp0] = 0;
     702          46 :             tmp.fMat[kMPersp1] = 0;
     703          46 :             tmp.fMat[kMPersp2] = 1;
     704             :             //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
     705             :             //SkASSERT(!(tmp.getType() & kPerspective_Mask));
     706          46 :             tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     707             :         }
     708          46 :         *this = tmp;
     709             :     }
     710         843 : }
     711             : 
     712           0 : void SkMatrix::preConcat(const SkMatrix& mat) {
     713             :     // check for identity first, so we don't do a needless copy of ourselves
     714             :     // to ourselves inside setConcat()
     715           0 :     if(!mat.isIdentity()) {
     716           0 :         this->setConcat(*this, mat);
     717             :     }
     718           0 : }
     719             : 
     720          30 : void SkMatrix::postConcat(const SkMatrix& mat) {
     721             :     // check for identity first, so we don't do a needless copy of ourselves
     722             :     // to ourselves inside setConcat()
     723          30 :     if (!mat.isIdentity()) {
     724          28 :         this->setConcat(mat, *this);
     725             :     }
     726          30 : }
     727             : 
     728             : ///////////////////////////////////////////////////////////////////////////////
     729             : 
     730             : /*  Matrix inversion is very expensive, but also the place where keeping
     731             :     precision may be most important (here and matrix concat). Hence to avoid
     732             :     bitmap blitting artifacts when walking the inverse, we use doubles for
     733             :     the intermediate math, even though we know that is more expensive.
     734             :  */
     735             : 
     736           0 : static inline SkScalar scross_dscale(SkScalar a, SkScalar b,
     737             :                                      SkScalar c, SkScalar d, double scale) {
     738           0 :     return SkDoubleToScalar(scross(a, b, c, d) * scale);
     739             : }
     740             : 
     741           0 : static inline double dcross(double a, double b, double c, double d) {
     742           0 :     return a * b - c * d;
     743             : }
     744             : 
     745           0 : static inline SkScalar dcross_dscale(double a, double b,
     746             :                                      double c, double d, double scale) {
     747           0 :     return SkDoubleToScalar(dcross(a, b, c, d) * scale);
     748             : }
     749             : 
     750           0 : static double sk_inv_determinant(const float mat[9], int isPerspective) {
     751             :     double det;
     752             : 
     753           0 :     if (isPerspective) {
     754           0 :         det = mat[SkMatrix::kMScaleX] *
     755           0 :               dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2],
     756           0 :                      mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1])
     757           0 :               +
     758           0 :               mat[SkMatrix::kMSkewX]  *
     759           0 :               dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0],
     760           0 :                      mat[SkMatrix::kMSkewY],  mat[SkMatrix::kMPersp2])
     761             :               +
     762           0 :               mat[SkMatrix::kMTransX] *
     763           0 :               dcross(mat[SkMatrix::kMSkewY],  mat[SkMatrix::kMPersp1],
     764           0 :                      mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]);
     765             :     } else {
     766           0 :         det = dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY],
     767           0 :                      mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
     768             :     }
     769             : 
     770             :     // Since the determinant is on the order of the cube of the matrix members,
     771             :     // compare to the cube of the default nearly-zero constant (although an
     772             :     // estimate of the condition number would be better if it wasn't so expensive).
     773           0 :     if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
     774           0 :         return 0;
     775             :     }
     776           0 :     return 1.0 / det;
     777             : }
     778             : 
     779           0 : void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
     780           0 :     affine[kAScaleX] = 1;
     781           0 :     affine[kASkewY] = 0;
     782           0 :     affine[kASkewX] = 0;
     783           0 :     affine[kAScaleY] = 1;
     784           0 :     affine[kATransX] = 0;
     785           0 :     affine[kATransY] = 0;
     786           0 : }
     787             : 
     788           0 : bool SkMatrix::asAffine(SkScalar affine[6]) const {
     789           0 :     if (this->hasPerspective()) {
     790           0 :         return false;
     791             :     }
     792           0 :     if (affine) {
     793           0 :         affine[kAScaleX] = this->fMat[kMScaleX];
     794           0 :         affine[kASkewY] = this->fMat[kMSkewY];
     795           0 :         affine[kASkewX] = this->fMat[kMSkewX];
     796           0 :         affine[kAScaleY] = this->fMat[kMScaleY];
     797           0 :         affine[kATransX] = this->fMat[kMTransX];
     798           0 :         affine[kATransY] = this->fMat[kMTransY];
     799             :     }
     800           0 :     return true;
     801             : }
     802             : 
     803           0 : void SkMatrix::ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp) {
     804           0 :     SkASSERT(src != dst);
     805           0 :     SkASSERT(src && dst);
     806             : 
     807           0 :     if (isPersp) {
     808           0 :         dst[kMScaleX] = scross_dscale(src[kMScaleY], src[kMPersp2], src[kMTransY], src[kMPersp1], invDet);
     809           0 :         dst[kMSkewX]  = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX],  src[kMPersp2], invDet);
     810           0 :         dst[kMTransX] = scross_dscale(src[kMSkewX],  src[kMTransY], src[kMTransX], src[kMScaleY], invDet);
     811             : 
     812           0 :         dst[kMSkewY]  = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY],  src[kMPersp2], invDet);
     813           0 :         dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX], src[kMPersp0], invDet);
     814           0 :         dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY],  src[kMScaleX], src[kMTransY], invDet);
     815             : 
     816           0 :         dst[kMPersp0] = scross_dscale(src[kMSkewY],  src[kMPersp1], src[kMScaleY], src[kMPersp0], invDet);
     817           0 :         dst[kMPersp1] = scross_dscale(src[kMSkewX],  src[kMPersp0], src[kMScaleX], src[kMPersp1], invDet);
     818           0 :         dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX],  src[kMSkewY],  invDet);
     819             :     } else {   // not perspective
     820           0 :         dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * invDet);
     821           0 :         dst[kMSkewX]  = SkDoubleToScalar(-src[kMSkewX] * invDet);
     822           0 :         dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY], src[kMTransX], invDet);
     823             : 
     824           0 :         dst[kMSkewY]  = SkDoubleToScalar(-src[kMSkewY] * invDet);
     825           0 :         dst[kMScaleY] = SkDoubleToScalar(src[kMScaleX] * invDet);
     826           0 :         dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX], src[kMTransY], invDet);
     827             : 
     828           0 :         dst[kMPersp0] = 0;
     829           0 :         dst[kMPersp1] = 0;
     830           0 :         dst[kMPersp2] = 1;
     831             :     }
     832           0 : }
     833             : 
     834         516 : bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
     835         516 :     SkASSERT(!this->isIdentity());
     836             : 
     837         516 :     TypeMask mask = this->getType();
     838             : 
     839         516 :     if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
     840         516 :         bool invertible = true;
     841         516 :         if (inv) {
     842         350 :             if (mask & kScale_Mask) {
     843         135 :                 SkScalar invX = fMat[kMScaleX];
     844         135 :                 SkScalar invY = fMat[kMScaleY];
     845         135 :                 if (0 == invX || 0 == invY) {
     846           0 :                     return false;
     847             :                 }
     848         135 :                 invX = SkScalarInvert(invX);
     849         135 :                 invY = SkScalarInvert(invY);
     850             : 
     851             :                 // Must be careful when writing to inv, since it may be the
     852             :                 // same memory as this.
     853             : 
     854         135 :                 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
     855         135 :                 inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
     856             : 
     857         135 :                 inv->fMat[kMScaleX] = invX;
     858         135 :                 inv->fMat[kMScaleY] = invY;
     859         135 :                 inv->fMat[kMPersp2] = 1;
     860         135 :                 inv->fMat[kMTransX] = -fMat[kMTransX] * invX;
     861         135 :                 inv->fMat[kMTransY] = -fMat[kMTransY] * invY;
     862             : 
     863         135 :                 inv->setTypeMask(mask | kRectStaysRect_Mask);
     864             :             } else {
     865             :                 // translate only
     866         215 :                 inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
     867             :             }
     868             :         } else {    // inv is nullptr, just check if we're invertible
     869         166 :             if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
     870           0 :                 invertible = false;
     871             :             }
     872             :         }
     873         516 :         return invertible;
     874             :     }
     875             : 
     876           0 :     int    isPersp = mask & kPerspective_Mask;
     877           0 :     double invDet = sk_inv_determinant(fMat, isPersp);
     878             : 
     879           0 :     if (invDet == 0) { // underflow
     880           0 :         return false;
     881             :     }
     882             : 
     883           0 :     bool applyingInPlace = (inv == this);
     884             : 
     885           0 :     SkMatrix* tmp = inv;
     886             : 
     887             :     SkMatrix storage;
     888           0 :     if (applyingInPlace || nullptr == tmp) {
     889           0 :         tmp = &storage;     // we either need to avoid trampling memory or have no memory
     890             :     }
     891             : 
     892           0 :     ComputeInv(tmp->fMat, fMat, invDet, isPersp);
     893           0 :     if (!tmp->isFinite()) {
     894           0 :         return false;
     895             :     }
     896             : 
     897           0 :     tmp->setTypeMask(fTypeMask);
     898             : 
     899           0 :     if (applyingInPlace) {
     900           0 :         *inv = storage; // need to copy answer back
     901             :     }
     902             : 
     903           0 :     return true;
     904             : }
     905             : 
     906             : ///////////////////////////////////////////////////////////////////////////////
     907             : 
     908         137 : void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
     909         137 :     SkASSERT(m.getType() == 0);
     910             : 
     911         137 :     if (dst != src && count > 0) {
     912         137 :         memcpy(dst, src, count * sizeof(SkPoint));
     913             :     }
     914         137 : }
     915             : 
     916         114 : void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
     917         114 :     SkASSERT(m.getType() <= SkMatrix::kTranslate_Mask);
     918         114 :     if (count > 0) {
     919         114 :         SkScalar tx = m.getTranslateX();
     920         114 :         SkScalar ty = m.getTranslateY();
     921         114 :         if (count & 1) {
     922          19 :             dst->fX = src->fX + tx;
     923          19 :             dst->fY = src->fY + ty;
     924          19 :             src += 1;
     925          19 :             dst += 1;
     926             :         }
     927             :         Sk4s trans4(tx, ty, tx, ty);
     928         114 :         count >>= 1;
     929         114 :         if (count & 1) {
     930         276 :             (Sk4s::Load(src) + trans4).store(dst);
     931          92 :             src += 2;
     932          92 :             dst += 2;
     933             :         }
     934         114 :         count >>= 1;
     935         223 :         for (int i = 0; i < count; ++i) {
     936         327 :             (Sk4s::Load(src+0) + trans4).store(dst+0);
     937         436 :             (Sk4s::Load(src+2) + trans4).store(dst+2);
     938         109 :             src += 4;
     939         109 :             dst += 4;
     940             :         }
     941             :     }
     942         114 : }
     943             : 
     944          67 : void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
     945          67 :     SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
     946          67 :     if (count > 0) {
     947          67 :         SkScalar tx = m.getTranslateX();
     948          67 :         SkScalar ty = m.getTranslateY();
     949          67 :         SkScalar sx = m.getScaleX();
     950          67 :         SkScalar sy = m.getScaleY();
     951          67 :         if (count & 1) {
     952          16 :             dst->fX = src->fX * sx + tx;
     953          16 :             dst->fY = src->fY * sy + ty;
     954          16 :             src += 1;
     955          16 :             dst += 1;
     956             :         }
     957             :         Sk4s trans4(tx, ty, tx, ty);
     958             :         Sk4s scale4(sx, sy, sx, sy);
     959          67 :         count >>= 1;
     960          67 :         if (count & 1) {
     961         196 :             (Sk4s::Load(src) * scale4 + trans4).store(dst);
     962          49 :             src += 2;
     963          49 :             dst += 2;
     964             :         }
     965          67 :         count >>= 1;
     966         274 :         for (int i = 0; i < count; ++i) {
     967         828 :             (Sk4s::Load(src+0) * scale4 + trans4).store(dst+0);
     968        1035 :             (Sk4s::Load(src+2) * scale4 + trans4).store(dst+2);
     969         207 :             src += 4;
     970         207 :             dst += 4;
     971             :         }
     972             :     }
     973          67 : }
     974             : 
     975           0 : void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
     976             :                          const SkPoint src[], int count) {
     977           0 :     SkASSERT(m.hasPerspective());
     978             : 
     979           0 :     if (count > 0) {
     980           0 :         do {
     981           0 :             SkScalar sy = src->fY;
     982           0 :             SkScalar sx = src->fX;
     983           0 :             src += 1;
     984             : 
     985           0 :             SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
     986           0 :             SkScalar y = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
     987             : #ifdef SK_LEGACY_MATRIX_MATH_ORDER
     988           0 :             SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]);
     989             : #else
     990             :             SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
     991             : #endif
     992           0 :             if (z) {
     993           0 :                 z = SkScalarFastInvert(z);
     994             :             }
     995             : 
     996           0 :             dst->fY = y * z;
     997           0 :             dst->fX = x * z;
     998           0 :             dst += 1;
     999             :         } while (--count);
    1000             :     }
    1001           0 : }
    1002             : 
    1003           0 : void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
    1004           0 :     SkASSERT(m.getType() != SkMatrix::kPerspective_Mask);
    1005           0 :     if (count > 0) {
    1006           0 :         SkScalar tx = m.getTranslateX();
    1007           0 :         SkScalar ty = m.getTranslateY();
    1008           0 :         SkScalar sx = m.getScaleX();
    1009           0 :         SkScalar sy = m.getScaleY();
    1010           0 :         SkScalar kx = m.getSkewX();
    1011           0 :         SkScalar ky = m.getSkewY();
    1012           0 :         if (count & 1) {
    1013           0 :             dst->set(src->fX * sx + src->fY * kx + tx,
    1014           0 :                      src->fX * ky + src->fY * sy + ty);
    1015           0 :             src += 1;
    1016           0 :             dst += 1;
    1017             :         }
    1018             :         Sk4s trans4(tx, ty, tx, ty);
    1019             :         Sk4s scale4(sx, sy, sx, sy);
    1020             :         Sk4s  skew4(kx, ky, kx, ky);    // applied to swizzle of src4
    1021           0 :         count >>= 1;
    1022           0 :         for (int i = 0; i < count; ++i) {
    1023           0 :             Sk4s src4 = Sk4s::Load(src);
    1024           0 :             Sk4s swz4 = SkNx_shuffle<1,0,3,2>(src4);  // y0 x0, y1 x1
    1025           0 :             (src4 * scale4 + swz4 * skew4 + trans4).store(dst);
    1026           0 :             src += 2;
    1027           0 :             dst += 2;
    1028             :         }
    1029             :     }
    1030           0 : }
    1031             : 
    1032             : const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
    1033             :     SkMatrix::Identity_pts, SkMatrix::Trans_pts,
    1034             :     SkMatrix::Scale_pts,    SkMatrix::Scale_pts,
    1035             :     SkMatrix::Affine_vpts,  SkMatrix::Affine_vpts,
    1036             :     SkMatrix::Affine_vpts,  SkMatrix::Affine_vpts,
    1037             :     // repeat the persp proc 8 times
    1038             :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
    1039             :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
    1040             :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
    1041             :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts
    1042             : };
    1043             : 
    1044             : ///////////////////////////////////////////////////////////////////////////////
    1045             : 
    1046           0 : void SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const {
    1047           0 :     SkASSERT((dst && src && count > 0) || 0 == count);
    1048             :     // no partial overlap
    1049           0 :     SkASSERT(src == dst || &dst[3*count] <= &src[0] || &src[3*count] <= &dst[0]);
    1050             : 
    1051           0 :     if (count > 0) {
    1052           0 :         if (this->isIdentity()) {
    1053           0 :             memcpy(dst, src, 3*count*sizeof(SkScalar));
    1054           0 :             return;
    1055             :         }
    1056           0 :         do {
    1057           0 :             SkScalar sx = src[0];
    1058           0 :             SkScalar sy = src[1];
    1059           0 :             SkScalar sw = src[2];
    1060           0 :             src += 3;
    1061             : 
    1062           0 :             SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX],  sw, fMat[kMTransX]);
    1063           0 :             SkScalar y = sdot(sx, fMat[kMSkewY],  sy, fMat[kMScaleY], sw, fMat[kMTransY]);
    1064           0 :             SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]);
    1065             : 
    1066           0 :             dst[0] = x;
    1067           0 :             dst[1] = y;
    1068           0 :             dst[2] = w;
    1069           0 :             dst += 3;
    1070             :         } while (--count);
    1071             :     }
    1072             : }
    1073             : 
    1074             : ///////////////////////////////////////////////////////////////////////////////
    1075             : 
    1076          15 : void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
    1077          15 :     if (this->hasPerspective()) {
    1078             :         SkPoint origin;
    1079             : 
    1080           0 :         MapXYProc proc = this->getMapXYProc();
    1081           0 :         proc(*this, 0, 0, &origin);
    1082             : 
    1083           0 :         for (int i = count - 1; i >= 0; --i) {
    1084             :             SkPoint tmp;
    1085             : 
    1086           0 :             proc(*this, src[i].fX, src[i].fY, &tmp);
    1087           0 :             dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
    1088             :         }
    1089             :     } else {
    1090          15 :         SkMatrix tmp = *this;
    1091             : 
    1092          15 :         tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
    1093          15 :         tmp.clearTypeMask(kTranslate_Mask);
    1094          15 :         tmp.mapPoints(dst, src, count);
    1095             :     }
    1096          15 : }
    1097             : 
    1098        1427 : static Sk4f sort_as_rect(const Sk4f& ltrb) {
    1099        5708 :     Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
    1100        1427 :     Sk4f min = Sk4f::Min(ltrb, rblt);
    1101        1427 :     Sk4f max = Sk4f::Max(ltrb, rblt);
    1102             :     // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
    1103             :     // ARM this sequence generates the fastest (a single instruction).
    1104        7135 :     return Sk4f(min[2], min[3], max[0], max[1]);
    1105             : }
    1106             : 
    1107          62 : void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
    1108          62 :     SkASSERT(dst);
    1109          62 :     SkASSERT(this->isScaleTranslate());
    1110             : 
    1111          62 :     SkScalar sx = fMat[kMScaleX];
    1112          62 :     SkScalar sy = fMat[kMScaleY];
    1113          62 :     SkScalar tx = fMat[kMTransX];
    1114          62 :     SkScalar ty = fMat[kMTransY];
    1115             :     Sk4f scale(sx, sy, sx, sy);
    1116             :     Sk4f trans(tx, ty, tx, ty);
    1117         310 :     sort_as_rect(Sk4f::Load(&src.fLeft) * scale + trans).store(&dst->fLeft);
    1118          62 : }
    1119             : 
    1120        1427 : bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
    1121        1427 :     SkASSERT(dst);
    1122             : 
    1123        1427 :     if (this->getType() <= kTranslate_Mask) {
    1124        1365 :         SkScalar tx = fMat[kMTransX];
    1125        1365 :         SkScalar ty = fMat[kMTransY];
    1126             :         Sk4f trans(tx, ty, tx, ty);
    1127        5460 :         sort_as_rect(Sk4f::Load(&src.fLeft) + trans).store(&dst->fLeft);
    1128        1365 :         return true;
    1129             :     }
    1130          62 :     if (this->isScaleTranslate()) {
    1131          62 :         this->mapRectScaleTranslate(dst, src);
    1132          62 :         return true;
    1133             :     } else {
    1134             :         SkPoint quad[4];
    1135             : 
    1136           0 :         src.toQuad(quad);
    1137           0 :         this->mapPoints(quad, quad, 4);
    1138           0 :         dst->set(quad, 4);
    1139           0 :         return false;
    1140             :     }
    1141             : }
    1142             : 
    1143           0 : SkScalar SkMatrix::mapRadius(SkScalar radius) const {
    1144             :     SkVector    vec[2];
    1145             : 
    1146           0 :     vec[0].set(radius, 0);
    1147           0 :     vec[1].set(0, radius);
    1148           0 :     this->mapVectors(vec, 2);
    1149             : 
    1150           0 :     SkScalar d0 = vec[0].length();
    1151           0 :     SkScalar d1 = vec[1].length();
    1152             : 
    1153             :     // return geometric mean
    1154           0 :     return SkScalarSqrt(d0 * d1);
    1155             : }
    1156             : 
    1157             : ///////////////////////////////////////////////////////////////////////////////
    1158             : 
    1159           0 : void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1160             :                         SkPoint* pt) {
    1161           0 :     SkASSERT(m.hasPerspective());
    1162             : 
    1163           0 :     SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
    1164           0 :     SkScalar y = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
    1165           0 :     SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
    1166           0 :     if (z) {
    1167           0 :         z = SkScalarFastInvert(z);
    1168             :     }
    1169           0 :     pt->fX = x * z;
    1170           0 :     pt->fY = y * z;
    1171           0 : }
    1172             : 
    1173        3335 : void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1174             :                            SkPoint* pt) {
    1175        3335 :     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
    1176             : 
    1177             : #ifdef SK_LEGACY_MATRIX_MATH_ORDER
    1178        3335 :     pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX]  +  m.fMat[kMTransX]);
    1179        3335 :     pt->fY = sx * m.fMat[kMSkewY]  + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
    1180             : #else
    1181             :     pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
    1182             :     pt->fY = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
    1183             : #endif
    1184        3335 : }
    1185             : 
    1186           0 : void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1187             :                       SkPoint* pt) {
    1188           0 :     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
    1189           0 :     SkASSERT(0 == m.fMat[kMTransX]);
    1190           0 :     SkASSERT(0 == m.fMat[kMTransY]);
    1191             : 
    1192             : #ifdef SK_LEGACY_MATRIX_MATH_ORDER
    1193           0 :     pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX]  + m.fMat[kMTransX]);
    1194           0 :     pt->fY = sx * m.fMat[kMSkewY]  + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
    1195             : #else
    1196             :     pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX])  + m.fMat[kMTransX];
    1197             :     pt->fY = sdot(sx, m.fMat[kMSkewY],  sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
    1198             : #endif
    1199           0 : }
    1200             : 
    1201        1404 : void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1202             :                              SkPoint* pt) {
    1203        1404 :     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
    1204             :              == kScale_Mask);
    1205             : 
    1206        1404 :     pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
    1207        1404 :     pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
    1208        1404 : }
    1209             : 
    1210           0 : void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1211             :                         SkPoint* pt) {
    1212           0 :     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
    1213             :              == kScale_Mask);
    1214           0 :     SkASSERT(0 == m.fMat[kMTransX]);
    1215           0 :     SkASSERT(0 == m.fMat[kMTransY]);
    1216             : 
    1217           0 :     pt->fX = sx * m.fMat[kMScaleX];
    1218           0 :     pt->fY = sy * m.fMat[kMScaleY];
    1219           0 : }
    1220             : 
    1221        1801 : void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1222             :                         SkPoint* pt) {
    1223        1801 :     SkASSERT(m.getType() == kTranslate_Mask);
    1224             : 
    1225        1801 :     pt->fX = sx + m.fMat[kMTransX];
    1226        1801 :     pt->fY = sy + m.fMat[kMTransY];
    1227        1801 : }
    1228             : 
    1229         226 : void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1230             :                            SkPoint* pt) {
    1231         226 :     SkASSERT(0 == m.getType());
    1232             : 
    1233         226 :     pt->fX = sx;
    1234         226 :     pt->fY = sy;
    1235         226 : }
    1236             : 
    1237             : const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
    1238             :     SkMatrix::Identity_xy, SkMatrix::Trans_xy,
    1239             :     SkMatrix::Scale_xy,    SkMatrix::ScaleTrans_xy,
    1240             :     SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
    1241             :     SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
    1242             :     // repeat the persp proc 8 times
    1243             :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
    1244             :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
    1245             :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
    1246             :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy
    1247             : };
    1248             : 
    1249             : ///////////////////////////////////////////////////////////////////////////////
    1250             : 
    1251             : // if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
    1252             : #define PerspNearlyZero(x)  SkScalarNearlyZero(x, (1.0f / (1 << 26)))
    1253             : 
    1254           0 : bool SkMatrix::isFixedStepInX() const {
    1255           0 :   return PerspNearlyZero(fMat[kMPersp0]);
    1256             : }
    1257             : 
    1258           0 : SkVector SkMatrix::fixedStepInX(SkScalar y) const {
    1259           0 :     SkASSERT(PerspNearlyZero(fMat[kMPersp0]));
    1260           0 :     if (PerspNearlyZero(fMat[kMPersp1]) &&
    1261           0 :         PerspNearlyZero(fMat[kMPersp2] - 1)) {
    1262           0 :         return SkVector::Make(fMat[kMScaleX], fMat[kMSkewY]);
    1263             :     } else {
    1264           0 :         SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
    1265           0 :         return SkVector::Make(fMat[kMScaleX] / z, fMat[kMSkewY] / z);
    1266             :     }
    1267             : }
    1268             : 
    1269             : ///////////////////////////////////////////////////////////////////////////////
    1270             : 
    1271             : #include "SkPerspIter.h"
    1272             : 
    1273           0 : SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
    1274           0 :         : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
    1275             :     SkPoint pt;
    1276             : 
    1277           0 :     SkMatrix::Persp_xy(m, x0, y0, &pt);
    1278           0 :     fX = SkScalarToFixed(pt.fX);
    1279           0 :     fY = SkScalarToFixed(pt.fY);
    1280           0 : }
    1281             : 
    1282           0 : int SkPerspIter::next() {
    1283           0 :     int n = fCount;
    1284             : 
    1285           0 :     if (0 == n) {
    1286           0 :         return 0;
    1287             :     }
    1288             :     SkPoint pt;
    1289           0 :     SkFixed x = fX;
    1290           0 :     SkFixed y = fY;
    1291             :     SkFixed dx, dy;
    1292             : 
    1293           0 :     if (n >= kCount) {
    1294           0 :         n = kCount;
    1295           0 :         fSX += SkIntToScalar(kCount);
    1296           0 :         SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
    1297           0 :         fX = SkScalarToFixed(pt.fX);
    1298           0 :         fY = SkScalarToFixed(pt.fY);
    1299           0 :         dx = (fX - x) >> kShift;
    1300           0 :         dy = (fY - y) >> kShift;
    1301             :     } else {
    1302           0 :         fSX += SkIntToScalar(n);
    1303           0 :         SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
    1304           0 :         fX = SkScalarToFixed(pt.fX);
    1305           0 :         fY = SkScalarToFixed(pt.fY);
    1306           0 :         dx = (fX - x) / n;
    1307           0 :         dy = (fY - y) / n;
    1308             :     }
    1309             : 
    1310           0 :     SkFixed* p = fStorage;
    1311           0 :     for (int i = 0; i < n; i++) {
    1312           0 :         *p++ = x; x += dx;
    1313           0 :         *p++ = y; y += dy;
    1314             :     }
    1315             : 
    1316           0 :     fCount -= n;
    1317           0 :     return n;
    1318             : }
    1319             : 
    1320             : ///////////////////////////////////////////////////////////////////////////////
    1321             : 
    1322           0 : static inline bool checkForZero(float x) {
    1323           0 :     return x*x == 0;
    1324             : }
    1325             : 
    1326           0 : static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
    1327           0 :     float   x = 1, y = 1;
    1328             :     SkPoint pt1, pt2;
    1329             : 
    1330           0 :     if (count > 1) {
    1331           0 :         pt1.fX = poly[1].fX - poly[0].fX;
    1332           0 :         pt1.fY = poly[1].fY - poly[0].fY;
    1333           0 :         y = SkPoint::Length(pt1.fX, pt1.fY);
    1334           0 :         if (checkForZero(y)) {
    1335           0 :             return false;
    1336             :         }
    1337           0 :         switch (count) {
    1338             :             case 2:
    1339           0 :                 break;
    1340             :             case 3:
    1341           0 :                 pt2.fX = poly[0].fY - poly[2].fY;
    1342           0 :                 pt2.fY = poly[2].fX - poly[0].fX;
    1343           0 :                 goto CALC_X;
    1344             :             default:
    1345           0 :                 pt2.fX = poly[0].fY - poly[3].fY;
    1346           0 :                 pt2.fY = poly[3].fX - poly[0].fX;
    1347             :             CALC_X:
    1348           0 :                 x = sdot(pt1.fX, pt2.fX, pt1.fY, pt2.fY) / y;
    1349           0 :                 break;
    1350             :         }
    1351             :     }
    1352           0 :     pt->set(x, y);
    1353           0 :     return true;
    1354             : }
    1355             : 
    1356           0 : bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
    1357             :                          const SkPoint& scale) {
    1358           0 :     float invScale = 1 / scale.fY;
    1359             : 
    1360           0 :     dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
    1361           0 :     dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
    1362           0 :     dst->fMat[kMPersp0] = 0;
    1363           0 :     dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
    1364           0 :     dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
    1365           0 :     dst->fMat[kMPersp1] = 0;
    1366           0 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1367           0 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1368           0 :     dst->fMat[kMPersp2] = 1;
    1369           0 :     dst->setTypeMask(kUnknown_Mask);
    1370           0 :     return true;
    1371             : }
    1372             : 
    1373           0 : bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
    1374             :                          const SkPoint& scale) {
    1375           0 :     float invScale = 1 / scale.fX;
    1376           0 :     dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
    1377           0 :     dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
    1378           0 :     dst->fMat[kMPersp0] = 0;
    1379             : 
    1380           0 :     invScale = 1 / scale.fY;
    1381           0 :     dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
    1382           0 :     dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
    1383           0 :     dst->fMat[kMPersp1] = 0;
    1384             : 
    1385           0 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1386           0 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1387           0 :     dst->fMat[kMPersp2] = 1;
    1388           0 :     dst->setTypeMask(kUnknown_Mask);
    1389           0 :     return true;
    1390             : }
    1391             : 
    1392           0 : bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
    1393             :                          const SkPoint& scale) {
    1394             :     float   a1, a2;
    1395             :     float   x0, y0, x1, y1, x2, y2;
    1396             : 
    1397           0 :     x0 = srcPt[2].fX - srcPt[0].fX;
    1398           0 :     y0 = srcPt[2].fY - srcPt[0].fY;
    1399           0 :     x1 = srcPt[2].fX - srcPt[1].fX;
    1400           0 :     y1 = srcPt[2].fY - srcPt[1].fY;
    1401           0 :     x2 = srcPt[2].fX - srcPt[3].fX;
    1402           0 :     y2 = srcPt[2].fY - srcPt[3].fY;
    1403             : 
    1404             :     /* check if abs(x2) > abs(y2) */
    1405           0 :     if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
    1406           0 :         float denom = (x1 * y2 / x2) - y1;
    1407           0 :         if (checkForZero(denom)) {
    1408           0 :             return false;
    1409             :         }
    1410           0 :         a1 = (((x0 - x1) * y2 / x2) - y0 + y1) / denom;
    1411             :     } else {
    1412           0 :         float denom = x1 - (y1 * x2 / y2);
    1413           0 :         if (checkForZero(denom)) {
    1414           0 :             return false;
    1415             :         }
    1416           0 :         a1 = (x0 - x1 - ((y0 - y1) * x2 / y2)) / denom;
    1417             :     }
    1418             : 
    1419             :     /* check if abs(x1) > abs(y1) */
    1420           0 :     if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
    1421           0 :         float denom = y2 - (x2 * y1 / x1);
    1422           0 :         if (checkForZero(denom)) {
    1423           0 :             return false;
    1424             :         }
    1425           0 :         a2 = (y0 - y2 - ((x0 - x2) * y1 / x1)) / denom;
    1426             :     } else {
    1427           0 :         float denom = (y2 * x1 / y1) - x2;
    1428           0 :         if (checkForZero(denom)) {
    1429           0 :             return false;
    1430             :         }
    1431           0 :         a2 = (((y0 - y2) * x1 / y1) - x0 + x2) / denom;
    1432             :     }
    1433             : 
    1434           0 :     float invScale = SkScalarInvert(scale.fX);
    1435           0 :     dst->fMat[kMScaleX] = (a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX) * invScale;
    1436           0 :     dst->fMat[kMSkewY]  = (a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY) * invScale;
    1437           0 :     dst->fMat[kMPersp0] = a2 * invScale;
    1438             : 
    1439           0 :     invScale = SkScalarInvert(scale.fY);
    1440           0 :     dst->fMat[kMSkewX]  = (a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX) * invScale;
    1441           0 :     dst->fMat[kMScaleY] = (a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY) * invScale;
    1442           0 :     dst->fMat[kMPersp1] = a1 * invScale;
    1443             : 
    1444           0 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1445           0 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1446           0 :     dst->fMat[kMPersp2] = 1;
    1447           0 :     dst->setTypeMask(kUnknown_Mask);
    1448           0 :     return true;
    1449             : }
    1450             : 
    1451             : typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
    1452             : 
    1453             : /*  Taken from Rob Johnson's original sample code in QuickDraw GX
    1454             : */
    1455           0 : bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
    1456             :                              int count) {
    1457           0 :     if ((unsigned)count > 4) {
    1458           0 :         SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
    1459           0 :         return false;
    1460             :     }
    1461             : 
    1462           0 :     if (0 == count) {
    1463           0 :         this->reset();
    1464           0 :         return true;
    1465             :     }
    1466           0 :     if (1 == count) {
    1467           0 :         this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
    1468           0 :         return true;
    1469             :     }
    1470             : 
    1471             :     SkPoint scale;
    1472           0 :     if (!poly_to_point(&scale, src, count) ||
    1473           0 :             SkScalarNearlyZero(scale.fX) ||
    1474           0 :             SkScalarNearlyZero(scale.fY)) {
    1475           0 :         return false;
    1476             :     }
    1477             : 
    1478             :     static const PolyMapProc gPolyMapProcs[] = {
    1479             :         SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
    1480             :     };
    1481           0 :     PolyMapProc proc = gPolyMapProcs[count - 2];
    1482             : 
    1483             :     SkMatrix tempMap, result;
    1484           0 :     tempMap.setTypeMask(kUnknown_Mask);
    1485             : 
    1486           0 :     if (!proc(src, &tempMap, scale)) {
    1487           0 :         return false;
    1488             :     }
    1489           0 :     if (!tempMap.invert(&result)) {
    1490           0 :         return false;
    1491             :     }
    1492           0 :     if (!proc(dst, &tempMap, scale)) {
    1493           0 :         return false;
    1494             :     }
    1495           0 :     this->setConcat(tempMap, result);
    1496           0 :     return true;
    1497             : }
    1498             : 
    1499             : ///////////////////////////////////////////////////////////////////////////////
    1500             : 
    1501             : enum MinMaxOrBoth {
    1502             :     kMin_MinMaxOrBoth,
    1503             :     kMax_MinMaxOrBoth,
    1504             :     kBoth_MinMaxOrBoth
    1505             : };
    1506             : 
    1507           0 : template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
    1508             :                                                               const SkScalar m[9],
    1509             :                                                               SkScalar results[/*1 or 2*/]) {
    1510           0 :     if (typeMask & SkMatrix::kPerspective_Mask) {
    1511           0 :         return false;
    1512             :     }
    1513           0 :     if (SkMatrix::kIdentity_Mask == typeMask) {
    1514           0 :         results[0] = SK_Scalar1;
    1515             :         if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1516           0 :             results[1] = SK_Scalar1;
    1517             :         }
    1518           0 :         return true;
    1519             :     }
    1520           0 :     if (!(typeMask & SkMatrix::kAffine_Mask)) {
    1521             :         if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1522           0 :              results[0] = SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
    1523           0 :                                       SkScalarAbs(m[SkMatrix::kMScaleY]));
    1524             :         } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1525           0 :              results[0] = SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
    1526           0 :                                       SkScalarAbs(m[SkMatrix::kMScaleY]));
    1527             :         } else {
    1528           0 :             results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
    1529           0 :             results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
    1530           0 :              if (results[0] > results[1]) {
    1531           0 :                  SkTSwap(results[0], results[1]);
    1532             :              }
    1533             :         }
    1534           0 :         return true;
    1535             :     }
    1536             :     // ignore the translation part of the matrix, just look at 2x2 portion.
    1537             :     // compute singular values, take largest or smallest abs value.
    1538             :     // [a b; b c] = A^T*A
    1539           0 :     SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
    1540           0 :                       m[SkMatrix::kMSkewY],  m[SkMatrix::kMSkewY]);
    1541           0 :     SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
    1542           0 :                       m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
    1543           0 :     SkScalar c = sdot(m[SkMatrix::kMSkewX],  m[SkMatrix::kMSkewX],
    1544           0 :                       m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
    1545             :     // eigenvalues of A^T*A are the squared singular values of A.
    1546             :     // characteristic equation is det((A^T*A) - l*I) = 0
    1547             :     // l^2 - (a + c)l + (ac-b^2)
    1548             :     // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
    1549             :     // and roots are guaranteed to be pos and real).
    1550           0 :     SkScalar bSqd = b * b;
    1551             :     // if upper left 2x2 is orthogonal save some math
    1552           0 :     if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
    1553             :         if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1554           0 :             results[0] = SkMinScalar(a, c);
    1555             :         } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1556           0 :             results[0] = SkMaxScalar(a, c);
    1557             :         } else {
    1558           0 :             results[0] = a;
    1559           0 :             results[1] = c;
    1560           0 :             if (results[0] > results[1]) {
    1561           0 :                 SkTSwap(results[0], results[1]);
    1562             :             }
    1563             :         }
    1564             :     } else {
    1565           0 :         SkScalar aminusc = a - c;
    1566           0 :         SkScalar apluscdiv2 = SkScalarHalf(a + c);
    1567           0 :         SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
    1568             :         if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1569           0 :             results[0] = apluscdiv2 - x;
    1570             :         } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1571           0 :             results[0] = apluscdiv2 + x;
    1572             :         } else {
    1573           0 :             results[0] = apluscdiv2 - x;
    1574           0 :             results[1] = apluscdiv2 + x;
    1575             :         }
    1576             :     }
    1577           0 :     if (!SkScalarIsFinite(results[0])) {
    1578           0 :         return false;
    1579             :     }
    1580             :     // Due to the floating point inaccuracy, there might be an error in a, b, c
    1581             :     // calculated by sdot, further deepened by subsequent arithmetic operations
    1582             :     // on them. Therefore, we allow and cap the nearly-zero negative values.
    1583           0 :     SkASSERT(results[0] >= -SK_ScalarNearlyZero);
    1584           0 :     if (results[0] < 0) {
    1585           0 :         results[0] = 0;
    1586             :     }
    1587           0 :     results[0] = SkScalarSqrt(results[0]);
    1588             :     if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
    1589           0 :         if (!SkScalarIsFinite(results[1])) {
    1590           0 :             return false;
    1591             :         }
    1592           0 :         SkASSERT(results[1] >= -SK_ScalarNearlyZero);
    1593           0 :         if (results[1] < 0) {
    1594           0 :             results[1] = 0;
    1595             :         }
    1596           0 :         results[1] = SkScalarSqrt(results[1]);
    1597             :     }
    1598           0 :     return true;
    1599             : }
    1600             : 
    1601           0 : SkScalar SkMatrix::getMinScale() const {
    1602             :     SkScalar factor;
    1603           0 :     if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
    1604           0 :         return factor;
    1605             :     } else {
    1606           0 :         return -1;
    1607             :     }
    1608             : }
    1609             : 
    1610           0 : SkScalar SkMatrix::getMaxScale() const {
    1611             :     SkScalar factor;
    1612           0 :     if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
    1613           0 :         return factor;
    1614             :     } else {
    1615           0 :         return -1;
    1616             :     }
    1617             : }
    1618             : 
    1619           0 : bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
    1620           0 :     return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
    1621             : }
    1622             : 
    1623             : namespace {
    1624             : 
    1625             : // SkMatrix is C++11 POD (trivial and standard-layout), but not aggregate (it has private fields).
    1626             : struct AggregateMatrix {
    1627             :     SkScalar matrix[9];
    1628             :     uint32_t typemask;
    1629             : 
    1630          12 :     const SkMatrix& asSkMatrix() const { return *reinterpret_cast<const SkMatrix*>(this); }
    1631             : };
    1632             : static_assert(sizeof(AggregateMatrix) == sizeof(SkMatrix), "AggregateMatrix size mismatch.");
    1633             : 
    1634             : }  // namespace
    1635             : 
    1636           6 : const SkMatrix& SkMatrix::I() {
    1637             :     static_assert(offsetof(SkMatrix,fMat)      == offsetof(AggregateMatrix,matrix),   "fMat");
    1638             :     static_assert(offsetof(SkMatrix,fTypeMask) == offsetof(AggregateMatrix,typemask), "fTypeMask");
    1639             : 
    1640             :     static const AggregateMatrix identity = { {SK_Scalar1, 0, 0,
    1641             :                                                0, SK_Scalar1, 0,
    1642             :                                                0, 0, SK_Scalar1 },
    1643             :                                              kIdentity_Mask | kRectStaysRect_Mask};
    1644           6 :     SkASSERT(identity.asSkMatrix().isIdentity());
    1645           6 :     return identity.asSkMatrix();
    1646             : }
    1647             : 
    1648           0 : const SkMatrix& SkMatrix::InvalidMatrix() {
    1649             :     static_assert(offsetof(SkMatrix,fMat)      == offsetof(AggregateMatrix,matrix),   "fMat");
    1650             :     static_assert(offsetof(SkMatrix,fTypeMask) == offsetof(AggregateMatrix,typemask), "fTypeMask");
    1651             : 
    1652             :     static const AggregateMatrix invalid =
    1653             :         { {SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
    1654             :            SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
    1655             :            SK_ScalarMax, SK_ScalarMax, SK_ScalarMax },
    1656             :          kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask };
    1657           0 :     return invalid.asSkMatrix();
    1658             : }
    1659             : 
    1660           0 : bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const {
    1661           0 :     if (this->hasPerspective()) {
    1662           0 :         return false;
    1663             :     }
    1664             : 
    1665           0 :     const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY());
    1666           0 :     const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY());
    1667           0 :     if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) ||
    1668           0 :         SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) {
    1669           0 :         return false;
    1670             :     }
    1671             : 
    1672           0 :     if (scale) {
    1673           0 :         scale->set(sx, sy);
    1674             :     }
    1675           0 :     if (remaining) {
    1676           0 :         *remaining = *this;
    1677           0 :         remaining->postScale(SkScalarInvert(sx), SkScalarInvert(sy));
    1678             :     }
    1679           0 :     return true;
    1680             : }
    1681             : 
    1682             : ///////////////////////////////////////////////////////////////////////////////
    1683             : 
    1684           0 : size_t SkMatrix::writeToMemory(void* buffer) const {
    1685             :     // TODO write less for simple matrices
    1686             :     static const size_t sizeInMemory = 9 * sizeof(SkScalar);
    1687           0 :     if (buffer) {
    1688           0 :         memcpy(buffer, fMat, sizeInMemory);
    1689             :     }
    1690           0 :     return sizeInMemory;
    1691             : }
    1692             : 
    1693           0 : size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
    1694             :     static const size_t sizeInMemory = 9 * sizeof(SkScalar);
    1695           0 :     if (length < sizeInMemory) {
    1696           0 :         return 0;
    1697             :     }
    1698           0 :     if (buffer) {
    1699           0 :         memcpy(fMat, buffer, sizeInMemory);
    1700           0 :         this->setTypeMask(kUnknown_Mask);
    1701             :     }
    1702           0 :     return sizeInMemory;
    1703             : }
    1704             : 
    1705           0 : void SkMatrix::dump() const {
    1706           0 :     SkString str;
    1707           0 :     this->toString(&str);
    1708           0 :     SkDebugf("%s\n", str.c_str());
    1709           0 : }
    1710             : 
    1711           0 : void SkMatrix::toString(SkString* str) const {
    1712           0 :     str->appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
    1713           0 :              fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
    1714           0 :              fMat[6], fMat[7], fMat[8]);
    1715           0 : }
    1716             : 
    1717             : ///////////////////////////////////////////////////////////////////////////////
    1718             : 
    1719             : #include "SkMatrixUtils.h"
    1720             : 
    1721         130 : bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkPaint& paint) {
    1722             :     // Our path aa is 2-bits, and our rect aa is 8, so we could use 8,
    1723             :     // but in practice 4 seems enough (still looks smooth) and allows
    1724             :     // more slightly fractional cases to fall into the fast (sprite) case.
    1725             :     static const unsigned kAntiAliasSubpixelBits = 4;
    1726             : 
    1727         130 :     const unsigned subpixelBits = paint.isAntiAlias() ? kAntiAliasSubpixelBits : 0;
    1728             : 
    1729             :     // quick reject on affine or perspective
    1730         130 :     if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
    1731           0 :         return false;
    1732             :     }
    1733             : 
    1734             :     // quick success check
    1735         130 :     if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
    1736           3 :         return true;
    1737             :     }
    1738             : 
    1739             :     // mapRect supports negative scales, so we eliminate those first
    1740         127 :     if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
    1741           0 :         return false;
    1742             :     }
    1743             : 
    1744             :     SkRect dst;
    1745         127 :     SkIRect isrc = SkIRect::MakeSize(size);
    1746             : 
    1747             :     {
    1748             :         SkRect src;
    1749         127 :         src.set(isrc);
    1750         127 :         mat.mapRect(&dst, src);
    1751             :     }
    1752             : 
    1753             :     // just apply the translate to isrc
    1754         127 :     isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
    1755         254 :                 SkScalarRoundToInt(mat.getTranslateY()));
    1756             : 
    1757         127 :     if (subpixelBits) {
    1758         127 :         isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits);
    1759         127 :         isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits);
    1760         127 :         isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits);
    1761         127 :         isrc.fBottom = SkLeftShift(isrc.fBottom, subpixelBits);
    1762             : 
    1763         127 :         const float scale = 1 << subpixelBits;
    1764         127 :         dst.fLeft *= scale;
    1765         127 :         dst.fTop *= scale;
    1766         127 :         dst.fRight *= scale;
    1767         127 :         dst.fBottom *= scale;
    1768             :     }
    1769             : 
    1770             :     SkIRect idst;
    1771         127 :     dst.round(&idst);
    1772         127 :     return isrc == idst;
    1773             : }
    1774             : 
    1775             : // A square matrix M can be decomposed (via polar decomposition) into two matrices --
    1776             : // an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
    1777             : // where U is another orthogonal matrix and W is a scale matrix. These can be recombined
    1778             : // to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
    1779             : //
    1780             : // The one wrinkle is that traditionally Q may contain a reflection -- the
    1781             : // calculation has been rejiggered to put that reflection into W.
    1782           0 : bool SkDecomposeUpper2x2(const SkMatrix& matrix,
    1783             :                          SkPoint* rotation1,
    1784             :                          SkPoint* scale,
    1785             :                          SkPoint* rotation2) {
    1786             : 
    1787           0 :     SkScalar A = matrix[SkMatrix::kMScaleX];
    1788           0 :     SkScalar B = matrix[SkMatrix::kMSkewX];
    1789           0 :     SkScalar C = matrix[SkMatrix::kMSkewY];
    1790           0 :     SkScalar D = matrix[SkMatrix::kMScaleY];
    1791             : 
    1792           0 :     if (is_degenerate_2x2(A, B, C, D)) {
    1793           0 :         return false;
    1794             :     }
    1795             : 
    1796             :     double w1, w2;
    1797             :     SkScalar cos1, sin1;
    1798             :     SkScalar cos2, sin2;
    1799             : 
    1800             :     // do polar decomposition (M = Q*S)
    1801             :     SkScalar cosQ, sinQ;
    1802             :     double Sa, Sb, Sd;
    1803             :     // if M is already symmetric (i.e., M = I*S)
    1804           0 :     if (SkScalarNearlyEqual(B, C)) {
    1805           0 :         cosQ = 1;
    1806           0 :         sinQ = 0;
    1807             : 
    1808           0 :         Sa = A;
    1809           0 :         Sb = B;
    1810           0 :         Sd = D;
    1811             :     } else {
    1812           0 :         cosQ = A + D;
    1813           0 :         sinQ = C - B;
    1814           0 :         SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
    1815           0 :         cosQ *= reciplen;
    1816           0 :         sinQ *= reciplen;
    1817             : 
    1818             :         // S = Q^-1*M
    1819             :         // we don't calc Sc since it's symmetric
    1820           0 :         Sa = A*cosQ + C*sinQ;
    1821           0 :         Sb = B*cosQ + D*sinQ;
    1822           0 :         Sd = -B*sinQ + D*cosQ;
    1823             :     }
    1824             : 
    1825             :     // Now we need to compute eigenvalues of S (our scale factors)
    1826             :     // and eigenvectors (bases for our rotation)
    1827             :     // From this, should be able to reconstruct S as U*W*U^T
    1828           0 :     if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
    1829             :         // already diagonalized
    1830           0 :         cos1 = 1;
    1831           0 :         sin1 = 0;
    1832           0 :         w1 = Sa;
    1833           0 :         w2 = Sd;
    1834           0 :         cos2 = cosQ;
    1835           0 :         sin2 = sinQ;
    1836             :     } else {
    1837           0 :         double diff = Sa - Sd;
    1838           0 :         double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
    1839           0 :         double trace = Sa + Sd;
    1840           0 :         if (diff > 0) {
    1841           0 :             w1 = 0.5*(trace + discriminant);
    1842           0 :             w2 = 0.5*(trace - discriminant);
    1843             :         } else {
    1844           0 :             w1 = 0.5*(trace - discriminant);
    1845           0 :             w2 = 0.5*(trace + discriminant);
    1846             :         }
    1847             : 
    1848           0 :         cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
    1849           0 :         SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
    1850           0 :         cos1 *= reciplen;
    1851           0 :         sin1 *= reciplen;
    1852             : 
    1853             :         // rotation 2 is composition of Q and U
    1854           0 :         cos2 = cos1*cosQ - sin1*sinQ;
    1855           0 :         sin2 = sin1*cosQ + cos1*sinQ;
    1856             : 
    1857             :         // rotation 1 is U^T
    1858           0 :         sin1 = -sin1;
    1859             :     }
    1860             : 
    1861           0 :     if (scale) {
    1862           0 :         scale->fX = SkDoubleToScalar(w1);
    1863           0 :         scale->fY = SkDoubleToScalar(w2);
    1864             :     }
    1865           0 :     if (rotation1) {
    1866           0 :         rotation1->fX = cos1;
    1867           0 :         rotation1->fY = sin1;
    1868             :     }
    1869           0 :     if (rotation2) {
    1870           0 :         rotation2->fX = cos2;
    1871           0 :         rotation2->fY = sin2;
    1872             :     }
    1873             : 
    1874           0 :     return true;
    1875             : }
    1876             : 
    1877             : //////////////////////////////////////////////////////////////////////////////////////////////////
    1878             : 
    1879           0 : void SkRSXform::toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const {
    1880             : #if 0
    1881             :     // This is the slow way, but it documents what we're doing
    1882             :     quad[0].set(0, 0);
    1883             :     quad[1].set(width, 0);
    1884             :     quad[2].set(width, height);
    1885             :     quad[3].set(0, height);
    1886             :     SkMatrix m;
    1887             :     m.setRSXform(*this).mapPoints(quad, quad, 4);
    1888             : #else
    1889           0 :     const SkScalar m00 = fSCos;
    1890           0 :     const SkScalar m01 = -fSSin;
    1891           0 :     const SkScalar m02 = fTx;
    1892           0 :     const SkScalar m10 = -m01;
    1893           0 :     const SkScalar m11 = m00;
    1894           0 :     const SkScalar m12 = fTy;
    1895             : 
    1896           0 :     quad[0].set(m02, m12);
    1897           0 :     quad[1].set(m00 * width + m02, m10 * width + m12);
    1898           0 :     quad[2].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
    1899           0 :     quad[3].set(m01 * height + m02, m11 * height + m12);
    1900             : #endif
    1901           0 : }

Generated by: LCOV version 1.13