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