2 * Copyright 2006 The Android Open Source Project
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
9 #include "SkFloatBits.h"
14 // In a few places, we performed the following
17 // a * b + (c * d + e)
19 // sdot and scross are indended to capture these compound operations into a
20 // function, with an eye toward considering upscaling the intermediates to
21 // doubles for more precision (as we do in concat and invert).
23 // However, these few lines that performed the last add before the "dot", cause
24 // tiny image differences, so we guard that change until we see the impact on
25 // chrome's layouttests.
27 #define SK_LEGACY_MATRIX_MATH_ORDER
29 static inline float SkDoubleToFloat(double x) {
30 return static_cast<float>(x);
33 /* [scale-x skew-x trans-x] [X] [X']
34 [skew-y scale-y trans-y] * [Y] = [Y']
35 [persp-0 persp-1 persp-2] [1] [1 ]
38 void SkMatrix::reset() {
39 fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
40 fMat[kMSkewX] = fMat[kMSkewY] =
41 fMat[kMTransX] = fMat[kMTransY] =
42 fMat[kMPersp0] = fMat[kMPersp1] = 0;
44 this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
47 // this guy aligns with the masks, so we can compute a mask from a varaible 0/1
56 static const int32_t kScalar1Int = 0x3f800000;
58 uint8_t SkMatrix::computePerspectiveTypeMask() const {
59 // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
60 // is a win, but replacing those below is not. We don't yet understand
62 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
63 // If this is a perspective transform, we return true for all other
64 // transform flags - this does not disable any optimizations, respects
65 // the rule that the type mask must be conservative, and speeds up
66 // type mask computation.
67 return SkToU8(kORableMasks);
70 return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
73 uint8_t SkMatrix::computeTypeMask() const {
76 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
77 // Once it is determined that that this is a perspective transform,
78 // all other flags are moot as far as optimizations are concerned.
79 return SkToU8(kORableMasks);
82 if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
83 mask |= kTranslate_Mask;
86 int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
87 int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
88 int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
89 int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
92 // The skew components may be scale-inducing, unless we are dealing
93 // with a pure rotation. Testing for a pure rotation is expensive,
94 // so we opt for being conservative by always setting the scale bit.
96 // By doing this, we are also ensuring that matrices have the same
97 // type masks as their inverses.
98 mask |= kAffine_Mask | kScale_Mask;
100 // For rectStaysRect, in the affine case, we only need check that
101 // the primary diagonal is all zeros and that the secondary diagonal
108 int dp0 = 0 == (m00 | m11) ; // true if both are 0
109 int ds1 = m01 & m10; // true if both are 1
111 mask |= (dp0 & ds1) << kRectStaysRect_Shift;
113 // Only test for scale explicitly if not affine, since affine sets the
115 if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) {
119 // Not affine, therefore we already know secondary diagonal is
120 // all zeros, so we just need to check that primary diagonal is
127 // record if the (p)rimary diagonal is all non-zero
128 mask |= (m00 & m11) << kRectStaysRect_Shift;
134 ///////////////////////////////////////////////////////////////////////////////
136 bool operator==(const SkMatrix& a, const SkMatrix& b) {
137 const SkScalar* SK_RESTRICT ma = a.fMat;
138 const SkScalar* SK_RESTRICT mb = b.fMat;
140 return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
141 ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
142 ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
145 ///////////////////////////////////////////////////////////////////////////////
147 // helper function to determine if upper-left 2x2 of matrix is degenerate
148 static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
149 SkScalar skewY, SkScalar scaleY) {
150 SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
151 return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero);
154 ///////////////////////////////////////////////////////////////////////////////
156 bool SkMatrix::isSimilarity(SkScalar tol) const {
157 // if identity or translate matrix
158 TypeMask mask = this->getType();
159 if (mask <= kTranslate_Mask) {
162 if (mask & kPerspective_Mask) {
166 SkScalar mx = fMat[kMScaleX];
167 SkScalar my = fMat[kMScaleY];
168 // if no skew, can just compare scale factors
169 if (!(mask & kAffine_Mask)) {
170 return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
172 SkScalar sx = fMat[kMSkewX];
173 SkScalar sy = fMat[kMSkewY];
175 if (is_degenerate_2x2(mx, sx, sy, my)) {
179 // upper 2x2 is rotation/reflection + uniform scale if basis vectors
180 // are 90 degree rotations of each other
181 return (SkScalarNearlyEqual(mx, my, tol) && SkScalarNearlyEqual(sx, -sy, tol))
182 || (SkScalarNearlyEqual(mx, -my, tol) && SkScalarNearlyEqual(sx, sy, tol));
185 bool SkMatrix::preservesRightAngles(SkScalar tol) const {
186 TypeMask mask = this->getType();
188 if (mask <= kTranslate_Mask) {
189 // identity, translate and/or scale
192 if (mask & kPerspective_Mask) {
196 SkASSERT(mask & (kAffine_Mask | kScale_Mask));
198 SkScalar mx = fMat[kMScaleX];
199 SkScalar my = fMat[kMScaleY];
200 SkScalar sx = fMat[kMSkewX];
201 SkScalar sy = fMat[kMSkewY];
203 if (is_degenerate_2x2(mx, sx, sy, my)) {
207 // upper 2x2 is scale + rotation/reflection if basis vectors are orthogonal
212 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol));
215 ///////////////////////////////////////////////////////////////////////////////
217 static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
218 return a * b + c * d;
221 static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d,
222 SkScalar e, SkScalar f) {
223 return a * b + c * d + e * f;
226 static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
227 return a * b - c * d;
230 void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
235 fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
236 fMat[kMSkewX] = fMat[kMSkewY] =
237 fMat[kMPersp0] = fMat[kMPersp1] = 0;
239 this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
245 void SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
250 if (this->hasPerspective()) {
252 m.setTranslate(dx, dy);
255 fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
256 fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
257 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
261 void SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
266 if (this->hasPerspective()) {
268 m.setTranslate(dx, dy);
271 fMat[kMTransX] += dx;
272 fMat[kMTransY] += dy;
273 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
277 ///////////////////////////////////////////////////////////////////////////////
279 void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
280 if (1 == sx && 1 == sy) {
285 fMat[kMTransX] = px - sx * px;
286 fMat[kMTransY] = py - sy * py;
289 fMat[kMSkewX] = fMat[kMSkewY] =
290 fMat[kMPersp0] = fMat[kMPersp1] = 0;
292 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
296 void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
297 if (1 == sx && 1 == sy) {
304 fMat[kMTransX] = fMat[kMTransY] =
305 fMat[kMSkewX] = fMat[kMSkewY] =
306 fMat[kMPersp0] = fMat[kMPersp1] = 0;
308 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
312 bool SkMatrix::setIDiv(int divx, int divy) {
313 if (!divx || !divy) {
316 this->setScale(SkScalarInvert(divx), SkScalarInvert(divy));
320 void SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
321 if (1 == sx && 1 == sy) {
326 m.setScale(sx, sy, px, py);
330 void SkMatrix::preScale(SkScalar sx, SkScalar sy) {
331 if (1 == sx && 1 == sy) {
335 // the assumption is that these multiplies are very cheap, and that
336 // a full concat and/or just computing the matrix type is more expensive.
337 // Also, the fixed-point case checks for overflow, but the float doesn't,
338 // so we can get away with these blind multiplies.
340 fMat[kMScaleX] *= sx;
342 fMat[kMPersp0] *= sx;
345 fMat[kMScaleY] *= sy;
346 fMat[kMPersp1] *= sy;
348 this->orTypeMask(kScale_Mask);
351 void SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
352 if (1 == sx && 1 == sy) {
356 m.setScale(sx, sy, px, py);
360 void SkMatrix::postScale(SkScalar sx, SkScalar sy) {
361 if (1 == sx && 1 == sy) {
369 // this guy perhaps can go away, if we have a fract/high-precision way to
371 bool SkMatrix::postIDiv(int divx, int divy) {
372 if (divx == 0 || divy == 0) {
376 const float invX = 1.f / divx;
377 const float invY = 1.f / divy;
379 fMat[kMScaleX] *= invX;
380 fMat[kMSkewX] *= invX;
381 fMat[kMTransX] *= invX;
383 fMat[kMScaleY] *= invY;
384 fMat[kMSkewY] *= invY;
385 fMat[kMTransY] *= invY;
387 this->setTypeMask(kUnknown_Mask);
391 ////////////////////////////////////////////////////////////////////////////////////
393 void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
394 SkScalar px, SkScalar py) {
395 const SkScalar oneMinusCosV = 1 - cosV;
397 fMat[kMScaleX] = cosV;
398 fMat[kMSkewX] = -sinV;
399 fMat[kMTransX] = sdot(sinV, py, oneMinusCosV, px);
401 fMat[kMSkewY] = sinV;
402 fMat[kMScaleY] = cosV;
403 fMat[kMTransY] = sdot(-sinV, px, oneMinusCosV, py);
405 fMat[kMPersp0] = fMat[kMPersp1] = 0;
408 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
411 void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
412 fMat[kMScaleX] = cosV;
413 fMat[kMSkewX] = -sinV;
416 fMat[kMSkewY] = sinV;
417 fMat[kMScaleY] = cosV;
420 fMat[kMPersp0] = fMat[kMPersp1] = 0;
423 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
426 void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
428 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
429 this->setSinCos(sinV, cosV, px, py);
432 void SkMatrix::setRotate(SkScalar degrees) {
434 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
435 this->setSinCos(sinV, cosV);
438 void SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
440 m.setRotate(degrees, px, py);
444 void SkMatrix::preRotate(SkScalar degrees) {
446 m.setRotate(degrees);
450 void SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
452 m.setRotate(degrees, px, py);
456 void SkMatrix::postRotate(SkScalar degrees) {
458 m.setRotate(degrees);
462 ////////////////////////////////////////////////////////////////////////////////////
464 void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
467 fMat[kMTransX] = -sx * py;
471 fMat[kMTransY] = -sy * px;
473 fMat[kMPersp0] = fMat[kMPersp1] = 0;
476 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
479 void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
488 fMat[kMPersp0] = fMat[kMPersp1] = 0;
491 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
494 void SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
496 m.setSkew(sx, sy, px, py);
500 void SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
506 void SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
508 m.setSkew(sx, sy, px, py);
512 void SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
518 ///////////////////////////////////////////////////////////////////////////////
520 bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
529 sk_bzero(fMat, 8 * sizeof(SkScalar));
530 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
532 SkScalar tx, sx = dst.width() / src.width();
533 SkScalar ty, sy = dst.height() / src.height();
534 bool xLarger = false;
536 if (align != kFill_ScaleToFit) {
545 tx = dst.fLeft - src.fLeft * sx;
546 ty = dst.fTop - src.fTop * sy;
547 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
551 diff = dst.width() - src.width() * sy;
553 diff = dst.height() - src.height() * sy;
556 if (align == kCenter_ScaleToFit) {
557 diff = SkScalarHalf(diff);
571 fMat[kMSkewX] = fMat[kMSkewY] =
572 fMat[kMPersp0] = fMat[kMPersp1] = 0;
574 unsigned mask = kRectStaysRect_Mask;
575 if (sx != 1 || sy != 1) {
579 mask |= kTranslate_Mask;
581 this->setTypeMask(mask);
588 ///////////////////////////////////////////////////////////////////////////////
590 static inline float muladdmul(float a, float b, float c, float d) {
591 return SkDoubleToFloat((double)a * b + (double)c * d);
594 static inline float rowcol3(const float row[], const float col[]) {
595 return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
598 static void normalize_perspective(SkScalar mat[9]) {
599 if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > 1) {
600 for (int i = 0; i < 9; i++)
601 mat[i] = SkScalarHalf(mat[i]);
605 void SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
606 TypeMask aType = a.getPerspectiveTypeMaskOnly();
607 TypeMask bType = b.getPerspectiveTypeMaskOnly();
609 if (a.isTriviallyIdentity()) {
611 } else if (b.isTriviallyIdentity()) {
616 if ((aType | bType) & kPerspective_Mask) {
617 tmp.fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
618 tmp.fMat[kMSkewX] = rowcol3(&a.fMat[0], &b.fMat[1]);
619 tmp.fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
620 tmp.fMat[kMSkewY] = rowcol3(&a.fMat[3], &b.fMat[0]);
621 tmp.fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
622 tmp.fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
623 tmp.fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
624 tmp.fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
625 tmp.fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
627 normalize_perspective(tmp.fMat);
628 tmp.setTypeMask(kUnknown_Mask);
629 } else { // not perspective
630 tmp.fMat[kMScaleX] = muladdmul(a.fMat[kMScaleX],
635 tmp.fMat[kMSkewX] = muladdmul(a.fMat[kMScaleX],
640 tmp.fMat[kMTransX] = muladdmul(a.fMat[kMScaleX],
645 tmp.fMat[kMTransX] += a.fMat[kMTransX];
647 tmp.fMat[kMSkewY] = muladdmul(a.fMat[kMSkewY],
652 tmp.fMat[kMScaleY] = muladdmul(a.fMat[kMSkewY],
657 tmp.fMat[kMTransY] = muladdmul(a.fMat[kMSkewY],
662 tmp.fMat[kMTransY] += a.fMat[kMTransY];
663 tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
664 tmp.fMat[kMPersp2] = 1;
665 //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
666 //SkASSERT(!(tmp.getType() & kPerspective_Mask));
667 tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
673 void SkMatrix::preConcat(const SkMatrix& mat) {
674 // check for identity first, so we don't do a needless copy of ourselves
675 // to ourselves inside setConcat()
676 if(!mat.isIdentity()) {
677 this->setConcat(*this, mat);
681 void SkMatrix::postConcat(const SkMatrix& mat) {
682 // check for identity first, so we don't do a needless copy of ourselves
683 // to ourselves inside setConcat()
684 if (!mat.isIdentity()) {
685 this->setConcat(mat, *this);
689 ///////////////////////////////////////////////////////////////////////////////
691 /* Matrix inversion is very expensive, but also the place where keeping
692 precision may be most important (here and matrix concat). Hence to avoid
693 bitmap blitting artifacts when walking the inverse, we use doubles for
694 the intermediate math, even though we know that is more expensive.
697 static inline SkScalar scross_dscale(SkScalar a, SkScalar b,
698 SkScalar c, SkScalar d, double scale) {
699 return SkDoubleToScalar(scross(a, b, c, d) * scale);
702 static inline double dcross(double a, double b, double c, double d) {
703 return a * b - c * d;
706 static inline SkScalar dcross_dscale(double a, double b,
707 double c, double d, double scale) {
708 return SkDoubleToScalar(dcross(a, b, c, d) * scale);
711 static double sk_inv_determinant(const float mat[9], int isPerspective) {
715 det = mat[SkMatrix::kMScaleX] *
716 dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2],
717 mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1])
719 mat[SkMatrix::kMSkewX] *
720 dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0],
721 mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2])
723 mat[SkMatrix::kMTransX] *
724 dcross(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1],
725 mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]);
727 det = dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY],
728 mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
731 // Since the determinant is on the order of the cube of the matrix members,
732 // compare to the cube of the default nearly-zero constant (although an
733 // estimate of the condition number would be better if it wasn't so expensive).
734 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
740 void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
741 affine[kAScaleX] = 1;
744 affine[kAScaleY] = 1;
745 affine[kATransX] = 0;
746 affine[kATransY] = 0;
749 bool SkMatrix::asAffine(SkScalar affine[6]) const {
750 if (this->hasPerspective()) {
754 affine[kAScaleX] = this->fMat[kMScaleX];
755 affine[kASkewY] = this->fMat[kMSkewY];
756 affine[kASkewX] = this->fMat[kMSkewX];
757 affine[kAScaleY] = this->fMat[kMScaleY];
758 affine[kATransX] = this->fMat[kMTransX];
759 affine[kATransY] = this->fMat[kMTransY];
764 bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
765 SkASSERT(!this->isIdentity());
767 TypeMask mask = this->getType();
769 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
770 bool invertible = true;
772 if (mask & kScale_Mask) {
773 SkScalar invX = fMat[kMScaleX];
774 SkScalar invY = fMat[kMScaleY];
775 if (0 == invX || 0 == invY) {
778 invX = SkScalarInvert(invX);
779 invY = SkScalarInvert(invY);
781 // Must be careful when writing to inv, since it may be the
782 // same memory as this.
784 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
785 inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
787 inv->fMat[kMScaleX] = invX;
788 inv->fMat[kMScaleY] = invY;
789 inv->fMat[kMPersp2] = 1;
790 inv->fMat[kMTransX] = -fMat[kMTransX] * invX;
791 inv->fMat[kMTransY] = -fMat[kMTransY] * invY;
793 inv->setTypeMask(mask | kRectStaysRect_Mask);
796 inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
798 } else { // inv is NULL, just check if we're invertible
799 if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
806 int isPersp = mask & kPerspective_Mask;
807 double scale = sk_inv_determinant(fMat, isPersp);
809 if (scale == 0) { // underflow
820 inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale);
821 inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale);
822 inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale);
824 inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale);
825 inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale);
826 inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale);
828 inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale);
829 inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale);
830 inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale);
831 } else { // not perspective
832 inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale);
833 inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale);
834 inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale);
836 inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale);
837 inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale);
838 inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale);
840 inv->fMat[kMPersp0] = 0;
841 inv->fMat[kMPersp1] = 0;
842 inv->fMat[kMPersp2] = 1;
845 inv->setTypeMask(fTypeMask);
848 *(SkMatrix*)this = tmp;
854 ///////////////////////////////////////////////////////////////////////////////
856 void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
857 const SkPoint src[], int count) {
858 SkASSERT(m.getType() == 0);
860 if (dst != src && count > 0)
861 memcpy(dst, src, count * sizeof(SkPoint));
864 void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
865 const SkPoint src[], int count) {
866 SkASSERT(m.getType() == kTranslate_Mask);
869 SkScalar tx = m.fMat[kMTransX];
870 SkScalar ty = m.fMat[kMTransY];
872 dst->fY = src->fY + ty;
873 dst->fX = src->fX + tx;
880 void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
881 const SkPoint src[], int count) {
882 SkASSERT(m.getType() == kScale_Mask);
885 SkScalar mx = m.fMat[kMScaleX];
886 SkScalar my = m.fMat[kMScaleY];
888 dst->fY = src->fY * my;
889 dst->fX = src->fX * mx;
896 void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
897 const SkPoint src[], int count) {
898 SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
901 SkScalar mx = m.fMat[kMScaleX];
902 SkScalar my = m.fMat[kMScaleY];
903 SkScalar tx = m.fMat[kMTransX];
904 SkScalar ty = m.fMat[kMTransY];
906 dst->fY = src->fY * my + ty;
907 dst->fX = src->fX * mx + tx;
914 void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
915 const SkPoint src[], int count) {
916 SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
919 SkScalar mx = m.fMat[kMScaleX];
920 SkScalar my = m.fMat[kMScaleY];
921 SkScalar kx = m.fMat[kMSkewX];
922 SkScalar ky = m.fMat[kMSkewY];
924 SkScalar sy = src->fY;
925 SkScalar sx = src->fX;
927 dst->fY = sdot(sx, ky, sy, my);
928 dst->fX = sdot(sx, mx, sy, kx);
934 void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
935 const SkPoint src[], int count) {
936 SkASSERT(!m.hasPerspective());
939 SkScalar mx = m.fMat[kMScaleX];
940 SkScalar my = m.fMat[kMScaleY];
941 SkScalar kx = m.fMat[kMSkewX];
942 SkScalar ky = m.fMat[kMSkewY];
943 SkScalar tx = m.fMat[kMTransX];
944 SkScalar ty = m.fMat[kMTransY];
946 SkScalar sy = src->fY;
947 SkScalar sx = src->fX;
949 #ifdef SK_LEGACY_MATRIX_MATH_ORDER
950 dst->fY = sx * ky + (sy * my + ty);
951 dst->fX = sx * mx + (sy * kx + tx);
953 dst->fY = sdot(sx, ky, sy, my) + ty;
954 dst->fX = sdot(sx, mx, sy, kx) + tx;
961 void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
962 const SkPoint src[], int count) {
963 SkASSERT(m.hasPerspective());
967 SkScalar sy = src->fY;
968 SkScalar sx = src->fX;
971 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
972 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
973 #ifdef SK_LEGACY_MATRIX_MATH_ORDER
974 SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]);
976 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
979 z = SkScalarFastInvert(z);
989 const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
990 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
991 SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts,
992 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
993 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
994 // repeat the persp proc 8 times
995 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
996 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
997 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
998 SkMatrix::Persp_pts, SkMatrix::Persp_pts
1001 void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
1002 SkASSERT((dst && src && count > 0) || 0 == count);
1003 // no partial overlap
1004 SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
1006 this->getMapPtsProc()(*this, dst, src, count);
1009 ///////////////////////////////////////////////////////////////////////////////
1011 void SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const {
1012 SkASSERT((dst && src && count > 0) || 0 == count);
1013 // no partial overlap
1014 SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= 3*count);
1017 if (this->isIdentity()) {
1018 memcpy(dst, src, 3*count*sizeof(SkScalar));
1022 SkScalar sx = src[0];
1023 SkScalar sy = src[1];
1024 SkScalar sw = src[2];
1027 SkScalar x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX], sw, fMat[kMTransX]);
1028 SkScalar y = sdot(sx, fMat[kMSkewY], sy, fMat[kMScaleY], sw, fMat[kMTransY]);
1029 SkScalar w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]);
1039 ///////////////////////////////////////////////////////////////////////////////
1041 void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
1042 if (this->hasPerspective()) {
1045 MapXYProc proc = this->getMapXYProc();
1046 proc(*this, 0, 0, &origin);
1048 for (int i = count - 1; i >= 0; --i) {
1051 proc(*this, src[i].fX, src[i].fY, &tmp);
1052 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1055 SkMatrix tmp = *this;
1057 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1058 tmp.clearTypeMask(kTranslate_Mask);
1059 tmp.mapPoints(dst, src, count);
1063 bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
1066 if (this->rectStaysRect()) {
1067 this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
1074 this->mapPoints(quad, quad, 4);
1080 SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1083 vec[0].set(radius, 0);
1084 vec[1].set(0, radius);
1085 this->mapVectors(vec, 2);
1087 SkScalar d0 = vec[0].length();
1088 SkScalar d1 = vec[1].length();
1090 // return geometric mean
1091 return SkScalarSqrt(d0 * d1);
1094 ///////////////////////////////////////////////////////////////////////////////
1096 void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1098 SkASSERT(m.hasPerspective());
1100 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1101 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1102 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1104 z = SkScalarFastInvert(z);
1110 void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1112 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1114 #ifdef SK_LEGACY_MATRIX_MATH_ORDER
1115 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1116 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1118 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1119 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1123 void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1125 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1126 SkASSERT(0 == m.fMat[kMTransX]);
1127 SkASSERT(0 == m.fMat[kMTransY]);
1129 #ifdef SK_LEGACY_MATRIX_MATH_ORDER
1130 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1131 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1133 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1134 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1138 void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1140 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1143 pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
1144 pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
1147 void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1149 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1151 SkASSERT(0 == m.fMat[kMTransX]);
1152 SkASSERT(0 == m.fMat[kMTransY]);
1154 pt->fX = sx * m.fMat[kMScaleX];
1155 pt->fY = sy * m.fMat[kMScaleY];
1158 void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1160 SkASSERT(m.getType() == kTranslate_Mask);
1162 pt->fX = sx + m.fMat[kMTransX];
1163 pt->fY = sy + m.fMat[kMTransY];
1166 void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1168 SkASSERT(0 == m.getType());
1174 const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1175 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1176 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1177 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1178 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1179 // repeat the persp proc 8 times
1180 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1181 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1182 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1183 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1186 ///////////////////////////////////////////////////////////////////////////////
1188 // if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1189 #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1191 bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
1192 if (PerspNearlyZero(fMat[kMPersp0])) {
1193 if (stepX || stepY) {
1194 if (PerspNearlyZero(fMat[kMPersp1]) &&
1195 PerspNearlyZero(fMat[kMPersp2] - 1)) {
1197 *stepX = SkScalarToFixed(fMat[kMScaleX]);
1200 *stepY = SkScalarToFixed(fMat[kMSkewY]);
1203 SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
1205 *stepX = SkScalarToFixed(fMat[kMScaleX] / z);
1208 *stepY = SkScalarToFixed(fMat[kMSkewY] / z);
1217 ///////////////////////////////////////////////////////////////////////////////
1219 #include "SkPerspIter.h"
1221 SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
1222 : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
1225 SkMatrix::Persp_xy(m, x0, y0, &pt);
1226 fX = SkScalarToFixed(pt.fX);
1227 fY = SkScalarToFixed(pt.fY);
1230 int SkPerspIter::next() {
1243 fSX += SkIntToScalar(kCount);
1244 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1245 fX = SkScalarToFixed(pt.fX);
1246 fY = SkScalarToFixed(pt.fY);
1247 dx = (fX - x) >> kShift;
1248 dy = (fY - y) >> kShift;
1250 fSX += SkIntToScalar(n);
1251 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1252 fX = SkScalarToFixed(pt.fX);
1253 fY = SkScalarToFixed(pt.fY);
1258 SkFixed* p = fStorage;
1259 for (int i = 0; i < n; i++) {
1268 ///////////////////////////////////////////////////////////////////////////////
1270 static inline bool checkForZero(float x) {
1274 static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1279 pt1.fX = poly[1].fX - poly[0].fX;
1280 pt1.fY = poly[1].fY - poly[0].fY;
1281 y = SkPoint::Length(pt1.fX, pt1.fY);
1282 if (checkForZero(y)) {
1289 pt2.fX = poly[0].fY - poly[2].fY;
1290 pt2.fY = poly[2].fX - poly[0].fX;
1293 pt2.fX = poly[0].fY - poly[3].fY;
1294 pt2.fY = poly[3].fX - poly[0].fX;
1296 x = sdot(pt1.fX, pt2.fX, pt1.fY, pt2.fY) / y;
1304 bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1305 const SkPoint& scale) {
1306 float invScale = 1 / scale.fY;
1308 dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1309 dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
1310 dst->fMat[kMPersp0] = 0;
1311 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1312 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1313 dst->fMat[kMPersp1] = 0;
1314 dst->fMat[kMTransX] = srcPt[0].fX;
1315 dst->fMat[kMTransY] = srcPt[0].fY;
1316 dst->fMat[kMPersp2] = 1;
1317 dst->setTypeMask(kUnknown_Mask);
1321 bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1322 const SkPoint& scale) {
1323 float invScale = 1 / scale.fX;
1324 dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
1325 dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
1326 dst->fMat[kMPersp0] = 0;
1328 invScale = 1 / scale.fY;
1329 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1330 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1331 dst->fMat[kMPersp1] = 0;
1333 dst->fMat[kMTransX] = srcPt[0].fX;
1334 dst->fMat[kMTransY] = srcPt[0].fY;
1335 dst->fMat[kMPersp2] = 1;
1336 dst->setTypeMask(kUnknown_Mask);
1340 bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1341 const SkPoint& scale) {
1343 float x0, y0, x1, y1, x2, y2;
1345 x0 = srcPt[2].fX - srcPt[0].fX;
1346 y0 = srcPt[2].fY - srcPt[0].fY;
1347 x1 = srcPt[2].fX - srcPt[1].fX;
1348 y1 = srcPt[2].fY - srcPt[1].fY;
1349 x2 = srcPt[2].fX - srcPt[3].fX;
1350 y2 = srcPt[2].fY - srcPt[3].fY;
1352 /* check if abs(x2) > abs(y2) */
1353 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1354 float denom = SkScalarMulDiv(x1, y2, x2) - y1;
1355 if (checkForZero(denom)) {
1358 a1 = (SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1) / denom;
1360 float denom = x1 - SkScalarMulDiv(y1, x2, y2);
1361 if (checkForZero(denom)) {
1364 a1 = (x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2)) / denom;
1367 /* check if abs(x1) > abs(y1) */
1368 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1369 float denom = y2 - SkScalarMulDiv(x2, y1, x1);
1370 if (checkForZero(denom)) {
1373 a2 = (y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1)) / denom;
1375 float denom = SkScalarMulDiv(y2, x1, y1) - x2;
1376 if (checkForZero(denom)) {
1379 a2 = (SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2) / denom;
1382 float invScale = SkScalarInvert(scale.fX);
1383 dst->fMat[kMScaleX] = (a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX) * invScale;
1384 dst->fMat[kMSkewY] = (a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY) * invScale;
1385 dst->fMat[kMPersp0] = a2 * invScale;
1387 invScale = SkScalarInvert(scale.fY);
1388 dst->fMat[kMSkewX] = (a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX) * invScale;
1389 dst->fMat[kMScaleY] = (a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY) * invScale;
1390 dst->fMat[kMPersp1] = a1 * invScale;
1392 dst->fMat[kMTransX] = srcPt[0].fX;
1393 dst->fMat[kMTransY] = srcPt[0].fY;
1394 dst->fMat[kMPersp2] = 1;
1395 dst->setTypeMask(kUnknown_Mask);
1399 typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
1401 /* Taken from Rob Johnson's original sample code in QuickDraw GX
1403 bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
1405 if ((unsigned)count > 4) {
1406 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1415 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1420 if (!poly_to_point(&scale, src, count) ||
1421 SkScalarNearlyZero(scale.fX) ||
1422 SkScalarNearlyZero(scale.fY)) {
1426 static const PolyMapProc gPolyMapProcs[] = {
1427 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1429 PolyMapProc proc = gPolyMapProcs[count - 2];
1431 SkMatrix tempMap, result;
1432 tempMap.setTypeMask(kUnknown_Mask);
1434 if (!proc(src, &tempMap, scale)) {
1437 if (!tempMap.invert(&result)) {
1440 if (!proc(dst, &tempMap, scale)) {
1443 this->setConcat(tempMap, result);
1447 ///////////////////////////////////////////////////////////////////////////////
1455 template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
1456 const SkScalar m[9],
1457 SkScalar results[/*1 or 2*/]) {
1458 if (typeMask & SkMatrix::kPerspective_Mask) {
1461 if (SkMatrix::kIdentity_Mask == typeMask) {
1462 results[0] = SK_Scalar1;
1463 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1464 results[1] = SK_Scalar1;
1468 if (!(typeMask & SkMatrix::kAffine_Mask)) {
1469 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1470 results[0] = SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1471 SkScalarAbs(m[SkMatrix::kMScaleY]));
1472 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1473 results[0] = SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1474 SkScalarAbs(m[SkMatrix::kMScaleY]));
1476 results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
1477 results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
1478 if (results[0] > results[1]) {
1479 SkTSwap(results[0], results[1]);
1484 // ignore the translation part of the matrix, just look at 2x2 portion.
1485 // compute singular values, take largest or smallest abs value.
1486 // [a b; b c] = A^T*A
1487 SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
1488 m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
1489 SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
1490 m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
1491 SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX],
1492 m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
1493 // eigenvalues of A^T*A are the squared singular values of A.
1494 // characteristic equation is det((A^T*A) - l*I) = 0
1495 // l^2 - (a + c)l + (ac-b^2)
1496 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1497 // and roots are guaranteed to be pos and real).
1498 SkScalar bSqd = b * b;
1499 // if upper left 2x2 is orthogonal save some math
1500 if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
1501 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1502 results[0] = SkMinScalar(a, c);
1503 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1504 results[0] = SkMaxScalar(a, c);
1508 if (results[0] > results[1]) {
1509 SkTSwap(results[0], results[1]);
1513 SkScalar aminusc = a - c;
1514 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1515 SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
1516 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1517 results[0] = apluscdiv2 - x;
1518 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1519 results[0] = apluscdiv2 + x;
1521 results[0] = apluscdiv2 - x;
1522 results[1] = apluscdiv2 + x;
1525 SkASSERT(results[0] >= 0);
1526 results[0] = SkScalarSqrt(results[0]);
1527 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1528 SkASSERT(results[1] >= 0);
1529 results[1] = SkScalarSqrt(results[1]);
1534 SkScalar SkMatrix::getMinScale() const {
1536 if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1543 SkScalar SkMatrix::getMaxScale() const {
1545 if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1552 bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1553 return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1562 const SkMatrix& asSkMatrix() const { return *reinterpret_cast<const SkMatrix*>(this); }
1564 SK_COMPILE_ASSERT(sizeof(PODMatrix) == sizeof(SkMatrix), PODMatrixSizeMismatch);
1568 const SkMatrix& SkMatrix::I() {
1569 SK_COMPILE_ASSERT(offsetof(SkMatrix, fMat) == offsetof(PODMatrix, matrix), BadfMat);
1570 SK_COMPILE_ASSERT(offsetof(SkMatrix, fTypeMask) == offsetof(PODMatrix, typemask), BadfTypeMask);
1572 static const PODMatrix identity = { {SK_Scalar1, 0, 0,
1575 kIdentity_Mask | kRectStaysRect_Mask};
1576 SkASSERT(identity.asSkMatrix().isIdentity());
1577 return identity.asSkMatrix();
1580 const SkMatrix& SkMatrix::InvalidMatrix() {
1581 SK_COMPILE_ASSERT(offsetof(SkMatrix, fMat) == offsetof(PODMatrix, matrix), BadfMat);
1582 SK_COMPILE_ASSERT(offsetof(SkMatrix, fTypeMask) == offsetof(PODMatrix, typemask), BadfTypeMask);
1584 static const PODMatrix invalid =
1585 { {SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1586 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1587 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax },
1588 kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask };
1589 return invalid.asSkMatrix();
1592 ///////////////////////////////////////////////////////////////////////////////
1594 size_t SkMatrix::writeToMemory(void* buffer) const {
1595 // TODO write less for simple matrices
1596 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1598 memcpy(buffer, fMat, sizeInMemory);
1600 return sizeInMemory;
1603 size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
1604 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1605 if (length < sizeInMemory) {
1609 memcpy(fMat, buffer, sizeInMemory);
1610 this->setTypeMask(kUnknown_Mask);
1612 return sizeInMemory;
1616 void SkMatrix::dump() const {
1618 this->toString(&str);
1619 SkDebugf("%s\n", str.c_str());
1623 #ifndef SK_IGNORE_TO_STRING
1624 void SkMatrix::toString(SkString* str) const {
1625 str->appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
1626 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1627 fMat[6], fMat[7], fMat[8]);
1631 ///////////////////////////////////////////////////////////////////////////////
1633 #include "SkMatrixUtils.h"
1635 bool SkTreatAsSprite(const SkMatrix& mat, int width, int height,
1636 unsigned subpixelBits) {
1637 // quick reject on affine or perspective
1638 if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
1642 // quick success check
1643 if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1647 // mapRect supports negative scales, so we eliminate those first
1648 if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1653 SkIRect isrc = { 0, 0, width, height };
1658 mat.mapRect(&dst, src);
1661 // just apply the translate to isrc
1662 isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1663 SkScalarRoundToInt(mat.getTranslateY()));
1666 isrc.fLeft <<= subpixelBits;
1667 isrc.fTop <<= subpixelBits;
1668 isrc.fRight <<= subpixelBits;
1669 isrc.fBottom <<= subpixelBits;
1671 const float scale = 1 << subpixelBits;
1674 dst.fRight *= scale;
1675 dst.fBottom *= scale;
1680 return isrc == idst;
1683 // A square matrix M can be decomposed (via polar decomposition) into two matrices --
1684 // an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
1685 // where U is another orthogonal matrix and W is a scale matrix. These can be recombined
1686 // to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
1688 // The one wrinkle is that traditionally Q may contain a reflection -- the
1689 // calculation has been rejiggered to put that reflection into W.
1690 bool SkDecomposeUpper2x2(const SkMatrix& matrix,
1693 SkPoint* rotation2) {
1695 SkScalar A = matrix[SkMatrix::kMScaleX];
1696 SkScalar B = matrix[SkMatrix::kMSkewX];
1697 SkScalar C = matrix[SkMatrix::kMSkewY];
1698 SkScalar D = matrix[SkMatrix::kMScaleY];
1700 if (is_degenerate_2x2(A, B, C, D)) {
1705 SkScalar cos1, sin1;
1706 SkScalar cos2, sin2;
1708 // do polar decomposition (M = Q*S)
1709 SkScalar cosQ, sinQ;
1711 // if M is already symmetric (i.e., M = I*S)
1712 if (SkScalarNearlyEqual(B, C)) {
1722 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
1727 // we don't calc Sc since it's symmetric
1728 Sa = A*cosQ + C*sinQ;
1729 Sb = B*cosQ + D*sinQ;
1730 Sd = -B*sinQ + D*cosQ;
1733 // Now we need to compute eigenvalues of S (our scale factors)
1734 // and eigenvectors (bases for our rotation)
1735 // From this, should be able to reconstruct S as U*W*U^T
1736 if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
1737 // already diagonalized
1745 double diff = Sa - Sd;
1746 double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
1747 double trace = Sa + Sd;
1749 w1 = 0.5*(trace + discriminant);
1750 w2 = 0.5*(trace - discriminant);
1752 w1 = 0.5*(trace - discriminant);
1753 w2 = 0.5*(trace + discriminant);
1756 cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
1757 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
1761 // rotation 2 is composition of Q and U
1762 cos2 = cos1*cosQ - sin1*sinQ;
1763 sin2 = sin1*cosQ + cos1*sinQ;
1765 // rotation 1 is U^T
1770 scale->fX = SkDoubleToScalar(w1);
1771 scale->fY = SkDoubleToScalar(w2);
1774 rotation1->fX = cos1;
1775 rotation1->fY = sin1;
1778 rotation2->fX = cos2;
1779 rotation2->fY = sin2;