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    static inline float SkDoubleToFloat(double x) {
20        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
31void SkMatrix::reset() {
32    fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
33    fMat[kMSkewX]  = fMat[kMSkewY] =
34    fMat[kMTransX] = fMat[kMTransY] =
35    fMat[kMPersp0] = fMat[kMPersp1] = 0;
36    fMat[kMPersp2] = kMatrix22Elem;
37
38    this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
39}
40
41// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
42enum {
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
59uint8_t SkMatrix::computePerspectiveTypeMask() const {
60    unsigned mask = kOnlyPerspectiveValid_Mask | kUnknown_Mask;
61
62    if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
63            SkScalarAs2sCompliment(fMat[kMPersp1]) |
64            (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
65        mask |= kPerspective_Mask;
66    }
67
68    return SkToU8(mask);
69}
70
71uint8_t SkMatrix::computeTypeMask() const {
72    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    if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 ||
90        fMat[kMPersp2] != kMatrix22Elem) {
91        mask |= kPerspective_Mask;
92    }
93
94    if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
95        mask |= kTranslate_Mask;
96    }
97#endif
98
99    int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
100    int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
101    int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
102    int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
103
104    if (m01 | m10) {
105        mask |= kAffine_Mask;
106    }
107
108    if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) {
109        mask |= kScale_Mask;
110    }
111
112    if ((mask & kPerspective_Mask) == 0) {
113        // map non-zero to 1
114        m00 = m00 != 0;
115        m01 = m01 != 0;
116        m10 = m10 != 0;
117        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        int dp0 = (m00 | m11) ^ 1;  // true if both are 0
122        int dp1 = m00 & m11;        // true if both are 1
123        int ds0 = (m01 | m10) ^ 1;  // true if both are 0
124        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        mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
129    }
130
131    return SkToU8(mask);
132}
133
134///////////////////////////////////////////////////////////////////////////////
135
136#ifdef SK_SCALAR_IS_FLOAT
137
138bool operator==(const SkMatrix& a, const SkMatrix& b) {
139    const SkScalar* SK_RESTRICT ma = a.fMat;
140    const SkScalar* SK_RESTRICT mb = b.fMat;
141
142    return  ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
143            ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
144            ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
145}
146
147#endif
148
149///////////////////////////////////////////////////////////////////////////////
150
151void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
152    if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
153        fMat[kMTransX] = dx;
154        fMat[kMTransY] = dy;
155
156        fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
157        fMat[kMSkewX]  = fMat[kMSkewY] =
158        fMat[kMPersp0] = fMat[kMPersp1] = 0;
159        fMat[kMPersp2] = kMatrix22Elem;
160
161        this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
162    } else {
163        this->reset();
164    }
165}
166
167bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
168    if (this->hasPerspective()) {
169        SkMatrix    m;
170        m.setTranslate(dx, dy);
171        return this->preConcat(m);
172    }
173
174    if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
175        fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) +
176                          SkScalarMul(fMat[kMSkewX], dy);
177        fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
178                          SkScalarMul(fMat[kMScaleY], dy);
179
180        this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
181    }
182    return true;
183}
184
185bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
186    if (this->hasPerspective()) {
187        SkMatrix    m;
188        m.setTranslate(dx, dy);
189        return this->postConcat(m);
190    }
191
192    if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
193        fMat[kMTransX] += dx;
194        fMat[kMTransY] += dy;
195        this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
196    }
197    return true;
198}
199
200///////////////////////////////////////////////////////////////////////////////
201
202void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
203    if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
204        this->reset();
205    } else {
206        fMat[kMScaleX] = sx;
207        fMat[kMScaleY] = sy;
208        fMat[kMTransX] = px - SkScalarMul(sx, px);
209        fMat[kMTransY] = py - SkScalarMul(sy, py);
210        fMat[kMPersp2] = kMatrix22Elem;
211
212        fMat[kMSkewX]  = fMat[kMSkewY] =
213        fMat[kMPersp0] = fMat[kMPersp1] = 0;
214
215        this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
216    }
217}
218
219void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
220    if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
221        this->reset();
222    } else {
223        fMat[kMScaleX] = sx;
224        fMat[kMScaleY] = sy;
225        fMat[kMPersp2] = kMatrix22Elem;
226
227        fMat[kMTransX] = fMat[kMTransY] =
228        fMat[kMSkewX]  = fMat[kMSkewY] =
229        fMat[kMPersp0] = fMat[kMPersp1] = 0;
230
231        this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
232    }
233}
234
235bool SkMatrix::setIDiv(int divx, int divy) {
236    if (!divx || !divy) {
237        return false;
238    }
239    this->setScale(SK_Scalar1 / divx, SK_Scalar1 / divy);
240    return true;
241}
242
243bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
244    SkMatrix    m;
245    m.setScale(sx, sy, px, py);
246    return this->preConcat(m);
247}
248
249bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
250    if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
251        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    fMat[kMScaleX] = SkScalarMul(fMat[kMScaleX], sx);
265    fMat[kMSkewY] = SkScalarMul(fMat[kMSkewY],   sx);
266    fMat[kMPersp0] = SkScalarMul(fMat[kMPersp0], sx);
267
268    fMat[kMSkewX] = SkScalarMul(fMat[kMSkewX],   sy);
269    fMat[kMScaleY] = SkScalarMul(fMat[kMScaleY], sy);
270    fMat[kMPersp1] = SkScalarMul(fMat[kMPersp1], sy);
271
272    this->orTypeMask(kScale_Mask);
273    return true;
274#endif
275}
276
277bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
278    if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
279        return true;
280    }
281    SkMatrix    m;
282    m.setScale(sx, sy, px, py);
283    return this->postConcat(m);
284}
285
286bool SkMatrix::postScale(SkScalar sx, SkScalar sy) {
287    if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
288        return true;
289    }
290    SkMatrix    m;
291    m.setScale(sx, sy);
292    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
310bool SkMatrix::postIDiv(int divx, int divy) {
311    if (divx == 0 || divy == 0) {
312        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    const float invX = 1.f / divx;
325    const float invY = 1.f / divy;
326
327    fMat[kMScaleX] *= invX;
328    fMat[kMSkewX]  *= invX;
329    fMat[kMTransX] *= invX;
330
331    fMat[kMScaleY] *= invY;
332    fMat[kMSkewY]  *= invY;
333    fMat[kMTransY] *= invY;
334#endif
335
336    this->setTypeMask(kUnknown_Mask);
337    return true;
338}
339
340////////////////////////////////////////////////////////////////////////////////////
341
342void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
343                         SkScalar px, SkScalar py) {
344    const SkScalar oneMinusCosV = SK_Scalar1 - cosV;
345
346    fMat[kMScaleX]  = cosV;
347    fMat[kMSkewX]   = -sinV;
348    fMat[kMTransX]  = SkScalarMul(sinV, py) + SkScalarMul(oneMinusCosV, px);
349
350    fMat[kMSkewY]   = sinV;
351    fMat[kMScaleY]  = cosV;
352    fMat[kMTransY]  = SkScalarMul(-sinV, px) + SkScalarMul(oneMinusCosV, py);
353
354    fMat[kMPersp0] = fMat[kMPersp1] = 0;
355    fMat[kMPersp2] = kMatrix22Elem;
356
357    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
358}
359
360void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
361    fMat[kMScaleX]  = cosV;
362    fMat[kMSkewX]   = -sinV;
363    fMat[kMTransX]  = 0;
364
365    fMat[kMSkewY]   = sinV;
366    fMat[kMScaleY]  = cosV;
367    fMat[kMTransY]  = 0;
368
369    fMat[kMPersp0] = fMat[kMPersp1] = 0;
370    fMat[kMPersp2] = kMatrix22Elem;
371
372    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
373}
374
375void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
376    SkScalar sinV, cosV;
377    sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
378    this->setSinCos(sinV, cosV, px, py);
379}
380
381void SkMatrix::setRotate(SkScalar degrees) {
382    SkScalar sinV, cosV;
383    sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
384    this->setSinCos(sinV, cosV);
385}
386
387bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
388    SkMatrix    m;
389    m.setRotate(degrees, px, py);
390    return this->preConcat(m);
391}
392
393bool SkMatrix::preRotate(SkScalar degrees) {
394    SkMatrix    m;
395    m.setRotate(degrees);
396    return this->preConcat(m);
397}
398
399bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
400    SkMatrix    m;
401    m.setRotate(degrees, px, py);
402    return this->postConcat(m);
403}
404
405bool SkMatrix::postRotate(SkScalar degrees) {
406    SkMatrix    m;
407    m.setRotate(degrees);
408    return this->postConcat(m);
409}
410
411////////////////////////////////////////////////////////////////////////////////////
412
413void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
414    fMat[kMScaleX]  = SK_Scalar1;
415    fMat[kMSkewX]   = sx;
416    fMat[kMTransX]  = SkScalarMul(-sx, py);
417
418    fMat[kMSkewY]   = sy;
419    fMat[kMScaleY]  = SK_Scalar1;
420    fMat[kMTransY]  = SkScalarMul(-sy, px);
421
422    fMat[kMPersp0] = fMat[kMPersp1] = 0;
423    fMat[kMPersp2] = kMatrix22Elem;
424
425    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
426}
427
428void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
429    fMat[kMScaleX]  = SK_Scalar1;
430    fMat[kMSkewX]   = sx;
431    fMat[kMTransX]  = 0;
432
433    fMat[kMSkewY]   = sy;
434    fMat[kMScaleY]  = SK_Scalar1;
435    fMat[kMTransY]  = 0;
436
437    fMat[kMPersp0] = fMat[kMPersp1] = 0;
438    fMat[kMPersp2] = kMatrix22Elem;
439
440    this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
441}
442
443bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
444    SkMatrix    m;
445    m.setSkew(sx, sy, px, py);
446    return this->preConcat(m);
447}
448
449bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
450    SkMatrix    m;
451    m.setSkew(sx, sy);
452    return this->preConcat(m);
453}
454
455bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
456    SkMatrix    m;
457    m.setSkew(sx, sy, px, py);
458    return this->postConcat(m);
459}
460
461bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
462    SkMatrix    m;
463    m.setSkew(sx, sy);
464    return this->postConcat(m);
465}
466
467///////////////////////////////////////////////////////////////////////////////
468
469bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
470                             ScaleToFit align)
471{
472    if (src.isEmpty()) {
473        this->reset();
474        return false;
475    }
476
477    if (dst.isEmpty()) {
478        sk_bzero(fMat, 8 * sizeof(SkScalar));
479        this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
480    } else {
481        SkScalar    tx, sx = SkScalarDiv(dst.width(), src.width());
482        SkScalar    ty, sy = SkScalarDiv(dst.height(), src.height());
483        bool        xLarger = false;
484
485        if (align != kFill_ScaleToFit) {
486            if (sx > sy) {
487                xLarger = true;
488                sx = sy;
489            } else {
490                sy = sx;
491            }
492        }
493
494        tx = dst.fLeft - SkScalarMul(src.fLeft, sx);
495        ty = dst.fTop - SkScalarMul(src.fTop, sy);
496        if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
497            SkScalar diff;
498
499            if (xLarger) {
500                diff = dst.width() - SkScalarMul(src.width(), sy);
501            } else {
502                diff = dst.height() - SkScalarMul(src.height(), sy);
503            }
504
505            if (align == kCenter_ScaleToFit) {
506                diff = SkScalarHalf(diff);
507            }
508
509            if (xLarger) {
510                tx += diff;
511            } else {
512                ty += diff;
513            }
514        }
515
516        fMat[kMScaleX] = sx;
517        fMat[kMScaleY] = sy;
518        fMat[kMTransX] = tx;
519        fMat[kMTransY] = ty;
520        fMat[kMSkewX]  = fMat[kMSkewY] =
521        fMat[kMPersp0] = fMat[kMPersp1] = 0;
522
523        this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
524    }
525    // shared cleanup
526    fMat[kMPersp2] = kMatrix22Elem;
527    return true;
528}
529
530///////////////////////////////////////////////////////////////////////////////
531
532#ifdef SK_SCALAR_IS_FLOAT
533    static inline int fixmuladdmul(float a, float b, float c, float d,
534                                   float* result) {
535        *result = SkDoubleToFloat((double)a * b + (double)c * d);
536        return true;
537    }
538
539    static inline bool rowcol3(const float row[], const float col[],
540                               float* result) {
541        *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
542        return true;
543    }
544
545    static inline int negifaddoverflows(float& result, float a, float b) {
546        result = a + b;
547        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
598static void normalize_perspective(SkScalar mat[9]) {
599    if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > kMatrix22Elem) {
600        for (int i = 0; i < 9; i++)
601            mat[i] = SkScalarHalf(mat[i]);
602    }
603}
604
605bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
606    TypeMask aType = a.getPerspectiveTypeMaskOnly();
607    TypeMask bType = b.getPerspectiveTypeMaskOnly();
608
609    if (a.isTriviallyIdentity()) {
610        *this = b;
611    } else if (b.isTriviallyIdentity()) {
612        *this = a;
613    } else {
614        SkMatrix tmp;
615
616        if ((aType | bType) & kPerspective_Mask) {
617            if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) {
618                return false;
619            }
620            if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) {
621                return false;
622            }
623            if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) {
624                return false;
625            }
626
627            if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) {
628                return false;
629            }
630            if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) {
631                return false;
632            }
633            if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) {
634                return false;
635            }
636
637            if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) {
638                return false;
639            }
640            if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) {
641                return false;
642            }
643            if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) {
644                return false;
645            }
646
647            normalize_perspective(tmp.fMat);
648            tmp.setTypeMask(kUnknown_Mask);
649        } else {    // not perspective
650            if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
651                    a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
652                return false;
653            }
654            if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX],
655                      a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) {
656                return false;
657            }
658            if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX],
659                      a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) {
660                return false;
661            }
662            if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX],
663                                  a.fMat[kMTransX]) < 0) {
664                return false;
665            }
666
667            if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX],
668                      a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) {
669                return false;
670            }
671            if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX],
672                    a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) {
673                return false;
674            }
675            if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX],
676                     a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) {
677                return false;
678            }
679            if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY],
680                                  a.fMat[kMTransY]) < 0) {
681                return false;
682            }
683
684            tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
685            tmp.fMat[kMPersp2] = kMatrix22Elem;
686            //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
687            //SkASSERT(!(tmp.getType() & kPerspective_Mask));
688            tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
689        }
690        *this = tmp;
691    }
692    return true;
693}
694
695bool 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    return mat.isIdentity() || this->setConcat(*this, mat);
699}
700
701bool 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    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    static double sk_inv_determinant(const float mat[9], int isPerspective,
721                                    int* /* (only used in Fixed case) */) {
722        double det;
723
724        if (isPerspective) {
725            det =   mat[SkMatrix::kMScaleX] * ((double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp2] - (double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp1]) +
726                    mat[SkMatrix::kMSkewX] * ((double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp0] - (double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp2]) +
727                    mat[SkMatrix::kMTransX] * ((double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp1] - (double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp0]);
728        } else {
729            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        if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
736            return 0;
737        }
738        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    static float inline mul_diff_scale(double a, double b, double c, double d,
744                                       double scale) {
745        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
796void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
797    affine[kAScaleX] = SK_Scalar1;
798    affine[kASkewY] = 0;
799    affine[kASkewX] = 0;
800    affine[kAScaleY] = SK_Scalar1;
801    affine[kATransX] = 0;
802    affine[kATransY] = 0;
803}
804
805bool SkMatrix::asAffine(SkScalar affine[6]) const {
806    if (this->hasPerspective()) {
807        return false;
808    }
809    if (affine) {
810        affine[kAScaleX] = this->fMat[kMScaleX];
811        affine[kASkewY] = this->fMat[kMSkewY];
812        affine[kASkewX] = this->fMat[kMSkewX];
813        affine[kAScaleY] = this->fMat[kMScaleY];
814        affine[kATransX] = this->fMat[kMTransX];
815        affine[kATransY] = this->fMat[kMTransY];
816    }
817    return true;
818}
819
820bool SkMatrix::invert(SkMatrix* inv) const {
821    int         isPersp = this->hasPerspective();
822    int         shift;
823    SkDetScalar scale = sk_inv_determinant(fMat, isPersp, &shift);
824
825    if (scale == 0) { // underflow
826        return false;
827    }
828
829    if (inv) {
830        SkMatrix tmp;
831        if (inv == this) {
832            inv = &tmp;
833        }
834        inv->setTypeMask(kUnknown_Mask);
835
836        if (isPersp) {
837            shift = 61 - shift;
838            inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift);
839            inv->fMat[kMSkewX]  = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX],  fMat[kMPersp2]), scale, shift);
840            inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift);
841
842            inv->fMat[kMSkewY]  = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY],   fMat[kMPersp2]), scale, shift);
843            inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX],  fMat[kMPersp0]), scale, shift);
844            inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift);
845
846            inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift);
847            inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift);
848            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            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            inv->fMat[kMScaleX] = SkDoubleToFloat(fMat[kMScaleY] * scale);
902            inv->fMat[kMSkewX] = SkDoubleToFloat(-fMat[kMSkewX] * scale);
903            inv->fMat[kMTransX] = mul_diff_scale(fMat[kMSkewX], fMat[kMTransY],
904                                     fMat[kMScaleY], fMat[kMTransX], scale);
905
906            inv->fMat[kMSkewY] = SkDoubleToFloat(-fMat[kMSkewY] * scale);
907            inv->fMat[kMScaleY] = SkDoubleToFloat(fMat[kMScaleX] * scale);
908            inv->fMat[kMTransY] = mul_diff_scale(fMat[kMSkewY], fMat[kMTransX],
909                                        fMat[kMScaleX], fMat[kMTransY], scale);
910#endif
911            inv->fMat[kMPersp0] = 0;
912            inv->fMat[kMPersp1] = 0;
913            inv->fMat[kMPersp2] = kMatrix22Elem;
914            inv->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
915        }
916
917        if (inv == &tmp) {
918            *(SkMatrix*)this = tmp;
919        }
920    }
921    return true;
922}
923
924///////////////////////////////////////////////////////////////////////////////
925
926void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
927                            const SkPoint src[], int count) {
928    SkASSERT(m.getType() == 0);
929
930    if (dst != src && count > 0)
931        memcpy(dst, src, count * sizeof(SkPoint));
932}
933
934void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
935                         const SkPoint src[], int count) {
936    SkASSERT(m.getType() == kTranslate_Mask);
937
938    if (count > 0) {
939        SkScalar tx = m.fMat[kMTransX];
940        SkScalar ty = m.fMat[kMTransY];
941        do {
942            dst->fY = src->fY + ty;
943            dst->fX = src->fX + tx;
944            src += 1;
945            dst += 1;
946        } while (--count);
947    }
948}
949
950void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
951                         const SkPoint src[], int count) {
952    SkASSERT(m.getType() == kScale_Mask);
953
954    if (count > 0) {
955        SkScalar mx = m.fMat[kMScaleX];
956        SkScalar my = m.fMat[kMScaleY];
957        do {
958            dst->fY = SkScalarMul(src->fY, my);
959            dst->fX = SkScalarMul(src->fX, mx);
960            src += 1;
961            dst += 1;
962        } while (--count);
963    }
964}
965
966void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
967                              const SkPoint src[], int count) {
968    SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
969
970    if (count > 0) {
971        SkScalar mx = m.fMat[kMScaleX];
972        SkScalar my = m.fMat[kMScaleY];
973        SkScalar tx = m.fMat[kMTransX];
974        SkScalar ty = m.fMat[kMTransY];
975        do {
976            dst->fY = SkScalarMulAdd(src->fY, my, ty);
977            dst->fX = SkScalarMulAdd(src->fX, mx, tx);
978            src += 1;
979            dst += 1;
980        } while (--count);
981    }
982}
983
984void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
985                       const SkPoint src[], int count) {
986    SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
987
988    if (count > 0) {
989        SkScalar mx = m.fMat[kMScaleX];
990        SkScalar my = m.fMat[kMScaleY];
991        SkScalar kx = m.fMat[kMSkewX];
992        SkScalar ky = m.fMat[kMSkewY];
993        do {
994            SkScalar sy = src->fY;
995            SkScalar sx = src->fX;
996            src += 1;
997            dst->fY = SkScalarMul(sx, ky) + SkScalarMul(sy, my);
998            dst->fX = SkScalarMul(sx, mx) + SkScalarMul(sy, kx);
999            dst += 1;
1000        } while (--count);
1001    }
1002}
1003
1004void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
1005                            const SkPoint src[], int count) {
1006    SkASSERT(!m.hasPerspective());
1007
1008    if (count > 0) {
1009        SkScalar mx = m.fMat[kMScaleX];
1010        SkScalar my = m.fMat[kMScaleY];
1011        SkScalar kx = m.fMat[kMSkewX];
1012        SkScalar ky = m.fMat[kMSkewY];
1013        SkScalar tx = m.fMat[kMTransX];
1014        SkScalar ty = m.fMat[kMTransY];
1015        do {
1016            SkScalar sy = src->fY;
1017            SkScalar sx = src->fX;
1018            src += 1;
1019            dst->fY = SkScalarMul(sx, ky) + SkScalarMulAdd(sy, my, ty);
1020            dst->fX = SkScalarMul(sx, mx) + SkScalarMulAdd(sy, kx, tx);
1021            dst += 1;
1022        } while (--count);
1023    }
1024}
1025
1026void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
1027                         const SkPoint src[], int count) {
1028    SkASSERT(m.hasPerspective());
1029
1030#ifdef SK_SCALAR_IS_FIXED
1031    SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]);
1032#endif
1033
1034    if (count > 0) {
1035        do {
1036            SkScalar sy = src->fY;
1037            SkScalar sx = src->fX;
1038            src += 1;
1039
1040            SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1041                         SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1042            SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1043                         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            float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1049                      SkScalarMulAdd(sy, m.fMat[kMPersp1], m.fMat[kMPersp2]);
1050#endif
1051            if (z) {
1052                z = SkScalarFastInvert(z);
1053            }
1054
1055            dst->fY = SkScalarMul(y, z);
1056            dst->fX = SkScalarMul(x, z);
1057            dst += 1;
1058        } while (--count);
1059    }
1060}
1061
1062const 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
1074void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
1075    SkASSERT((dst && src && count > 0) || count == 0);
1076    // no partial overlap
1077    SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= count);
1078
1079    this->getMapPtsProc()(*this, dst, src, count);
1080}
1081
1082///////////////////////////////////////////////////////////////////////////////
1083
1084void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
1085    if (this->hasPerspective()) {
1086        SkPoint origin;
1087
1088        MapXYProc proc = this->getMapXYProc();
1089        proc(*this, 0, 0, &origin);
1090
1091        for (int i = count - 1; i >= 0; --i) {
1092            SkPoint tmp;
1093
1094            proc(*this, src[i].fX, src[i].fY, &tmp);
1095            dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1096        }
1097    } else {
1098        SkMatrix tmp = *this;
1099
1100        tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1101        tmp.clearTypeMask(kTranslate_Mask);
1102        tmp.mapPoints(dst, src, count);
1103    }
1104}
1105
1106bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
1107    SkASSERT(dst && &src);
1108
1109    if (this->rectStaysRect()) {
1110        this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
1111        dst->sort();
1112        return true;
1113    } else {
1114        SkPoint quad[4];
1115
1116        src.toQuad(quad);
1117        this->mapPoints(quad, quad, 4);
1118        dst->set(quad, 4);
1119        return false;
1120    }
1121}
1122
1123SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1124    SkVector    vec[2];
1125
1126    vec[0].set(radius, 0);
1127    vec[1].set(0, radius);
1128    this->mapVectors(vec, 2);
1129
1130    SkScalar d0 = vec[0].length();
1131    SkScalar d1 = vec[1].length();
1132
1133    return SkScalarMean(d0, d1);
1134}
1135
1136///////////////////////////////////////////////////////////////////////////////
1137
1138void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1139                        SkPoint* pt) {
1140    SkASSERT(m.hasPerspective());
1141
1142    SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1143                 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1144    SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1145                 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    float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1152              SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1153#endif
1154    if (z) {
1155        z = SkScalarFastInvert(z);
1156    }
1157    pt->fX = SkScalarMul(x, z);
1158    pt->fY = SkScalarMul(y, z);
1159}
1160
1161#ifdef SK_SCALAR_IS_FIXED
1162static 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
1173void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1174                           SkPoint* pt) {
1175    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    pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1184             SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1185    pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1186             SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1187#endif
1188}
1189
1190void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1191                      SkPoint* pt) {
1192    SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1193    SkASSERT(0 == m.fMat[kMTransX]);
1194    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    pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1201             SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1202    pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1203             SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1204#endif
1205}
1206
1207void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1208                             SkPoint* pt) {
1209    SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1210             == kScale_Mask);
1211
1212    pt->fX = SkScalarMulAdd(sx, m.fMat[kMScaleX], m.fMat[kMTransX]);
1213    pt->fY = SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1214}
1215
1216void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1217                        SkPoint* pt) {
1218    SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1219             == kScale_Mask);
1220    SkASSERT(0 == m.fMat[kMTransX]);
1221    SkASSERT(0 == m.fMat[kMTransY]);
1222
1223    pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]);
1224    pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]);
1225}
1226
1227void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1228                        SkPoint* pt) {
1229    SkASSERT(m.getType() == kTranslate_Mask);
1230
1231    pt->fX = sx + m.fMat[kMTransX];
1232    pt->fY = sy + m.fMat[kMTransY];
1233}
1234
1235void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1236                           SkPoint* pt) {
1237    SkASSERT(0 == m.getType());
1238
1239    pt->fX = sx;
1240    pt->fY = sy;
1241}
1242
1243const 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
1266bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
1267    if (PerspNearlyZero(fMat[kMPersp0])) {
1268        if (stepX || stepY) {
1269            if (PerspNearlyZero(fMat[kMPersp1]) &&
1270                    PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem)) {
1271                if (stepX) {
1272                    *stepX = SkScalarToFixed(fMat[kMScaleX]);
1273                }
1274                if (stepY) {
1275                    *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                float z = y * fMat[kMPersp1] + fMat[kMPersp2];
1283#endif
1284                if (stepX) {
1285                    *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z));
1286                }
1287                if (stepY) {
1288                    *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z));
1289                }
1290            }
1291        }
1292        return true;
1293    }
1294    return false;
1295}
1296
1297///////////////////////////////////////////////////////////////////////////////
1298
1299#include "SkPerspIter.h"
1300
1301SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
1302        : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
1303    SkPoint pt;
1304
1305    SkMatrix::Persp_xy(m, x0, y0, &pt);
1306    fX = SkScalarToFixed(pt.fX);
1307    fY = SkScalarToFixed(pt.fY);
1308}
1309
1310int SkPerspIter::next() {
1311    int n = fCount;
1312
1313    if (0 == n) {
1314        return 0;
1315    }
1316    SkPoint pt;
1317    SkFixed x = fX;
1318    SkFixed y = fY;
1319    SkFixed dx, dy;
1320
1321    if (n >= kCount) {
1322        n = kCount;
1323        fSX += SkIntToScalar(kCount);
1324        SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1325        fX = SkScalarToFixed(pt.fX);
1326        fY = SkScalarToFixed(pt.fY);
1327        dx = (fX - x) >> kShift;
1328        dy = (fY - y) >> kShift;
1329    } else {
1330        fSX += SkIntToScalar(n);
1331        SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1332        fX = SkScalarToFixed(pt.fX);
1333        fY = SkScalarToFixed(pt.fY);
1334        dx = (fX - x) / n;
1335        dy = (fY - y) / n;
1336    }
1337
1338    SkFixed* p = fStorage;
1339    for (int i = 0; i < n; i++) {
1340        *p++ = x; x += dx;
1341        *p++ = y; y += dy;
1342    }
1343
1344    fCount -= n;
1345    return n;
1346}
1347
1348///////////////////////////////////////////////////////////////////////////////
1349
1350#ifdef SK_SCALAR_IS_FIXED
1351
1352static 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
1390bool 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
1408bool 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
1425bool 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
1487static inline bool checkForZero(float x) {
1488    return x*x == 0;
1489}
1490
1491static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1492    float   x = 1, y = 1;
1493    SkPoint pt1, pt2;
1494
1495    if (count > 1) {
1496        pt1.fX = poly[1].fX - poly[0].fX;
1497        pt1.fY = poly[1].fY - poly[0].fY;
1498        y = SkPoint::Length(pt1.fX, pt1.fY);
1499        if (checkForZero(y)) {
1500            return false;
1501        }
1502        switch (count) {
1503            case 2:
1504                break;
1505            case 3:
1506                pt2.fX = poly[0].fY - poly[2].fY;
1507                pt2.fY = poly[2].fX - poly[0].fX;
1508                goto CALC_X;
1509            default:
1510                pt2.fX = poly[0].fY - poly[3].fY;
1511                pt2.fY = poly[3].fX - poly[0].fX;
1512            CALC_X:
1513                x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) +
1514                                SkScalarMul(pt1.fY, pt2.fY), y);
1515                break;
1516        }
1517    }
1518    pt->set(x, y);
1519    return true;
1520}
1521
1522bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1523                         const SkPoint& scale) {
1524    float invScale = 1 / scale.fY;
1525
1526    dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1527    dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
1528    dst->fMat[kMPersp0] = 0;
1529    dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1530    dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1531    dst->fMat[kMPersp1] = 0;
1532    dst->fMat[kMTransX] = srcPt[0].fX;
1533    dst->fMat[kMTransY] = srcPt[0].fY;
1534    dst->fMat[kMPersp2] = 1;
1535    dst->setTypeMask(kUnknown_Mask);
1536    return true;
1537}
1538
1539bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1540                         const SkPoint& scale) {
1541    float invScale = 1 / scale.fX;
1542    dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
1543    dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
1544    dst->fMat[kMPersp0] = 0;
1545
1546    invScale = 1 / scale.fY;
1547    dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1548    dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1549    dst->fMat[kMPersp1] = 0;
1550
1551    dst->fMat[kMTransX] = srcPt[0].fX;
1552    dst->fMat[kMTransY] = srcPt[0].fY;
1553    dst->fMat[kMPersp2] = 1;
1554    dst->setTypeMask(kUnknown_Mask);
1555    return true;
1556}
1557
1558bool 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    x0 = srcPt[2].fX - srcPt[0].fX;
1564    y0 = srcPt[2].fY - srcPt[0].fY;
1565    x1 = srcPt[2].fX - srcPt[1].fX;
1566    y1 = srcPt[2].fY - srcPt[1].fY;
1567    x2 = srcPt[2].fX - srcPt[3].fX;
1568    y2 = srcPt[2].fY - srcPt[3].fY;
1569
1570    /* check if abs(x2) > abs(y2) */
1571    if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1572        float denom = SkScalarMulDiv(x1, y2, x2) - y1;
1573        if (checkForZero(denom)) {
1574            return false;
1575        }
1576        a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1577    } else {
1578        float denom = x1 - SkScalarMulDiv(y1, x2, y2);
1579        if (checkForZero(denom)) {
1580            return false;
1581        }
1582        a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), denom);
1583    }
1584
1585    /* check if abs(x1) > abs(y1) */
1586    if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1587        float denom = y2 - SkScalarMulDiv(x2, y1, x1);
1588        if (checkForZero(denom)) {
1589            return false;
1590        }
1591        a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), denom);
1592    } else {
1593        float denom = SkScalarMulDiv(y2, x1, y1) - x2;
1594        if (checkForZero(denom)) {
1595            return false;
1596        }
1597        a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1598    }
1599
1600    float invScale = 1 / scale.fX;
1601    dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) +
1602                                      srcPt[3].fX - srcPt[0].fX, invScale);
1603    dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) +
1604                                     srcPt[3].fY - srcPt[0].fY, invScale);
1605    dst->fMat[kMPersp0] = SkScalarMul(a2, invScale);
1606    invScale = 1 / scale.fY;
1607    dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) +
1608                                     srcPt[1].fX - srcPt[0].fX, invScale);
1609    dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) +
1610                                      srcPt[1].fY - srcPt[0].fY, invScale);
1611    dst->fMat[kMPersp1] = SkScalarMul(a1, invScale);
1612    dst->fMat[kMTransX] = srcPt[0].fX;
1613    dst->fMat[kMTransY] = srcPt[0].fY;
1614    dst->fMat[kMPersp2] = 1;
1615    dst->setTypeMask(kUnknown_Mask);
1616    return true;
1617}
1618
1619#endif
1620
1621typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
1622
1623/*  Taken from Rob Johnson's original sample code in QuickDraw GX
1624*/
1625bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
1626                             int count) {
1627    if ((unsigned)count > 4) {
1628        SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1629        return false;
1630    }
1631
1632    if (0 == count) {
1633        this->reset();
1634        return true;
1635    }
1636    if (1 == count) {
1637        this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1638        return true;
1639    }
1640
1641    SkPoint scale;
1642    if (!poly_to_point(&scale, src, count) ||
1643            SkScalarNearlyZero(scale.fX) ||
1644            SkScalarNearlyZero(scale.fY)) {
1645        return false;
1646    }
1647
1648    static const PolyMapProc gPolyMapProcs[] = {
1649        SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1650    };
1651    PolyMapProc proc = gPolyMapProcs[count - 2];
1652
1653    SkMatrix tempMap, result;
1654    tempMap.setTypeMask(kUnknown_Mask);
1655
1656    if (!proc(src, &tempMap, scale)) {
1657        return false;
1658    }
1659    if (!tempMap.invert(&result)) {
1660        return false;
1661    }
1662    if (!proc(dst, &tempMap, scale)) {
1663        return false;
1664    }
1665    if (!result.setConcat(tempMap, result)) {
1666        return false;
1667    }
1668    *this = result;
1669    return true;
1670}
1671
1672///////////////////////////////////////////////////////////////////////////////
1673
1674SkScalar SkMatrix::getMaxStretch() const {
1675    TypeMask mask = this->getType();
1676
1677    if (this->hasPerspective()) {
1678        return -SK_Scalar1;
1679    }
1680    if (this->isIdentity()) {
1681        return SK_Scalar1;
1682    }
1683    if (!(mask & kAffine_Mask)) {
1684        return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
1685                           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    SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
1691                 SkScalarMul(fMat[kMSkewY],  fMat[kMSkewY]);
1692    SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
1693                 SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
1694    SkScalar c = SkScalarMul(fMat[kMSkewX],  fMat[kMSkewX]) +
1695                 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    SkScalar bSqd = SkScalarMul(b,b);
1703    // if upper left 2x2 is orthogonal save some math
1704    if (bSqd <= SK_ScalarNearlyZero) {
1705        largerRoot = SkMaxScalar(a, c);
1706    } else {
1707        SkScalar aminusc = a - c;
1708        SkScalar apluscdiv2 = SkScalarHalf(a + c);
1709        SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
1710        largerRoot = apluscdiv2 + x;
1711    }
1712    return SkScalarSqrt(largerRoot);
1713}
1714
1715const SkMatrix& SkMatrix::I() {
1716    static SkMatrix gIdentity;
1717    static bool gOnce;
1718    if (!gOnce) {
1719        gIdentity.reset();
1720        gOnce = true;
1721    }
1722    return gIdentity;
1723};
1724
1725const SkMatrix& SkMatrix::InvalidMatrix() {
1726    static SkMatrix gInvalid;
1727    static bool gOnce;
1728    if (!gOnce) {
1729        gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1730                        SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1731                        SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
1732        gInvalid.getType(); // force the type to be computed
1733        gOnce = true;
1734    }
1735    return gInvalid;
1736}
1737
1738///////////////////////////////////////////////////////////////////////////////
1739
1740uint32_t SkMatrix::flatten(void* buffer) const {
1741    // TODO write less for simple matrices
1742    if (buffer) {
1743        memcpy(buffer, fMat, 9 * sizeof(SkScalar));
1744    }
1745    return 9 * sizeof(SkScalar);
1746}
1747
1748uint32_t SkMatrix::unflatten(const void* buffer) {
1749    if (buffer) {
1750        memcpy(fMat, buffer, 9 * sizeof(SkScalar));
1751        this->setTypeMask(kUnknown_Mask);
1752    }
1753    return 9 * sizeof(SkScalar);
1754}
1755
1756void SkMatrix::dump() const {
1757    SkString str;
1758    this->toDumpString(&str);
1759    SkDebugf("%s\n", str.c_str());
1760}
1761
1762void 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             fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1767             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}
1779