LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkMatrix.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 790 0 0.0 %
Date: 2012-06-02 Functions: 77 0 0.0 %

       1                 : 
       2                 : /*
       3                 :  * Copyright 2006 The Android Open Source Project
       4                 :  *
       5                 :  * Use of this source code is governed by a BSD-style license that can be
       6                 :  * found in the LICENSE file.
       7                 :  */
       8                 : 
       9                 : 
      10                 : #include "SkMatrix.h"
      11                 : #include "Sk64.h"
      12                 : #include "SkFloatBits.h"
      13                 : #include "SkScalarCompare.h"
      14                 : #include "SkString.h"
      15                 : 
      16                 : #ifdef SK_SCALAR_IS_FLOAT
      17                 :     #define kMatrix22Elem   SK_Scalar1
      18                 : 
      19               0 :     static inline float SkDoubleToFloat(double x) {
      20               0 :         return static_cast<float>(x);
      21                 :     }
      22                 : #else
      23                 :     #define kMatrix22Elem   SK_Fract1
      24                 : #endif
      25                 : 
      26                 : /*      [scale-x    skew-x      trans-x]   [X]   [X']
      27                 :         [skew-y     scale-y     trans-y] * [Y] = [Y']
      28                 :         [persp-0    persp-1     persp-2]   [1]   [1 ]
      29                 : */
      30                 : 
      31               0 : void SkMatrix::reset() {
      32               0 :     fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
      33               0 :     fMat[kMSkewX]  = fMat[kMSkewY] = 
      34               0 :     fMat[kMTransX] = fMat[kMTransY] =
      35               0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
      36               0 :     fMat[kMPersp2] = kMatrix22Elem;
      37                 : 
      38               0 :     this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
      39               0 : }
      40                 : 
      41                 : // this guy aligns with the masks, so we can compute a mask from a varaible 0/1
      42                 : enum {
      43                 :     kTranslate_Shift,
      44                 :     kScale_Shift,
      45                 :     kAffine_Shift,
      46                 :     kPerspective_Shift,
      47                 :     kRectStaysRect_Shift
      48                 : };
      49                 : 
      50                 : #ifdef SK_SCALAR_IS_FLOAT
      51                 :     static const int32_t kScalar1Int = 0x3f800000;
      52                 :     static const int32_t kPersp1Int  = 0x3f800000;
      53                 : #else
      54                 :     #define scalarAsInt(x)  (x)
      55                 :     static const int32_t kScalar1Int = (1 << 16);
      56                 :     static const int32_t kPersp1Int  = (1 << 30);
      57                 : #endif
      58                 : 
      59               0 : uint8_t SkMatrix::computePerspectiveTypeMask() const {
      60               0 :     unsigned mask = kOnlyPerspectiveValid_Mask | kUnknown_Mask;
      61                 : 
      62               0 :     if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
      63               0 :             SkScalarAs2sCompliment(fMat[kMPersp1]) |
      64               0 :             (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
      65               0 :         mask |= kPerspective_Mask;
      66                 :     }
      67                 : 
      68               0 :     return SkToU8(mask);
      69                 : }
      70                 : 
      71               0 : uint8_t SkMatrix::computeTypeMask() const {
      72               0 :     unsigned mask = 0;
      73                 : 
      74                 : #ifdef SK_SCALAR_SLOW_COMPARES
      75                 :     if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
      76                 :             SkScalarAs2sCompliment(fMat[kMPersp1]) |
      77                 :             (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
      78                 :         mask |= kPerspective_Mask;
      79                 :     }
      80                 : 
      81                 :     if (SkScalarAs2sCompliment(fMat[kMTransX]) |
      82                 :             SkScalarAs2sCompliment(fMat[kMTransY])) {
      83                 :         mask |= kTranslate_Mask;
      84                 :     }
      85                 : #else
      86                 :     // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
      87                 :     // is a win, but replacing those below is not. We don't yet understand
      88                 :     // that result.
      89               0 :     if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 ||
      90               0 :         fMat[kMPersp2] != kMatrix22Elem) {
      91               0 :         mask |= kPerspective_Mask;
      92                 :     }
      93                 : 
      94               0 :     if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
      95               0 :         mask |= kTranslate_Mask;
      96                 :     }
      97                 : #endif
      98                 : 
      99               0 :     int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
     100               0 :     int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
     101               0 :     int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
     102               0 :     int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
     103                 : 
     104               0 :     if (m01 | m10) {
     105               0 :         mask |= kAffine_Mask;
     106                 :     }
     107                 : 
     108               0 :     if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) {
     109               0 :         mask |= kScale_Mask;
     110                 :     }
     111                 : 
     112               0 :     if ((mask & kPerspective_Mask) == 0) {
     113                 :         // map non-zero to 1
     114               0 :         m00 = m00 != 0;
     115               0 :         m01 = m01 != 0;
     116               0 :         m10 = m10 != 0;
     117               0 :         m11 = m11 != 0;
     118                 : 
     119                 :         // record if the (p)rimary and (s)econdary diagonals are all 0 or
     120                 :         // all non-zero (answer is 0 or 1)
     121               0 :         int dp0 = (m00 | m11) ^ 1;  // true if both are 0
     122               0 :         int dp1 = m00 & m11;        // true if both are 1
     123               0 :         int ds0 = (m01 | m10) ^ 1;  // true if both are 0
     124               0 :         int ds1 = m01 & m10;        // true if both are 1
     125                 : 
     126                 :         // return 1 if primary is 1 and secondary is 0 or
     127                 :         // primary is 0 and secondary is 1
     128               0 :         mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
     129                 :     }
     130                 : 
     131               0 :     return SkToU8(mask);
     132                 : }
     133                 : 
     134                 : ///////////////////////////////////////////////////////////////////////////////
     135                 : 
     136                 : #ifdef SK_SCALAR_IS_FLOAT
     137                 : 
     138               0 : bool operator==(const SkMatrix& a, const SkMatrix& b) {
     139               0 :     const SkScalar* SK_RESTRICT ma = a.fMat;
     140               0 :     const SkScalar* SK_RESTRICT mb = b.fMat;
     141                 : 
     142               0 :     return  ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
     143               0 :             ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
     144               0 :             ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
     145                 : }
     146                 : 
     147                 : #endif
     148                 : 
     149                 : ///////////////////////////////////////////////////////////////////////////////
     150                 : 
     151               0 : void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
     152               0 :     if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
     153               0 :         fMat[kMTransX] = dx;
     154               0 :         fMat[kMTransY] = dy;
     155                 : 
     156               0 :         fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
     157               0 :         fMat[kMSkewX]  = fMat[kMSkewY] = 
     158               0 :         fMat[kMPersp0] = fMat[kMPersp1] = 0;
     159               0 :         fMat[kMPersp2] = kMatrix22Elem;
     160                 : 
     161               0 :         this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
     162                 :     } else {
     163               0 :         this->reset();
     164                 :     }
     165               0 : }
     166                 : 
     167               0 : bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
     168               0 :     if (this->hasPerspective()) {
     169                 :         SkMatrix    m;
     170               0 :         m.setTranslate(dx, dy);
     171               0 :         return this->preConcat(m);
     172                 :     }
     173                 :     
     174               0 :     if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
     175               0 :         fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) +
     176               0 :                           SkScalarMul(fMat[kMSkewX], dy);
     177               0 :         fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
     178               0 :                           SkScalarMul(fMat[kMScaleY], dy);
     179                 : 
     180               0 :         this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     181                 :     }
     182               0 :     return true;
     183                 : }
     184                 : 
     185               0 : bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
     186               0 :     if (this->hasPerspective()) {
     187                 :         SkMatrix    m;
     188               0 :         m.setTranslate(dx, dy);
     189               0 :         return this->postConcat(m);
     190                 :     }
     191                 :     
     192               0 :     if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
     193               0 :         fMat[kMTransX] += dx;
     194               0 :         fMat[kMTransY] += dy;
     195               0 :         this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     196                 :     }
     197               0 :     return true;
     198                 : }
     199                 : 
     200                 : ///////////////////////////////////////////////////////////////////////////////
     201                 : 
     202               0 : void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     203               0 :     if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
     204               0 :         this->reset();
     205                 :     } else {
     206               0 :         fMat[kMScaleX] = sx;
     207               0 :         fMat[kMScaleY] = sy;
     208               0 :         fMat[kMTransX] = px - SkScalarMul(sx, px);
     209               0 :         fMat[kMTransY] = py - SkScalarMul(sy, py);
     210               0 :         fMat[kMPersp2] = kMatrix22Elem;
     211                 : 
     212               0 :         fMat[kMSkewX]  = fMat[kMSkewY] = 
     213               0 :         fMat[kMPersp0] = fMat[kMPersp1] = 0;
     214                 :         
     215               0 :         this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
     216                 :     }
     217               0 : }
     218                 : 
     219               0 : void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
     220               0 :     if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
     221               0 :         this->reset();
     222                 :     } else {
     223               0 :         fMat[kMScaleX] = sx;
     224               0 :         fMat[kMScaleY] = sy;
     225               0 :         fMat[kMPersp2] = kMatrix22Elem;
     226                 : 
     227               0 :         fMat[kMTransX] = fMat[kMTransY] =
     228               0 :         fMat[kMSkewX]  = fMat[kMSkewY] = 
     229               0 :         fMat[kMPersp0] = fMat[kMPersp1] = 0;
     230                 : 
     231               0 :         this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
     232                 :     }
     233               0 : }
     234                 : 
     235               0 : bool SkMatrix::setIDiv(int divx, int divy) {
     236               0 :     if (!divx || !divy) {
     237               0 :         return false;
     238                 :     }
     239               0 :     this->setScale(SK_Scalar1 / divx, SK_Scalar1 / divy);
     240               0 :     return true;
     241                 : }
     242                 : 
     243               0 : bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     244                 :     SkMatrix    m;
     245               0 :     m.setScale(sx, sy, px, py);
     246               0 :     return this->preConcat(m);
     247                 : }
     248                 : 
     249               0 : bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
     250               0 :     if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
     251               0 :         return true;
     252                 :     }
     253                 : 
     254                 : #ifdef SK_SCALAR_IS_FIXED
     255                 :     SkMatrix    m;
     256                 :     m.setScale(sx, sy);
     257                 :     return this->preConcat(m);
     258                 : #else
     259                 :     // the assumption is that these multiplies are very cheap, and that
     260                 :     // a full concat and/or just computing the matrix type is more expensive.
     261                 :     // Also, the fixed-point case checks for overflow, but the float doesn't,
     262                 :     // so we can get away with these blind multiplies.
     263                 : 
     264               0 :     fMat[kMScaleX] = SkScalarMul(fMat[kMScaleX], sx);
     265               0 :     fMat[kMSkewY] = SkScalarMul(fMat[kMSkewY],   sx);
     266               0 :     fMat[kMPersp0] = SkScalarMul(fMat[kMPersp0], sx);
     267                 : 
     268               0 :     fMat[kMSkewX] = SkScalarMul(fMat[kMSkewX],   sy);
     269               0 :     fMat[kMScaleY] = SkScalarMul(fMat[kMScaleY], sy);
     270               0 :     fMat[kMPersp1] = SkScalarMul(fMat[kMPersp1], sy);
     271                 : 
     272               0 :     this->orTypeMask(kScale_Mask);
     273               0 :     return true;
     274                 : #endif
     275                 : }
     276                 : 
     277               0 : bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     278               0 :     if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
     279               0 :         return true;
     280                 :     }
     281                 :     SkMatrix    m;
     282               0 :     m.setScale(sx, sy, px, py);
     283               0 :     return this->postConcat(m);
     284                 : }
     285                 : 
     286               0 : bool SkMatrix::postScale(SkScalar sx, SkScalar sy) {
     287               0 :     if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
     288               0 :         return true;
     289                 :     }
     290                 :     SkMatrix    m;
     291               0 :     m.setScale(sx, sy);
     292               0 :     return this->postConcat(m);
     293                 : }
     294                 : 
     295                 : #ifdef SK_SCALAR_IS_FIXED
     296                 :     static inline SkFixed roundidiv(SkFixed numer, int denom) {
     297                 :         int ns = numer >> 31;
     298                 :         int ds = denom >> 31;
     299                 :         numer = (numer ^ ns) - ns;
     300                 :         denom = (denom ^ ds) - ds;
     301                 :         
     302                 :         SkFixed answer = (numer + (denom >> 1)) / denom;
     303                 :         int as = ns ^ ds;
     304                 :         return (answer ^ as) - as;
     305                 :     }
     306                 : #endif
     307                 : 
     308                 : // this guy perhaps can go away, if we have a fract/high-precision way to
     309                 : // scale matrices
     310               0 : bool SkMatrix::postIDiv(int divx, int divy) {
     311               0 :     if (divx == 0 || divy == 0) {
     312               0 :         return false;
     313                 :     }
     314                 : 
     315                 : #ifdef SK_SCALAR_IS_FIXED
     316                 :     fMat[kMScaleX] = roundidiv(fMat[kMScaleX], divx);
     317                 :     fMat[kMSkewX]  = roundidiv(fMat[kMSkewX],  divx);
     318                 :     fMat[kMTransX] = roundidiv(fMat[kMTransX], divx);
     319                 : 
     320                 :     fMat[kMScaleY] = roundidiv(fMat[kMScaleY], divy);
     321                 :     fMat[kMSkewY]  = roundidiv(fMat[kMSkewY],  divy);
     322                 :     fMat[kMTransY] = roundidiv(fMat[kMTransY], divy);
     323                 : #else
     324               0 :     const float invX = 1.f / divx;
     325               0 :     const float invY = 1.f / divy;
     326                 : 
     327               0 :     fMat[kMScaleX] *= invX;
     328               0 :     fMat[kMSkewX]  *= invX;
     329               0 :     fMat[kMTransX] *= invX;
     330                 :     
     331               0 :     fMat[kMScaleY] *= invY;
     332               0 :     fMat[kMSkewY]  *= invY;
     333               0 :     fMat[kMTransY] *= invY;
     334                 : #endif
     335                 : 
     336               0 :     this->setTypeMask(kUnknown_Mask);
     337               0 :     return true;
     338                 : }
     339                 : 
     340                 : ////////////////////////////////////////////////////////////////////////////////////
     341                 : 
     342               0 : void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
     343                 :                          SkScalar px, SkScalar py) {
     344               0 :     const SkScalar oneMinusCosV = SK_Scalar1 - cosV;
     345                 : 
     346               0 :     fMat[kMScaleX]  = cosV;
     347               0 :     fMat[kMSkewX]   = -sinV;
     348               0 :     fMat[kMTransX]  = SkScalarMul(sinV, py) + SkScalarMul(oneMinusCosV, px);
     349                 : 
     350               0 :     fMat[kMSkewY]   = sinV;
     351               0 :     fMat[kMScaleY]  = cosV;
     352               0 :     fMat[kMTransY]  = SkScalarMul(-sinV, px) + SkScalarMul(oneMinusCosV, py);
     353                 : 
     354               0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     355               0 :     fMat[kMPersp2] = kMatrix22Elem;
     356                 :     
     357               0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     358               0 : }
     359                 : 
     360               0 : void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
     361               0 :     fMat[kMScaleX]  = cosV;
     362               0 :     fMat[kMSkewX]   = -sinV;
     363               0 :     fMat[kMTransX]  = 0;
     364                 : 
     365               0 :     fMat[kMSkewY]   = sinV;
     366               0 :     fMat[kMScaleY]  = cosV;
     367               0 :     fMat[kMTransY]  = 0;
     368                 : 
     369               0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     370               0 :     fMat[kMPersp2] = kMatrix22Elem;
     371                 : 
     372               0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     373               0 : }
     374                 : 
     375               0 : void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
     376                 :     SkScalar sinV, cosV;
     377               0 :     sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
     378               0 :     this->setSinCos(sinV, cosV, px, py);
     379               0 : }
     380                 : 
     381               0 : void SkMatrix::setRotate(SkScalar degrees) {
     382                 :     SkScalar sinV, cosV;
     383               0 :     sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
     384               0 :     this->setSinCos(sinV, cosV);
     385               0 : }
     386                 : 
     387               0 : bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
     388                 :     SkMatrix    m;
     389               0 :     m.setRotate(degrees, px, py);
     390               0 :     return this->preConcat(m);
     391                 : }
     392                 : 
     393               0 : bool SkMatrix::preRotate(SkScalar degrees) {
     394                 :     SkMatrix    m;
     395               0 :     m.setRotate(degrees);
     396               0 :     return this->preConcat(m);
     397                 : }
     398                 : 
     399               0 : bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
     400                 :     SkMatrix    m;
     401               0 :     m.setRotate(degrees, px, py);
     402               0 :     return this->postConcat(m);
     403                 : }
     404                 : 
     405               0 : bool SkMatrix::postRotate(SkScalar degrees) {
     406                 :     SkMatrix    m;
     407               0 :     m.setRotate(degrees);
     408               0 :     return this->postConcat(m);
     409                 : }
     410                 : 
     411                 : ////////////////////////////////////////////////////////////////////////////////////
     412                 : 
     413               0 : void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     414               0 :     fMat[kMScaleX]  = SK_Scalar1;
     415               0 :     fMat[kMSkewX]   = sx;
     416               0 :     fMat[kMTransX]  = SkScalarMul(-sx, py);
     417                 : 
     418               0 :     fMat[kMSkewY]   = sy;
     419               0 :     fMat[kMScaleY]  = SK_Scalar1;
     420               0 :     fMat[kMTransY]  = SkScalarMul(-sy, px);
     421                 : 
     422               0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     423               0 :     fMat[kMPersp2] = kMatrix22Elem;
     424                 : 
     425               0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     426               0 : }
     427                 : 
     428               0 : void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
     429               0 :     fMat[kMScaleX]  = SK_Scalar1;
     430               0 :     fMat[kMSkewX]   = sx;
     431               0 :     fMat[kMTransX]  = 0;
     432                 : 
     433               0 :     fMat[kMSkewY]   = sy;
     434               0 :     fMat[kMScaleY]  = SK_Scalar1;
     435               0 :     fMat[kMTransY]  = 0;
     436                 : 
     437               0 :     fMat[kMPersp0] = fMat[kMPersp1] = 0;
     438               0 :     fMat[kMPersp2] = kMatrix22Elem;
     439                 : 
     440               0 :     this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     441               0 : }
     442                 : 
     443               0 : bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     444                 :     SkMatrix    m;
     445               0 :     m.setSkew(sx, sy, px, py);
     446               0 :     return this->preConcat(m);
     447                 : }
     448                 : 
     449               0 : bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
     450                 :     SkMatrix    m;
     451               0 :     m.setSkew(sx, sy);
     452               0 :     return this->preConcat(m);
     453                 : }
     454                 : 
     455               0 : bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
     456                 :     SkMatrix    m;
     457               0 :     m.setSkew(sx, sy, px, py);
     458               0 :     return this->postConcat(m);
     459                 : }
     460                 : 
     461               0 : bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
     462                 :     SkMatrix    m;
     463               0 :     m.setSkew(sx, sy);
     464               0 :     return this->postConcat(m);
     465                 : }
     466                 : 
     467                 : ///////////////////////////////////////////////////////////////////////////////
     468                 : 
     469               0 : bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
     470                 :                              ScaleToFit align)
     471                 : {
     472               0 :     if (src.isEmpty()) {
     473               0 :         this->reset();
     474               0 :         return false;
     475                 :     }
     476                 : 
     477               0 :     if (dst.isEmpty()) {
     478               0 :         sk_bzero(fMat, 8 * sizeof(SkScalar));
     479               0 :         this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
     480                 :     } else {
     481               0 :         SkScalar    tx, sx = SkScalarDiv(dst.width(), src.width());
     482               0 :         SkScalar    ty, sy = SkScalarDiv(dst.height(), src.height());
     483               0 :         bool        xLarger = false;
     484                 : 
     485               0 :         if (align != kFill_ScaleToFit) {
     486               0 :             if (sx > sy) {
     487               0 :                 xLarger = true;
     488               0 :                 sx = sy;
     489                 :             } else {
     490               0 :                 sy = sx;
     491                 :             }
     492                 :         }
     493                 : 
     494               0 :         tx = dst.fLeft - SkScalarMul(src.fLeft, sx);
     495               0 :         ty = dst.fTop - SkScalarMul(src.fTop, sy);
     496               0 :         if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
     497                 :             SkScalar diff;
     498                 : 
     499               0 :             if (xLarger) {
     500               0 :                 diff = dst.width() - SkScalarMul(src.width(), sy);
     501                 :             } else {
     502               0 :                 diff = dst.height() - SkScalarMul(src.height(), sy);
     503                 :             }
     504                 :             
     505               0 :             if (align == kCenter_ScaleToFit) {
     506               0 :                 diff = SkScalarHalf(diff);
     507                 :             }
     508                 : 
     509               0 :             if (xLarger) {
     510               0 :                 tx += diff;
     511                 :             } else {
     512               0 :                 ty += diff;
     513                 :             }
     514                 :         }
     515                 : 
     516               0 :         fMat[kMScaleX] = sx;
     517               0 :         fMat[kMScaleY] = sy;
     518               0 :         fMat[kMTransX] = tx;
     519               0 :         fMat[kMTransY] = ty;
     520               0 :         fMat[kMSkewX]  = fMat[kMSkewY] = 
     521               0 :         fMat[kMPersp0] = fMat[kMPersp1] = 0;
     522                 : 
     523               0 :         this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
     524                 :     }
     525                 :     // shared cleanup
     526               0 :     fMat[kMPersp2] = kMatrix22Elem;
     527               0 :     return true;
     528                 : }
     529                 : 
     530                 : ///////////////////////////////////////////////////////////////////////////////
     531                 : 
     532                 : #ifdef SK_SCALAR_IS_FLOAT
     533               0 :     static inline int fixmuladdmul(float a, float b, float c, float d,
     534                 :                                    float* result) {
     535               0 :         *result = SkDoubleToFloat((double)a * b + (double)c * d);
     536               0 :         return true;
     537                 :     }
     538                 : 
     539               0 :     static inline bool rowcol3(const float row[], const float col[],
     540                 :                                float* result) {
     541               0 :         *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
     542               0 :         return true;
     543                 :     }
     544                 : 
     545               0 :     static inline int negifaddoverflows(float& result, float a, float b) {
     546               0 :         result = a + b;
     547               0 :         return 0;
     548                 :     }
     549                 : #else
     550                 :     static inline bool fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d,
     551                 :                                     SkFixed* result) {
     552                 :         Sk64    tmp1, tmp2;
     553                 :         tmp1.setMul(a, b);
     554                 :         tmp2.setMul(c, d);
     555                 :         tmp1.add(tmp2);
     556                 :         if (tmp1.isFixed()) {
     557                 :             *result = tmp1.getFixed();
     558                 :             return true;
     559                 :         }
     560                 :         return false;
     561                 :     }
     562                 : 
     563                 :     static inline SkFixed fracmuladdmul(SkFixed a, SkFract b, SkFixed c,
     564                 :                                         SkFract d) {
     565                 :         Sk64 tmp1, tmp2;
     566                 :         tmp1.setMul(a, b);
     567                 :         tmp2.setMul(c, d);
     568                 :         tmp1.add(tmp2);
     569                 :         return tmp1.getFract();
     570                 :     }
     571                 : 
     572                 :     static inline bool rowcol3(const SkFixed row[], const SkFixed col[],
     573                 :                                SkFixed* result) {
     574                 :         Sk64 tmp1, tmp2;
     575                 : 
     576                 :         tmp1.setMul(row[0], col[0]);    // N * fixed
     577                 :         tmp2.setMul(row[1], col[3]);    // N * fixed
     578                 :         tmp1.add(tmp2);
     579                 : 
     580                 :         tmp2.setMul(row[2], col[6]);    // N * fract
     581                 :         tmp2.roundRight(14);            // make it fixed
     582                 :         tmp1.add(tmp2);
     583                 : 
     584                 :         if (tmp1.isFixed()) {
     585                 :             *result = tmp1.getFixed();
     586                 :             return true;
     587                 :         }
     588                 :         return false;
     589                 :     }
     590                 : 
     591                 :     static inline int negifaddoverflows(SkFixed& result, SkFixed a, SkFixed b) {
     592                 :         SkFixed c = a + b;
     593                 :         result = c;
     594                 :         return (c ^ a) & (c ^ b);
     595                 :     }
     596                 : #endif
     597                 : 
     598               0 : static void normalize_perspective(SkScalar mat[9]) {
     599               0 :     if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > kMatrix22Elem) {
     600               0 :         for (int i = 0; i < 9; i++)
     601               0 :             mat[i] = SkScalarHalf(mat[i]);
     602                 :     }
     603               0 : }
     604                 : 
     605               0 : bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
     606               0 :     TypeMask aType = a.getPerspectiveTypeMaskOnly();
     607               0 :     TypeMask bType = b.getPerspectiveTypeMaskOnly();
     608                 : 
     609               0 :     if (a.isTriviallyIdentity()) {
     610               0 :         *this = b;
     611               0 :     } else if (b.isTriviallyIdentity()) {
     612               0 :         *this = a;
     613                 :     } else {
     614                 :         SkMatrix tmp;
     615                 : 
     616               0 :         if ((aType | bType) & kPerspective_Mask) {
     617               0 :             if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) {
     618               0 :                 return false;
     619                 :             }
     620               0 :             if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) {
     621               0 :                 return false;
     622                 :             }
     623               0 :             if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) {
     624               0 :                 return false;
     625                 :             }
     626                 : 
     627               0 :             if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) {
     628               0 :                 return false;
     629                 :             }
     630               0 :             if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) {
     631               0 :                 return false;
     632                 :             }
     633               0 :             if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) {
     634               0 :                 return false;
     635                 :             }
     636                 : 
     637               0 :             if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) {
     638               0 :                 return false;
     639                 :             }
     640               0 :             if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) {
     641               0 :                 return false;
     642                 :             }
     643               0 :             if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) {
     644               0 :                 return false;
     645                 :             }
     646                 : 
     647               0 :             normalize_perspective(tmp.fMat);
     648               0 :             tmp.setTypeMask(kUnknown_Mask);
     649                 :         } else {    // not perspective
     650               0 :             if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
     651               0 :                     a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
     652               0 :                 return false;
     653                 :             }
     654               0 :             if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX],
     655               0 :                       a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) {
     656               0 :                 return false;
     657                 :             }
     658               0 :             if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX],
     659               0 :                       a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) {
     660               0 :                 return false;
     661                 :             }
     662               0 :             if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX],
     663               0 :                                   a.fMat[kMTransX]) < 0) {
     664               0 :                 return false;
     665                 :             }
     666                 : 
     667               0 :             if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX],
     668               0 :                       a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) {
     669               0 :                 return false;
     670                 :             }
     671               0 :             if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX],
     672               0 :                     a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) {
     673               0 :                 return false;
     674                 :             }
     675               0 :             if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX],
     676               0 :                      a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) {
     677               0 :                 return false;
     678                 :             }
     679               0 :             if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY],
     680               0 :                                   a.fMat[kMTransY]) < 0) {
     681               0 :                 return false;
     682                 :             }
     683                 : 
     684               0 :             tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
     685               0 :             tmp.fMat[kMPersp2] = kMatrix22Elem;
     686                 :             //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
     687                 :             //SkASSERT(!(tmp.getType() & kPerspective_Mask));
     688               0 :             tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     689                 :         }
     690               0 :         *this = tmp;
     691                 :     }
     692               0 :     return true;
     693                 : }
     694                 : 
     695               0 : bool SkMatrix::preConcat(const SkMatrix& mat) {
     696                 :     // check for identity first, so we don't do a needless copy of ourselves
     697                 :     // to ourselves inside setConcat()
     698               0 :     return mat.isIdentity() || this->setConcat(*this, mat);
     699                 : }
     700                 : 
     701               0 : bool SkMatrix::postConcat(const SkMatrix& mat) {
     702                 :     // check for identity first, so we don't do a needless copy of ourselves
     703                 :     // to ourselves inside setConcat()
     704               0 :     return mat.isIdentity() || this->setConcat(mat, *this);
     705                 : }
     706                 : 
     707                 : ///////////////////////////////////////////////////////////////////////////////
     708                 : 
     709                 : /*  Matrix inversion is very expensive, but also the place where keeping
     710                 :     precision may be most important (here and matrix concat). Hence to avoid
     711                 :     bitmap blitting artifacts when walking the inverse, we use doubles for
     712                 :     the intermediate math, even though we know that is more expensive.
     713                 :     The fixed counter part is us using Sk64 for temp calculations.
     714                 :  */
     715                 : 
     716                 : #ifdef SK_SCALAR_IS_FLOAT
     717                 :     typedef double SkDetScalar;
     718                 :     #define SkPerspMul(a, b)            SkScalarMul(a, b)
     719                 :     #define SkScalarMulShift(a, b, s)   SkDoubleToFloat((a) * (b))
     720               0 :     static double sk_inv_determinant(const float mat[9], int isPerspective,
     721                 :                                     int* /* (only used in Fixed case) */) {
     722                 :         double det;
     723                 : 
     724               0 :         if (isPerspective) {
     725               0 :             det =   mat[SkMatrix::kMScaleX] * ((double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp2] - (double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp1]) +
     726               0 :                     mat[SkMatrix::kMSkewX] * ((double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp0] - (double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp2]) +
     727               0 :                     mat[SkMatrix::kMTransX] * ((double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp1] - (double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp0]);
     728                 :         } else {
     729               0 :             det =   (double)mat[SkMatrix::kMScaleX] * mat[SkMatrix::kMScaleY] - (double)mat[SkMatrix::kMSkewX] * mat[SkMatrix::kMSkewY];
     730                 :         }
     731                 : 
     732                 :         // Since the determinant is on the order of the cube of the matrix members,
     733                 :         // compare to the cube of the default nearly-zero constant (although an
     734                 :         // estimate of the condition number would be better if it wasn't so expensive).
     735               0 :         if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
     736               0 :             return 0;
     737                 :         }
     738               0 :         return 1.0 / det;
     739                 :     }
     740                 :     // we declar a,b,c,d to all be doubles, because we want to perform
     741                 :     // double-precision muls and subtract, even though the original values are
     742                 :     // from the matrix, which are floats.
     743               0 :     static float inline mul_diff_scale(double a, double b, double c, double d,
     744                 :                                        double scale) {
     745               0 :         return SkDoubleToFloat((a * b - c * d) * scale);
     746                 :     }
     747                 : #else
     748                 :     typedef SkFixed SkDetScalar;
     749                 :     #define SkPerspMul(a, b)            SkFractMul(a, b)
     750                 :     #define SkScalarMulShift(a, b, s)   SkMulShift(a, b, s)
     751                 :     static void set_muladdmul(Sk64* dst, int32_t a, int32_t b, int32_t c,
     752                 :                               int32_t d) {
     753                 :         Sk64 tmp;
     754                 :         dst->setMul(a, b);
     755                 :         tmp.setMul(c, d);
     756                 :         dst->add(tmp);
     757                 :     }
     758                 : 
     759                 :     static SkFixed sk_inv_determinant(const SkFixed mat[9], int isPerspective,
     760                 :                                       int* shift) {
     761                 :         Sk64    tmp1, tmp2;
     762                 : 
     763                 :         if (isPerspective) {
     764                 :             tmp1.setMul(mat[SkMatrix::kMScaleX], fracmuladdmul(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], -mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1]));
     765                 :             tmp2.setMul(mat[SkMatrix::kMSkewX], fracmuladdmul(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], -mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2]));
     766                 :             tmp1.add(tmp2);
     767                 :             tmp2.setMul(mat[SkMatrix::kMTransX], fracmuladdmul(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], -mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]));
     768                 :             tmp1.add(tmp2);
     769                 :         } else {
     770                 :             tmp1.setMul(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY]);
     771                 :             tmp2.setMul(mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
     772                 :             tmp1.sub(tmp2);
     773                 :         }
     774                 : 
     775                 :         int s = tmp1.getClzAbs();
     776                 :         *shift = s;
     777                 : 
     778                 :         SkFixed denom;
     779                 :         if (s <= 32) {
     780                 :             denom = tmp1.getShiftRight(33 - s);
     781                 :         } else {
     782                 :             denom = (int32_t)tmp1.fLo << (s - 33);
     783                 :         }
     784                 : 
     785                 :         if (denom == 0) {
     786                 :             return 0;
     787                 :         }
     788                 :         /** This could perhaps be a special fractdiv function, since both of its
     789                 :             arguments are known to have bit 31 clear and bit 30 set (when they
     790                 :             are made positive), thus eliminating the need for calling clz()
     791                 :         */
     792                 :         return SkFractDiv(SK_Fract1, denom);
     793                 :     }
     794                 : #endif
     795                 : 
     796               0 : void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
     797               0 :     affine[kAScaleX] = SK_Scalar1;
     798               0 :     affine[kASkewY] = 0;
     799               0 :     affine[kASkewX] = 0;
     800               0 :     affine[kAScaleY] = SK_Scalar1;
     801               0 :     affine[kATransX] = 0;
     802               0 :     affine[kATransY] = 0;
     803               0 : }
     804                 : 
     805               0 : bool SkMatrix::asAffine(SkScalar affine[6]) const {
     806               0 :     if (this->hasPerspective()) {
     807               0 :         return false;
     808                 :     }
     809               0 :     if (affine) {
     810               0 :         affine[kAScaleX] = this->fMat[kMScaleX];
     811               0 :         affine[kASkewY] = this->fMat[kMSkewY];
     812               0 :         affine[kASkewX] = this->fMat[kMSkewX];
     813               0 :         affine[kAScaleY] = this->fMat[kMScaleY];
     814               0 :         affine[kATransX] = this->fMat[kMTransX];
     815               0 :         affine[kATransY] = this->fMat[kMTransY];
     816                 :     }
     817               0 :     return true;
     818                 : }
     819                 : 
     820               0 : bool SkMatrix::invert(SkMatrix* inv) const {
     821               0 :     int         isPersp = this->hasPerspective();
     822                 :     int         shift;
     823               0 :     SkDetScalar scale = sk_inv_determinant(fMat, isPersp, &shift);
     824                 : 
     825               0 :     if (scale == 0) { // underflow
     826               0 :         return false;
     827                 :     }
     828                 : 
     829               0 :     if (inv) {
     830                 :         SkMatrix tmp;
     831               0 :         if (inv == this) {
     832               0 :             inv = &tmp;
     833                 :         }
     834               0 :         inv->setTypeMask(kUnknown_Mask);
     835                 : 
     836               0 :         if (isPersp) {
     837               0 :             shift = 61 - shift;
     838               0 :             inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift);
     839               0 :             inv->fMat[kMSkewX]  = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX],  fMat[kMPersp2]), scale, shift);
     840               0 :             inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift);
     841                 : 
     842               0 :             inv->fMat[kMSkewY]  = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY],   fMat[kMPersp2]), scale, shift);
     843               0 :             inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX],  fMat[kMPersp0]), scale, shift);
     844               0 :             inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift);
     845                 : 
     846               0 :             inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift);             
     847               0 :             inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift);
     848               0 :             inv->fMat[kMPersp2] = SkScalarMulShift(SkScalarMul(fMat[kMScaleX], fMat[kMScaleY]) - SkScalarMul(fMat[kMSkewX], fMat[kMSkewY]), scale, shift);
     849                 : #ifdef SK_SCALAR_IS_FIXED
     850                 :             if (SkAbs32(inv->fMat[kMPersp2]) > SK_Fixed1) {
     851                 :                 Sk64    tmp;
     852                 : 
     853                 :                 tmp.set(SK_Fract1);
     854                 :                 tmp.shiftLeft(16);
     855                 :                 tmp.div(inv->fMat[kMPersp2], Sk64::kRound_DivOption);
     856                 : 
     857                 :                 SkFract scale = tmp.get32();
     858                 : 
     859                 :                 for (int i = 0; i < 9; i++) {
     860                 :                     inv->fMat[i] = SkFractMul(inv->fMat[i], scale);
     861                 :                 }
     862                 :             }
     863                 :             inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
     864                 : #endif
     865               0 :             inv->setTypeMask(kUnknown_Mask);
     866                 :         } else {   // not perspective
     867                 : #ifdef SK_SCALAR_IS_FIXED
     868                 :             Sk64    tx, ty;
     869                 :             int     clzNumer;
     870                 : 
     871                 :             // check the 2x2 for overflow
     872                 :             {
     873                 :                 int32_t value = SkAbs32(fMat[kMScaleY]);
     874                 :                 value |= SkAbs32(fMat[kMSkewX]);
     875                 :                 value |= SkAbs32(fMat[kMScaleX]);
     876                 :                 value |= SkAbs32(fMat[kMSkewY]);
     877                 :                 clzNumer = SkCLZ(value);
     878                 :                 if (shift - clzNumer > 31)
     879                 :                     return false;   // overflow
     880                 :             }
     881                 : 
     882                 :             set_muladdmul(&tx, fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX]);
     883                 :             set_muladdmul(&ty, fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY]);
     884                 :             // check tx,ty for overflow
     885                 :             clzNumer = SkCLZ(SkAbs32(tx.fHi) | SkAbs32(ty.fHi));
     886                 :             if (shift - clzNumer > 14) {
     887                 :                 return false;   // overflow
     888                 :             }
     889                 : 
     890                 :             int fixedShift = 61 - shift;
     891                 :             int sk64shift = 44 - shift + clzNumer;
     892                 : 
     893                 :             inv->fMat[kMScaleX] = SkMulShift(fMat[kMScaleY], scale, fixedShift);
     894                 :             inv->fMat[kMSkewX]  = SkMulShift(-fMat[kMSkewX], scale, fixedShift);
     895                 :             inv->fMat[kMTransX] = SkMulShift(tx.getShiftRight(33 - clzNumer), scale, sk64shift);
     896                 :                 
     897                 :             inv->fMat[kMSkewY]  = SkMulShift(-fMat[kMSkewY], scale, fixedShift);
     898                 :             inv->fMat[kMScaleY] = SkMulShift(fMat[kMScaleX], scale, fixedShift);
     899                 :             inv->fMat[kMTransY] = SkMulShift(ty.getShiftRight(33 - clzNumer), scale, sk64shift);
     900                 : #else
     901               0 :             inv->fMat[kMScaleX] = SkDoubleToFloat(fMat[kMScaleY] * scale);
     902               0 :             inv->fMat[kMSkewX] = SkDoubleToFloat(-fMat[kMSkewX] * scale);
     903               0 :             inv->fMat[kMTransX] = mul_diff_scale(fMat[kMSkewX], fMat[kMTransY],
     904               0 :                                      fMat[kMScaleY], fMat[kMTransX], scale);
     905                 :                 
     906               0 :             inv->fMat[kMSkewY] = SkDoubleToFloat(-fMat[kMSkewY] * scale);
     907               0 :             inv->fMat[kMScaleY] = SkDoubleToFloat(fMat[kMScaleX] * scale);
     908               0 :             inv->fMat[kMTransY] = mul_diff_scale(fMat[kMSkewY], fMat[kMTransX],
     909               0 :                                         fMat[kMScaleX], fMat[kMTransY], scale);
     910                 : #endif
     911               0 :             inv->fMat[kMPersp0] = 0;
     912               0 :             inv->fMat[kMPersp1] = 0;
     913               0 :             inv->fMat[kMPersp2] = kMatrix22Elem;
     914               0 :             inv->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
     915                 :         }
     916                 : 
     917               0 :         if (inv == &tmp) {
     918               0 :             *(SkMatrix*)this = tmp;
     919                 :         }
     920                 :     }
     921               0 :     return true;
     922                 : }
     923                 : 
     924                 : ///////////////////////////////////////////////////////////////////////////////
     925                 : 
     926               0 : void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
     927                 :                             const SkPoint src[], int count) {
     928               0 :     SkASSERT(m.getType() == 0);
     929                 : 
     930               0 :     if (dst != src && count > 0)
     931               0 :         memcpy(dst, src, count * sizeof(SkPoint));
     932               0 : }
     933                 : 
     934               0 : void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
     935                 :                          const SkPoint src[], int count) {
     936               0 :     SkASSERT(m.getType() == kTranslate_Mask);
     937                 : 
     938               0 :     if (count > 0) {
     939               0 :         SkScalar tx = m.fMat[kMTransX];
     940               0 :         SkScalar ty = m.fMat[kMTransY];
     941               0 :         do {
     942               0 :             dst->fY = src->fY + ty;
     943               0 :             dst->fX = src->fX + tx;
     944               0 :             src += 1;
     945               0 :             dst += 1;
     946                 :         } while (--count);
     947                 :     }
     948               0 : }
     949                 : 
     950               0 : void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
     951                 :                          const SkPoint src[], int count) {
     952               0 :     SkASSERT(m.getType() == kScale_Mask);
     953                 : 
     954               0 :     if (count > 0) {
     955               0 :         SkScalar mx = m.fMat[kMScaleX];
     956               0 :         SkScalar my = m.fMat[kMScaleY];
     957               0 :         do {
     958               0 :             dst->fY = SkScalarMul(src->fY, my);
     959               0 :             dst->fX = SkScalarMul(src->fX, mx);
     960               0 :             src += 1;
     961               0 :             dst += 1;
     962                 :         } while (--count);
     963                 :     }
     964               0 : }
     965                 : 
     966               0 : void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
     967                 :                               const SkPoint src[], int count) {
     968               0 :     SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
     969                 : 
     970               0 :     if (count > 0) {
     971               0 :         SkScalar mx = m.fMat[kMScaleX];
     972               0 :         SkScalar my = m.fMat[kMScaleY];
     973               0 :         SkScalar tx = m.fMat[kMTransX];
     974               0 :         SkScalar ty = m.fMat[kMTransY];
     975               0 :         do {
     976               0 :             dst->fY = SkScalarMulAdd(src->fY, my, ty);
     977               0 :             dst->fX = SkScalarMulAdd(src->fX, mx, tx);
     978               0 :             src += 1;
     979               0 :             dst += 1;
     980                 :         } while (--count);
     981                 :     }
     982               0 : }
     983                 : 
     984               0 : void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
     985                 :                        const SkPoint src[], int count) {
     986               0 :     SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
     987                 : 
     988               0 :     if (count > 0) {
     989               0 :         SkScalar mx = m.fMat[kMScaleX];
     990               0 :         SkScalar my = m.fMat[kMScaleY];
     991               0 :         SkScalar kx = m.fMat[kMSkewX];
     992               0 :         SkScalar ky = m.fMat[kMSkewY];
     993               0 :         do {
     994               0 :             SkScalar sy = src->fY;
     995               0 :             SkScalar sx = src->fX;
     996               0 :             src += 1;
     997               0 :             dst->fY = SkScalarMul(sx, ky) + SkScalarMul(sy, my);
     998               0 :             dst->fX = SkScalarMul(sx, mx) + SkScalarMul(sy, kx);
     999               0 :             dst += 1;
    1000                 :         } while (--count);
    1001                 :     }
    1002               0 : }
    1003                 : 
    1004               0 : void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
    1005                 :                             const SkPoint src[], int count) {
    1006               0 :     SkASSERT(!m.hasPerspective());
    1007                 : 
    1008               0 :     if (count > 0) {
    1009               0 :         SkScalar mx = m.fMat[kMScaleX];
    1010               0 :         SkScalar my = m.fMat[kMScaleY];
    1011               0 :         SkScalar kx = m.fMat[kMSkewX];
    1012               0 :         SkScalar ky = m.fMat[kMSkewY];
    1013               0 :         SkScalar tx = m.fMat[kMTransX];
    1014               0 :         SkScalar ty = m.fMat[kMTransY];
    1015               0 :         do {
    1016               0 :             SkScalar sy = src->fY;
    1017               0 :             SkScalar sx = src->fX;
    1018               0 :             src += 1;
    1019               0 :             dst->fY = SkScalarMul(sx, ky) + SkScalarMulAdd(sy, my, ty);
    1020               0 :             dst->fX = SkScalarMul(sx, mx) + SkScalarMulAdd(sy, kx, tx);
    1021               0 :             dst += 1;
    1022                 :         } while (--count);
    1023                 :     }
    1024               0 : }
    1025                 : 
    1026               0 : void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
    1027                 :                          const SkPoint src[], int count) {
    1028               0 :     SkASSERT(m.hasPerspective());
    1029                 : 
    1030                 : #ifdef SK_SCALAR_IS_FIXED
    1031                 :     SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]);
    1032                 : #endif
    1033                 : 
    1034               0 :     if (count > 0) {
    1035               0 :         do {
    1036               0 :             SkScalar sy = src->fY;
    1037               0 :             SkScalar sx = src->fX;
    1038               0 :             src += 1;
    1039                 : 
    1040               0 :             SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
    1041               0 :                          SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
    1042               0 :             SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
    1043               0 :                          SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
    1044                 : #ifdef SK_SCALAR_IS_FIXED
    1045                 :             SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
    1046                 :                         SkFractMul(sy, m.fMat[kMPersp1]) + persp2;
    1047                 : #else
    1048               0 :             float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
    1049               0 :                       SkScalarMulAdd(sy, m.fMat[kMPersp1], m.fMat[kMPersp2]);
    1050                 : #endif
    1051               0 :             if (z) {
    1052               0 :                 z = SkScalarFastInvert(z);
    1053                 :             }
    1054                 : 
    1055               0 :             dst->fY = SkScalarMul(y, z);
    1056               0 :             dst->fX = SkScalarMul(x, z);
    1057               0 :             dst += 1;
    1058                 :         } while (--count);
    1059                 :     }
    1060               0 : }
    1061                 : 
    1062                 : const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
    1063                 :     SkMatrix::Identity_pts, SkMatrix::Trans_pts,
    1064                 :     SkMatrix::Scale_pts,    SkMatrix::ScaleTrans_pts,
    1065                 :     SkMatrix::Rot_pts,      SkMatrix::RotTrans_pts,
    1066                 :     SkMatrix::Rot_pts,      SkMatrix::RotTrans_pts,
    1067                 :     // repeat the persp proc 8 times
    1068                 :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
    1069                 :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
    1070                 :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts,
    1071                 :     SkMatrix::Persp_pts,    SkMatrix::Persp_pts
    1072                 : };
    1073                 : 
    1074               0 : void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
    1075               0 :     SkASSERT((dst && src && count > 0) || count == 0);
    1076                 :     // no partial overlap
    1077               0 :     SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= count);
    1078                 : 
    1079               0 :     this->getMapPtsProc()(*this, dst, src, count);
    1080               0 : }
    1081                 : 
    1082                 : ///////////////////////////////////////////////////////////////////////////////
    1083                 : 
    1084               0 : void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
    1085               0 :     if (this->hasPerspective()) {
    1086                 :         SkPoint origin;
    1087                 : 
    1088               0 :         MapXYProc proc = this->getMapXYProc();
    1089               0 :         proc(*this, 0, 0, &origin);
    1090                 : 
    1091               0 :         for (int i = count - 1; i >= 0; --i) {
    1092                 :             SkPoint tmp;
    1093                 : 
    1094               0 :             proc(*this, src[i].fX, src[i].fY, &tmp);
    1095               0 :             dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
    1096                 :         }
    1097                 :     } else {
    1098               0 :         SkMatrix tmp = *this;
    1099                 : 
    1100               0 :         tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
    1101               0 :         tmp.clearTypeMask(kTranslate_Mask);
    1102               0 :         tmp.mapPoints(dst, src, count);
    1103                 :     }
    1104               0 : }
    1105                 : 
    1106               0 : bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
    1107               0 :     SkASSERT(dst && &src);
    1108                 : 
    1109               0 :     if (this->rectStaysRect()) {
    1110               0 :         this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
    1111               0 :         dst->sort();
    1112               0 :         return true;
    1113                 :     } else {
    1114                 :         SkPoint quad[4];
    1115                 : 
    1116               0 :         src.toQuad(quad);
    1117               0 :         this->mapPoints(quad, quad, 4);
    1118               0 :         dst->set(quad, 4);
    1119               0 :         return false;
    1120                 :     }
    1121                 : }
    1122                 : 
    1123               0 : SkScalar SkMatrix::mapRadius(SkScalar radius) const {
    1124                 :     SkVector    vec[2];
    1125                 : 
    1126               0 :     vec[0].set(radius, 0);
    1127               0 :     vec[1].set(0, radius);
    1128               0 :     this->mapVectors(vec, 2);
    1129                 : 
    1130               0 :     SkScalar d0 = vec[0].length();
    1131               0 :     SkScalar d1 = vec[1].length();
    1132                 : 
    1133               0 :     return SkScalarMean(d0, d1);
    1134                 : }
    1135                 : 
    1136                 : ///////////////////////////////////////////////////////////////////////////////
    1137                 : 
    1138               0 : void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1139                 :                         SkPoint* pt) {
    1140               0 :     SkASSERT(m.hasPerspective());
    1141                 : 
    1142               0 :     SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
    1143               0 :                  SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
    1144               0 :     SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
    1145               0 :                  SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
    1146                 : #ifdef SK_SCALAR_IS_FIXED
    1147                 :     SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
    1148                 :                 SkFractMul(sy, m.fMat[kMPersp1]) +
    1149                 :                 SkFractToFixed(m.fMat[kMPersp2]);
    1150                 : #else
    1151               0 :     float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
    1152               0 :               SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
    1153                 : #endif
    1154               0 :     if (z) {
    1155               0 :         z = SkScalarFastInvert(z);
    1156                 :     }
    1157               0 :     pt->fX = SkScalarMul(x, z);
    1158               0 :     pt->fY = SkScalarMul(y, z);
    1159               0 : }
    1160                 : 
    1161                 : #ifdef SK_SCALAR_IS_FIXED
    1162                 : static SkFixed fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d) {
    1163                 :     Sk64    tmp, tmp1;
    1164                 : 
    1165                 :     tmp.setMul(a, b);
    1166                 :     tmp1.setMul(c, d);
    1167                 :     return tmp.addGetFixed(tmp1);
    1168                 : //  tmp.add(tmp1);
    1169                 : //  return tmp.getFixed();
    1170                 : }
    1171                 : #endif
    1172                 : 
    1173               0 : void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1174                 :                            SkPoint* pt) {
    1175               0 :     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
    1176                 :     
    1177                 : #ifdef SK_SCALAR_IS_FIXED
    1178                 :     pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) +
    1179                 :              m.fMat[kMTransX];
    1180                 :     pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) +
    1181                 :              m.fMat[kMTransY];
    1182                 : #else
    1183               0 :     pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
    1184               0 :              SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
    1185               0 :     pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
    1186               0 :              SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
    1187                 : #endif
    1188               0 : }
    1189                 : 
    1190               0 : void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1191                 :                       SkPoint* pt) {
    1192               0 :     SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
    1193               0 :     SkASSERT(0 == m.fMat[kMTransX]);
    1194               0 :     SkASSERT(0 == m.fMat[kMTransY]);
    1195                 : 
    1196                 : #ifdef SK_SCALAR_IS_FIXED
    1197                 :     pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]);
    1198                 :     pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]);
    1199                 : #else
    1200               0 :     pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
    1201               0 :              SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
    1202               0 :     pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
    1203               0 :              SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
    1204                 : #endif
    1205               0 : }
    1206                 : 
    1207               0 : void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1208                 :                              SkPoint* pt) {
    1209               0 :     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
    1210                 :              == kScale_Mask);
    1211                 :     
    1212               0 :     pt->fX = SkScalarMulAdd(sx, m.fMat[kMScaleX], m.fMat[kMTransX]);
    1213               0 :     pt->fY = SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
    1214               0 : }
    1215                 : 
    1216               0 : void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1217                 :                         SkPoint* pt) {
    1218               0 :     SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
    1219                 :              == kScale_Mask);
    1220               0 :     SkASSERT(0 == m.fMat[kMTransX]);
    1221               0 :     SkASSERT(0 == m.fMat[kMTransY]);
    1222                 : 
    1223               0 :     pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]);
    1224               0 :     pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]);
    1225               0 : }
    1226                 : 
    1227               0 : void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1228                 :                         SkPoint* pt) {
    1229               0 :     SkASSERT(m.getType() == kTranslate_Mask);
    1230                 : 
    1231               0 :     pt->fX = sx + m.fMat[kMTransX];
    1232               0 :     pt->fY = sy + m.fMat[kMTransY];
    1233               0 : }
    1234                 : 
    1235               0 : void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
    1236                 :                            SkPoint* pt) {
    1237               0 :     SkASSERT(0 == m.getType());
    1238                 : 
    1239               0 :     pt->fX = sx;
    1240               0 :     pt->fY = sy;
    1241               0 : }
    1242                 : 
    1243                 : const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
    1244                 :     SkMatrix::Identity_xy, SkMatrix::Trans_xy,
    1245                 :     SkMatrix::Scale_xy,    SkMatrix::ScaleTrans_xy,
    1246                 :     SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
    1247                 :     SkMatrix::Rot_xy,      SkMatrix::RotTrans_xy,
    1248                 :     // repeat the persp proc 8 times
    1249                 :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
    1250                 :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
    1251                 :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy,
    1252                 :     SkMatrix::Persp_xy,    SkMatrix::Persp_xy
    1253                 : };
    1254                 : 
    1255                 : ///////////////////////////////////////////////////////////////////////////////
    1256                 : 
    1257                 : // if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
    1258                 : #ifdef SK_SCALAR_IS_FIXED
    1259                 :     typedef SkFract             SkPerspElemType;
    1260                 :     #define PerspNearlyZero(x)  (SkAbs32(x) < (SK_Fract1 >> 26))
    1261                 : #else
    1262                 :     typedef float               SkPerspElemType;
    1263                 :     #define PerspNearlyZero(x)  SkScalarNearlyZero(x, (1.0f / (1 << 26)))
    1264                 : #endif
    1265                 : 
    1266               0 : bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
    1267               0 :     if (PerspNearlyZero(fMat[kMPersp0])) {
    1268               0 :         if (stepX || stepY) {
    1269               0 :             if (PerspNearlyZero(fMat[kMPersp1]) &&
    1270               0 :                     PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem)) {
    1271               0 :                 if (stepX) {
    1272               0 :                     *stepX = SkScalarToFixed(fMat[kMScaleX]);
    1273                 :                 }
    1274               0 :                 if (stepY) {
    1275               0 :                     *stepY = SkScalarToFixed(fMat[kMSkewY]);
    1276                 :                 }
    1277                 :             } else {
    1278                 : #ifdef SK_SCALAR_IS_FIXED
    1279                 :                 SkFixed z = SkFractMul(y, fMat[kMPersp1]) +
    1280                 :                             SkFractToFixed(fMat[kMPersp2]);
    1281                 : #else
    1282               0 :                 float z = y * fMat[kMPersp1] + fMat[kMPersp2];
    1283                 : #endif
    1284               0 :                 if (stepX) {
    1285               0 :                     *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z));
    1286                 :                 }
    1287               0 :                 if (stepY) {
    1288               0 :                     *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z));
    1289                 :                 }
    1290                 :             }
    1291                 :         }
    1292               0 :         return true;
    1293                 :     }
    1294               0 :     return false;
    1295                 : }
    1296                 : 
    1297                 : ///////////////////////////////////////////////////////////////////////////////
    1298                 : 
    1299                 : #include "SkPerspIter.h"
    1300                 : 
    1301               0 : SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
    1302               0 :         : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
    1303                 :     SkPoint pt;
    1304                 : 
    1305               0 :     SkMatrix::Persp_xy(m, x0, y0, &pt);
    1306               0 :     fX = SkScalarToFixed(pt.fX);
    1307               0 :     fY = SkScalarToFixed(pt.fY);
    1308               0 : }
    1309                 : 
    1310               0 : int SkPerspIter::next() {
    1311               0 :     int n = fCount;
    1312                 :     
    1313               0 :     if (0 == n) {
    1314               0 :         return 0;
    1315                 :     }
    1316                 :     SkPoint pt;
    1317               0 :     SkFixed x = fX;
    1318               0 :     SkFixed y = fY;
    1319                 :     SkFixed dx, dy;
    1320                 : 
    1321               0 :     if (n >= kCount) {
    1322               0 :         n = kCount;
    1323               0 :         fSX += SkIntToScalar(kCount);
    1324               0 :         SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
    1325               0 :         fX = SkScalarToFixed(pt.fX);
    1326               0 :         fY = SkScalarToFixed(pt.fY);
    1327               0 :         dx = (fX - x) >> kShift;
    1328               0 :         dy = (fY - y) >> kShift;
    1329                 :     } else {
    1330               0 :         fSX += SkIntToScalar(n);
    1331               0 :         SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
    1332               0 :         fX = SkScalarToFixed(pt.fX);
    1333               0 :         fY = SkScalarToFixed(pt.fY);
    1334               0 :         dx = (fX - x) / n;
    1335               0 :         dy = (fY - y) / n;
    1336                 :     }
    1337                 : 
    1338               0 :     SkFixed* p = fStorage;
    1339               0 :     for (int i = 0; i < n; i++) {
    1340               0 :         *p++ = x; x += dx;
    1341               0 :         *p++ = y; y += dy;
    1342                 :     }
    1343                 :     
    1344               0 :     fCount -= n;
    1345               0 :     return n;
    1346                 : }
    1347                 : 
    1348                 : ///////////////////////////////////////////////////////////////////////////////
    1349                 : 
    1350                 : #ifdef SK_SCALAR_IS_FIXED
    1351                 : 
    1352                 : static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
    1353                 :     SkFixed x = SK_Fixed1, y = SK_Fixed1;
    1354                 :     SkPoint pt1, pt2;
    1355                 :     Sk64    w1, w2;
    1356                 : 
    1357                 :     if (count > 1) {
    1358                 :         pt1.fX = poly[1].fX - poly[0].fX;
    1359                 :         pt1.fY = poly[1].fY - poly[0].fY;
    1360                 :         y = SkPoint::Length(pt1.fX, pt1.fY);
    1361                 :         if (y == 0) {
    1362                 :             return false;
    1363                 :         }
    1364                 :         switch (count) {
    1365                 :             case 2:
    1366                 :                 break;
    1367                 :             case 3:
    1368                 :                 pt2.fX = poly[0].fY - poly[2].fY;
    1369                 :                 pt2.fY = poly[2].fX - poly[0].fX;
    1370                 :                 goto CALC_X;
    1371                 :             default:
    1372                 :                 pt2.fX = poly[0].fY - poly[3].fY;
    1373                 :                 pt2.fY = poly[3].fX - poly[0].fX;
    1374                 :             CALC_X:
    1375                 :                 w1.setMul(pt1.fX, pt2.fX);
    1376                 :                 w2.setMul(pt1.fY, pt2.fY);
    1377                 :                 w1.add(w2);
    1378                 :                 w1.div(y, Sk64::kRound_DivOption);
    1379                 :                 if (!w1.is32()) {
    1380                 :                     return false;
    1381                 :                 }
    1382                 :                 x = w1.get32();
    1383                 :                 break;
    1384                 :         }
    1385                 :     }
    1386                 :     pt->set(x, y);
    1387                 :     return true;
    1388                 : }
    1389                 : 
    1390                 : bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
    1391                 :                          const SkPoint& scalePt) {
    1392                 :     // need to check if SkFixedDiv overflows...
    1393                 : 
    1394                 :     const SkFixed scale = scalePt.fY;
    1395                 :     dst->fMat[kMScaleX] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
    1396                 :     dst->fMat[kMSkewY]  = SkFixedDiv(srcPt[0].fX - srcPt[1].fX, scale);
    1397                 :     dst->fMat[kMPersp0] = 0;
    1398                 :     dst->fMat[kMSkewX]  = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale);
    1399                 :     dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
    1400                 :     dst->fMat[kMPersp1] = 0;
    1401                 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1402                 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1403                 :     dst->fMat[kMPersp2] = SK_Fract1;
    1404                 :     dst->setTypeMask(kUnknown_Mask);
    1405                 :     return true;
    1406                 : }
    1407                 : 
    1408                 : bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
    1409                 :                          const SkPoint& scale) {
    1410                 :     // really, need to check if SkFixedDiv overflow'd
    1411                 : 
    1412                 :     dst->fMat[kMScaleX] = SkFixedDiv(srcPt[2].fX - srcPt[0].fX, scale.fX);
    1413                 :     dst->fMat[kMSkewY]  = SkFixedDiv(srcPt[2].fY - srcPt[0].fY, scale.fX);
    1414                 :     dst->fMat[kMPersp0] = 0;
    1415                 :     dst->fMat[kMSkewX]  = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale.fY);
    1416                 :     dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale.fY);
    1417                 :     dst->fMat[kMPersp1] = 0;
    1418                 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1419                 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1420                 :     dst->fMat[kMPersp2] = SK_Fract1;
    1421                 :     dst->setTypeMask(kUnknown_Mask);
    1422                 :     return true;
    1423                 : }
    1424                 : 
    1425                 : bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
    1426                 :                          const SkPoint& scale) {
    1427                 :     SkFract a1, a2;
    1428                 :     SkFixed x0, y0, x1, y1, x2, y2;
    1429                 : 
    1430                 :     x0 = srcPt[2].fX - srcPt[0].fX;
    1431                 :     y0 = srcPt[2].fY - srcPt[0].fY;
    1432                 :     x1 = srcPt[2].fX - srcPt[1].fX;
    1433                 :     y1 = srcPt[2].fY - srcPt[1].fY;
    1434                 :     x2 = srcPt[2].fX - srcPt[3].fX;
    1435                 :     y2 = srcPt[2].fY - srcPt[3].fY;
    1436                 : 
    1437                 :     /* check if abs(x2) > abs(y2) */
    1438                 :     if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
    1439                 :         SkFixed denom = SkMulDiv(x1, y2, x2) - y1;
    1440                 :         if (0 == denom) {
    1441                 :             return false;
    1442                 :         }
    1443                 :         a1 = SkFractDiv(SkMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
    1444                 :     } else {
    1445                 :         SkFixed denom = x1 - SkMulDiv(y1, x2, y2);
    1446                 :         if (0 == denom) {
    1447                 :             return false;
    1448                 :         }
    1449                 :         a1 = SkFractDiv(x0 - x1 - SkMulDiv(y0 - y1, x2, y2), denom);
    1450                 :     }
    1451                 : 
    1452                 :     /* check if abs(x1) > abs(y1) */
    1453                 :     if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
    1454                 :         SkFixed denom = y2 - SkMulDiv(x2, y1, x1);
    1455                 :         if (0 == denom) {
    1456                 :             return false;
    1457                 :         }
    1458                 :         a2 = SkFractDiv(y0 - y2 - SkMulDiv(x0 - x2, y1, x1), denom);
    1459                 :     } else {
    1460                 :         SkFixed denom = SkMulDiv(y2, x1, y1) - x2;
    1461                 :         if (0 == denom) {
    1462                 :             return false;
    1463                 :         }
    1464                 :         a2 = SkFractDiv(SkMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
    1465                 :     }
    1466                 : 
    1467                 :     // need to check if SkFixedDiv overflows...
    1468                 :     dst->fMat[kMScaleX] = SkFixedDiv(SkFractMul(a2, srcPt[3].fX) +
    1469                 :                                      srcPt[3].fX - srcPt[0].fX, scale.fX);
    1470                 :     dst->fMat[kMSkewY]  = SkFixedDiv(SkFractMul(a2, srcPt[3].fY) +
    1471                 :                                      srcPt[3].fY - srcPt[0].fY, scale.fX);
    1472                 :     dst->fMat[kMPersp0] = SkFixedDiv(a2, scale.fX);
    1473                 :     dst->fMat[kMSkewX]  = SkFixedDiv(SkFractMul(a1, srcPt[1].fX) +
    1474                 :                                      srcPt[1].fX - srcPt[0].fX, scale.fY);
    1475                 :     dst->fMat[kMScaleY] = SkFixedDiv(SkFractMul(a1, srcPt[1].fY) +
    1476                 :                                      srcPt[1].fY - srcPt[0].fY, scale.fY);
    1477                 :     dst->fMat[kMPersp1] = SkFixedDiv(a1, scale.fY);
    1478                 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1479                 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1480                 :     dst->fMat[kMPersp2] = SK_Fract1;
    1481                 :     dst->setTypeMask(kUnknown_Mask);
    1482                 :     return true;
    1483                 : }
    1484                 : 
    1485                 : #else   /* Scalar is float */
    1486                 : 
    1487               0 : static inline bool checkForZero(float x) {
    1488               0 :     return x*x == 0;
    1489                 : }
    1490                 : 
    1491               0 : static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
    1492               0 :     float   x = 1, y = 1;
    1493                 :     SkPoint pt1, pt2;
    1494                 : 
    1495               0 :     if (count > 1) {
    1496               0 :         pt1.fX = poly[1].fX - poly[0].fX;
    1497               0 :         pt1.fY = poly[1].fY - poly[0].fY;
    1498               0 :         y = SkPoint::Length(pt1.fX, pt1.fY);
    1499               0 :         if (checkForZero(y)) {
    1500               0 :             return false;
    1501                 :         }
    1502               0 :         switch (count) {
    1503                 :             case 2:
    1504               0 :                 break;
    1505                 :             case 3:
    1506               0 :                 pt2.fX = poly[0].fY - poly[2].fY;
    1507               0 :                 pt2.fY = poly[2].fX - poly[0].fX;
    1508               0 :                 goto CALC_X;
    1509                 :             default:
    1510               0 :                 pt2.fX = poly[0].fY - poly[3].fY;
    1511               0 :                 pt2.fY = poly[3].fX - poly[0].fX;
    1512                 :             CALC_X:
    1513                 :                 x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) +
    1514               0 :                                 SkScalarMul(pt1.fY, pt2.fY), y);
    1515               0 :                 break;
    1516                 :         }
    1517                 :     }
    1518               0 :     pt->set(x, y);
    1519               0 :     return true;
    1520                 : }
    1521                 : 
    1522               0 : bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
    1523                 :                          const SkPoint& scale) {
    1524               0 :     float invScale = 1 / scale.fY;
    1525                 : 
    1526               0 :     dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
    1527               0 :     dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
    1528               0 :     dst->fMat[kMPersp0] = 0;
    1529               0 :     dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
    1530               0 :     dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
    1531               0 :     dst->fMat[kMPersp1] = 0;
    1532               0 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1533               0 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1534               0 :     dst->fMat[kMPersp2] = 1;
    1535               0 :     dst->setTypeMask(kUnknown_Mask);
    1536               0 :     return true;
    1537                 : }
    1538                 : 
    1539               0 : bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
    1540                 :                          const SkPoint& scale) {
    1541               0 :     float invScale = 1 / scale.fX;
    1542               0 :     dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
    1543               0 :     dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
    1544               0 :     dst->fMat[kMPersp0] = 0;
    1545                 : 
    1546               0 :     invScale = 1 / scale.fY;
    1547               0 :     dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
    1548               0 :     dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
    1549               0 :     dst->fMat[kMPersp1] = 0;
    1550                 : 
    1551               0 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1552               0 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1553               0 :     dst->fMat[kMPersp2] = 1;
    1554               0 :     dst->setTypeMask(kUnknown_Mask);
    1555               0 :     return true;
    1556                 : }
    1557                 : 
    1558               0 : bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
    1559                 :                          const SkPoint& scale) {
    1560                 :     float   a1, a2;
    1561                 :     float   x0, y0, x1, y1, x2, y2;
    1562                 : 
    1563               0 :     x0 = srcPt[2].fX - srcPt[0].fX;
    1564               0 :     y0 = srcPt[2].fY - srcPt[0].fY;
    1565               0 :     x1 = srcPt[2].fX - srcPt[1].fX;
    1566               0 :     y1 = srcPt[2].fY - srcPt[1].fY;
    1567               0 :     x2 = srcPt[2].fX - srcPt[3].fX;
    1568               0 :     y2 = srcPt[2].fY - srcPt[3].fY;
    1569                 : 
    1570                 :     /* check if abs(x2) > abs(y2) */
    1571               0 :     if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
    1572               0 :         float denom = SkScalarMulDiv(x1, y2, x2) - y1;
    1573               0 :         if (checkForZero(denom)) {
    1574               0 :             return false;
    1575                 :         }
    1576               0 :         a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
    1577                 :     } else {
    1578               0 :         float denom = x1 - SkScalarMulDiv(y1, x2, y2);
    1579               0 :         if (checkForZero(denom)) {
    1580               0 :             return false;
    1581                 :         }
    1582               0 :         a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), denom);
    1583                 :     }
    1584                 : 
    1585                 :     /* check if abs(x1) > abs(y1) */
    1586               0 :     if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
    1587               0 :         float denom = y2 - SkScalarMulDiv(x2, y1, x1);
    1588               0 :         if (checkForZero(denom)) {
    1589               0 :             return false;
    1590                 :         }
    1591               0 :         a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), denom);
    1592                 :     } else {
    1593               0 :         float denom = SkScalarMulDiv(y2, x1, y1) - x2;
    1594               0 :         if (checkForZero(denom)) {
    1595               0 :             return false;
    1596                 :         }
    1597               0 :         a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
    1598                 :     }
    1599                 : 
    1600               0 :     float invScale = 1 / scale.fX;
    1601               0 :     dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) +
    1602               0 :                                       srcPt[3].fX - srcPt[0].fX, invScale);
    1603               0 :     dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) +
    1604               0 :                                      srcPt[3].fY - srcPt[0].fY, invScale);
    1605               0 :     dst->fMat[kMPersp0] = SkScalarMul(a2, invScale);
    1606               0 :     invScale = 1 / scale.fY;
    1607               0 :     dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) +
    1608               0 :                                      srcPt[1].fX - srcPt[0].fX, invScale);
    1609               0 :     dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) +
    1610               0 :                                       srcPt[1].fY - srcPt[0].fY, invScale);
    1611               0 :     dst->fMat[kMPersp1] = SkScalarMul(a1, invScale);
    1612               0 :     dst->fMat[kMTransX] = srcPt[0].fX;
    1613               0 :     dst->fMat[kMTransY] = srcPt[0].fY;
    1614               0 :     dst->fMat[kMPersp2] = 1;
    1615               0 :     dst->setTypeMask(kUnknown_Mask);
    1616               0 :     return true;
    1617                 : }
    1618                 : 
    1619                 : #endif
    1620                 : 
    1621                 : typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
    1622                 : 
    1623                 : /*  Taken from Rob Johnson's original sample code in QuickDraw GX
    1624                 : */
    1625               0 : bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
    1626                 :                              int count) {
    1627               0 :     if ((unsigned)count > 4) {
    1628               0 :         SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
    1629               0 :         return false;
    1630                 :     }
    1631                 : 
    1632               0 :     if (0 == count) {
    1633               0 :         this->reset();
    1634               0 :         return true;
    1635                 :     }
    1636               0 :     if (1 == count) {
    1637               0 :         this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
    1638               0 :         return true;
    1639                 :     }
    1640                 : 
    1641                 :     SkPoint scale;
    1642               0 :     if (!poly_to_point(&scale, src, count) ||
    1643               0 :             SkScalarNearlyZero(scale.fX) ||
    1644               0 :             SkScalarNearlyZero(scale.fY)) {
    1645               0 :         return false;
    1646                 :     }
    1647                 : 
    1648                 :     static const PolyMapProc gPolyMapProcs[] = {
    1649                 :         SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
    1650                 :     };
    1651               0 :     PolyMapProc proc = gPolyMapProcs[count - 2];
    1652                 : 
    1653                 :     SkMatrix tempMap, result;
    1654               0 :     tempMap.setTypeMask(kUnknown_Mask);
    1655                 : 
    1656               0 :     if (!proc(src, &tempMap, scale)) {
    1657               0 :         return false;
    1658                 :     }
    1659               0 :     if (!tempMap.invert(&result)) {
    1660               0 :         return false;
    1661                 :     }
    1662               0 :     if (!proc(dst, &tempMap, scale)) {
    1663               0 :         return false;
    1664                 :     }
    1665               0 :     if (!result.setConcat(tempMap, result)) {
    1666               0 :         return false;
    1667                 :     }
    1668               0 :     *this = result;
    1669               0 :     return true;
    1670                 : }
    1671                 : 
    1672                 : ///////////////////////////////////////////////////////////////////////////////
    1673                 : 
    1674               0 : SkScalar SkMatrix::getMaxStretch() const {
    1675               0 :     TypeMask mask = this->getType();
    1676                 : 
    1677               0 :     if (this->hasPerspective()) {
    1678               0 :         return -SK_Scalar1;
    1679                 :     }
    1680               0 :     if (this->isIdentity()) {
    1681               0 :         return SK_Scalar1;
    1682                 :     }
    1683               0 :     if (!(mask & kAffine_Mask)) {
    1684               0 :         return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
    1685               0 :                            SkScalarAbs(fMat[kMScaleY]));
    1686                 :     }
    1687                 :     // ignore the translation part of the matrix, just look at 2x2 portion.
    1688                 :     // compute singular values, take largest abs value.
    1689                 :     // [a b; b c] = A^T*A
    1690               0 :     SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
    1691               0 :                  SkScalarMul(fMat[kMSkewY],  fMat[kMSkewY]);
    1692               0 :     SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
    1693               0 :                  SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
    1694               0 :     SkScalar c = SkScalarMul(fMat[kMSkewX],  fMat[kMSkewX]) +
    1695               0 :                  SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
    1696                 :     // eigenvalues of A^T*A are the squared singular values of A.
    1697                 :     // characteristic equation is det((A^T*A) - l*I) = 0
    1698                 :     // l^2 - (a + c)l + (ac-b^2)
    1699                 :     // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
    1700                 :     // and roots are guaraunteed to be pos and real).
    1701                 :     SkScalar largerRoot;
    1702               0 :     SkScalar bSqd = SkScalarMul(b,b);
    1703                 :     // if upper left 2x2 is orthogonal save some math
    1704               0 :     if (bSqd <= SK_ScalarNearlyZero) {
    1705               0 :         largerRoot = SkMaxScalar(a, c);
    1706                 :     } else {
    1707               0 :         SkScalar aminusc = a - c;
    1708               0 :         SkScalar apluscdiv2 = SkScalarHalf(a + c);
    1709               0 :         SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
    1710               0 :         largerRoot = apluscdiv2 + x;
    1711                 :     }
    1712               0 :     return SkScalarSqrt(largerRoot);
    1713                 : }
    1714                 : 
    1715               0 : const SkMatrix& SkMatrix::I() {
    1716                 :     static SkMatrix gIdentity;
    1717                 :     static bool gOnce;
    1718               0 :     if (!gOnce) {
    1719               0 :         gIdentity.reset();
    1720               0 :         gOnce = true;
    1721                 :     }
    1722               0 :     return gIdentity;
    1723                 : }
    1724                 : 
    1725               0 : const SkMatrix& SkMatrix::InvalidMatrix() {
    1726                 :     static SkMatrix gInvalid;
    1727                 :     static bool gOnce;
    1728               0 :     if (!gOnce) {
    1729                 :         gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
    1730                 :                         SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
    1731               0 :                         SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
    1732               0 :         gInvalid.getType(); // force the type to be computed
    1733               0 :         gOnce = true;
    1734                 :     }
    1735               0 :     return gInvalid;
    1736                 : }
    1737                 : 
    1738                 : ///////////////////////////////////////////////////////////////////////////////
    1739                 : 
    1740               0 : uint32_t SkMatrix::flatten(void* buffer) const {
    1741                 :     // TODO write less for simple matrices
    1742               0 :     if (buffer) {
    1743               0 :         memcpy(buffer, fMat, 9 * sizeof(SkScalar));
    1744                 :     }
    1745               0 :     return 9 * sizeof(SkScalar);
    1746                 : }
    1747                 : 
    1748               0 : uint32_t SkMatrix::unflatten(const void* buffer) {
    1749               0 :     if (buffer) {
    1750               0 :         memcpy(fMat, buffer, 9 * sizeof(SkScalar));
    1751               0 :         this->setTypeMask(kUnknown_Mask);
    1752                 :     }
    1753               0 :     return 9 * sizeof(SkScalar);
    1754                 : }
    1755                 : 
    1756               0 : void SkMatrix::dump() const {
    1757               0 :     SkString str;
    1758               0 :     this->toDumpString(&str);
    1759               0 :     SkDebugf("%s\n", str.c_str());
    1760               0 : }
    1761                 : 
    1762               0 : void SkMatrix::toDumpString(SkString* str) const {
    1763                 : #ifdef SK_CAN_USE_FLOAT
    1764                 :     str->printf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
    1765                 : #ifdef SK_SCALAR_IS_FLOAT
    1766               0 :              fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
    1767               0 :              fMat[6], fMat[7], fMat[8]);
    1768                 : #else
    1769                 :     SkFixedToFloat(fMat[0]), SkFixedToFloat(fMat[1]), SkFixedToFloat(fMat[2]),
    1770                 :     SkFixedToFloat(fMat[3]), SkFixedToFloat(fMat[4]), SkFixedToFloat(fMat[5]),
    1771                 :     SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
    1772                 : #endif
    1773                 : #else   // can't use float
    1774                 :     str->printf("[%x %x %x][%x %x %x][%x %x %x]",
    1775                 :                 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
    1776                 :                 fMat[6], fMat[7], fMat[8]);
    1777                 : #endif
    1778               0 : }

Generated by: LCOV version 1.7