LCOV - app.info - gfx/skia/src/core/SkMatrix.cpp

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