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