blob: 41c0f883a7bdc9709aade0a23e2a94f493c1e3f1 [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
reed@android.com8a1c16f2008-12-17 15:59:43 +00008#include "SkMatrix.h"
9#include "Sk64.h"
10#include "SkFloatBits.h"
commit-bot@chromium.org21a705d2013-10-10 21:58:31 +000011#include "SkOnce.h"
reed@android.com31745582009-07-08 14:46:11 +000012#include "SkScalarCompare.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkString.h"
14
15#ifdef SK_SCALAR_IS_FLOAT
16 #define kMatrix22Elem SK_Scalar1
reed@android.comab7ac022009-09-18 13:38:43 +000017
18 static inline float SkDoubleToFloat(double x) {
19 return static_cast<float>(x);
20 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000021#else
22 #define kMatrix22Elem SK_Fract1
23#endif
24
25/* [scale-x skew-x trans-x] [X] [X']
26 [skew-y scale-y trans-y] * [Y] = [Y']
27 [persp-0 persp-1 persp-2] [1] [1 ]
28*/
29
30void SkMatrix::reset() {
31 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000032 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +000033 fMat[kMTransX] = fMat[kMTransY] =
34 fMat[kMPersp0] = fMat[kMPersp1] = 0;
35 fMat[kMPersp2] = kMatrix22Elem;
36
37 this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
38}
39
reed@android.com8a1c16f2008-12-17 15:59:43 +000040// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
41enum {
42 kTranslate_Shift,
43 kScale_Shift,
44 kAffine_Shift,
45 kPerspective_Shift,
46 kRectStaysRect_Shift
47};
48
49#ifdef SK_SCALAR_IS_FLOAT
50 static const int32_t kScalar1Int = 0x3f800000;
reed@android.com8a1c16f2008-12-17 15:59:43 +000051#else
52 #define scalarAsInt(x) (x)
53 static const int32_t kScalar1Int = (1 << 16);
54 static const int32_t kPersp1Int = (1 << 30);
55#endif
56
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000057uint8_t SkMatrix::computePerspectiveTypeMask() const {
junov@chromium.org6fc56992012-07-12 14:01:32 +000058#ifdef SK_SCALAR_SLOW_COMPARES
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000059 if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
60 SkScalarAs2sCompliment(fMat[kMPersp1]) |
61 (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
junov@chromium.org6fc56992012-07-12 14:01:32 +000062 return SkToU8(kORableMasks);
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000063 }
junov@chromium.org6fc56992012-07-12 14:01:32 +000064#else
65 // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
66 // is a win, but replacing those below is not. We don't yet understand
67 // that result.
68 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 ||
69 fMat[kMPersp2] != kMatrix22Elem) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000070 // If this is a perspective transform, we return true for all other
bsalomon@google.com19263b12012-07-13 13:36:38 +000071 // transform flags - this does not disable any optimizations, respects
rmistry@google.comfbfcd562012-08-23 18:09:54 +000072 // the rule that the type mask must be conservative, and speeds up
junov@chromium.org6fc56992012-07-12 14:01:32 +000073 // type mask computation.
74 return SkToU8(kORableMasks);
75 }
76#endif
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000077
junov@chromium.org6fc56992012-07-12 14:01:32 +000078 return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000079}
80
reed@android.com8a1c16f2008-12-17 15:59:43 +000081uint8_t SkMatrix::computeTypeMask() const {
82 unsigned mask = 0;
83
tomhudson@google.comac385252011-06-06 15:18:28 +000084#ifdef SK_SCALAR_SLOW_COMPARES
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
86 SkScalarAs2sCompliment(fMat[kMPersp1]) |
87 (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
junov@chromium.org6fc56992012-07-12 14:01:32 +000088 return SkToU8(kORableMasks);
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 }
tomhudson@google.comac385252011-06-06 15:18:28 +000090
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 if (SkScalarAs2sCompliment(fMat[kMTransX]) |
92 SkScalarAs2sCompliment(fMat[kMTransY])) {
93 mask |= kTranslate_Mask;
94 }
tomhudson@google.comac385252011-06-06 15:18:28 +000095#else
tomhudson@google.comac385252011-06-06 15:18:28 +000096 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 ||
tomhudson@google.com521ed7c2011-06-06 17:21:44 +000097 fMat[kMPersp2] != kMatrix22Elem) {
junov@chromium.org6fc56992012-07-12 14:01:32 +000098 // Once it is determined that that this is a perspective transform,
99 // all other flags are moot as far as optimizations are concerned.
100 return SkToU8(kORableMasks);
tomhudson@google.comac385252011-06-06 15:18:28 +0000101 }
102
103 if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
104 mask |= kTranslate_Mask;
105 }
106#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107
108 int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
109 int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
110 int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
111 int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
tomhudson@google.comac385252011-06-06 15:18:28 +0000112
reed@android.com8a1c16f2008-12-17 15:59:43 +0000113 if (m01 | m10) {
junov@chromium.org6fc56992012-07-12 14:01:32 +0000114 // The skew components may be scale-inducing, unless we are dealing
115 // with a pure rotation. Testing for a pure rotation is expensive,
116 // so we opt for being conservative by always setting the scale bit.
117 // along with affine.
118 // By doing this, we are also ensuring that matrices have the same
119 // type masks as their inverses.
120 mask |= kAffine_Mask | kScale_Mask;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000121
junov@chromium.org6fc56992012-07-12 14:01:32 +0000122 // For rectStaysRect, in the affine case, we only need check that
123 // the primary diagonal is all zeros and that the secondary diagonal
124 // is all non-zero.
tomhudson@google.comac385252011-06-06 15:18:28 +0000125
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 // map non-zero to 1
reed@android.com8a1c16f2008-12-17 15:59:43 +0000127 m01 = m01 != 0;
128 m10 = m10 != 0;
tomhudson@google.comac385252011-06-06 15:18:28 +0000129
junov@chromium.org6fc56992012-07-12 14:01:32 +0000130 int dp0 = 0 == (m00 | m11) ; // true if both are 0
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 int ds1 = m01 & m10; // true if both are 1
tomhudson@google.comac385252011-06-06 15:18:28 +0000132
junov@chromium.org6fc56992012-07-12 14:01:32 +0000133 mask |= (dp0 & ds1) << kRectStaysRect_Shift;
134 } else {
135 // Only test for scale explicitly if not affine, since affine sets the
136 // scale bit.
137 if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) {
138 mask |= kScale_Mask;
139 }
140
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000141 // Not affine, therefore we already know secondary diagonal is
junov@chromium.org6fc56992012-07-12 14:01:32 +0000142 // all zeros, so we just need to check that primary diagonal is
143 // all non-zero.
144
145 // map non-zero to 1
146 m00 = m00 != 0;
147 m11 = m11 != 0;
148
149 // record if the (p)rimary diagonal is all non-zero
150 mask |= (m00 & m11) << kRectStaysRect_Shift;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000151 }
152
153 return SkToU8(mask);
154}
155
156///////////////////////////////////////////////////////////////////////////////
157
reed@google.com3fb51872011-06-01 15:11:22 +0000158#ifdef SK_SCALAR_IS_FLOAT
159
160bool operator==(const SkMatrix& a, const SkMatrix& b) {
161 const SkScalar* SK_RESTRICT ma = a.fMat;
162 const SkScalar* SK_RESTRICT mb = b.fMat;
163
164 return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
165 ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
166 ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
167}
168
169#endif
170
171///////////////////////////////////////////////////////////////////////////////
172
commit-bot@chromium.org4dcd0622013-07-29 14:43:31 +0000173// helper function to determine if upper-left 2x2 of matrix is degenerate
skia.committer@gmail.com16d53aa2013-07-30 07:01:00 +0000174static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
commit-bot@chromium.org4dcd0622013-07-29 14:43:31 +0000175 SkScalar skewY, SkScalar scaleY) {
176 SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
177 return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero);
178}
179
180///////////////////////////////////////////////////////////////////////////////
181
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000182bool SkMatrix::isSimilarity(SkScalar tol) const {
183 // if identity or translate matrix
184 TypeMask mask = this->getType();
185 if (mask <= kTranslate_Mask) {
186 return true;
187 }
188 if (mask & kPerspective_Mask) {
189 return false;
190 }
191
192 SkScalar mx = fMat[kMScaleX];
193 SkScalar my = fMat[kMScaleY];
194 // if no skew, can just compare scale factors
195 if (!(mask & kAffine_Mask)) {
196 return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
197 }
198 SkScalar sx = fMat[kMSkewX];
199 SkScalar sy = fMat[kMSkewY];
200
commit-bot@chromium.org4dcd0622013-07-29 14:43:31 +0000201 if (is_degenerate_2x2(mx, sx, sy, my)) {
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000202 return false;
203 }
204
205 // it has scales and skews, but it could also be rotation, check it out.
206 SkVector vec[2];
207 vec[0].set(mx, sx);
208 vec[1].set(sy, my);
209
210 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
211 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000212 SkScalarSquare(tol));
213}
214
215bool SkMatrix::preservesRightAngles(SkScalar tol) const {
216 TypeMask mask = this->getType();
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000217
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000218 if (mask <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
219 // identity, translate and/or scale
220 return true;
221 }
222 if (mask & kPerspective_Mask) {
223 return false;
224 }
225
226 SkASSERT(mask & kAffine_Mask);
227
228 SkScalar mx = fMat[kMScaleX];
229 SkScalar my = fMat[kMScaleY];
230 SkScalar sx = fMat[kMSkewX];
231 SkScalar sy = fMat[kMSkewY];
232
commit-bot@chromium.org4dcd0622013-07-29 14:43:31 +0000233 if (is_degenerate_2x2(mx, sx, sy, my)) {
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000234 return false;
235 }
236
237 // it has scales and skews, but it could also be rotation, check it out.
238 SkVector vec[2];
239 vec[0].set(mx, sx);
240 vec[1].set(sy, my);
241
242 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
243 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
244 SkScalarSquare(tol));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000245}
246
247///////////////////////////////////////////////////////////////////////////////
248
reed@android.com8a1c16f2008-12-17 15:59:43 +0000249void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
reed@android.com31745582009-07-08 14:46:11 +0000250 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000251 fMat[kMTransX] = dx;
252 fMat[kMTransY] = dy;
253
254 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000255 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +0000256 fMat[kMPersp0] = fMat[kMPersp1] = 0;
257 fMat[kMPersp2] = kMatrix22Elem;
258
259 this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
260 } else {
261 this->reset();
262 }
263}
264
265bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000266 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267 SkMatrix m;
268 m.setTranslate(dx, dy);
269 return this->preConcat(m);
270 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000271
reed@android.com31745582009-07-08 14:46:11 +0000272 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000273 fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) +
274 SkScalarMul(fMat[kMSkewX], dy);
275 fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
276 SkScalarMul(fMat[kMScaleY], dy);
277
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000278 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 }
280 return true;
281}
282
283bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000284 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285 SkMatrix m;
286 m.setTranslate(dx, dy);
287 return this->postConcat(m);
288 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000289
reed@android.com31745582009-07-08 14:46:11 +0000290 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000291 fMat[kMTransX] += dx;
292 fMat[kMTransY] += dy;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000293 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 }
295 return true;
296}
297
298///////////////////////////////////////////////////////////////////////////////
299
300void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
reed@google.comf244f902011-09-06 21:02:36 +0000301 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
302 this->reset();
303 } else {
304 fMat[kMScaleX] = sx;
305 fMat[kMScaleY] = sy;
306 fMat[kMTransX] = px - SkScalarMul(sx, px);
307 fMat[kMTransY] = py - SkScalarMul(sy, py);
308 fMat[kMPersp2] = kMatrix22Elem;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000309
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000310 fMat[kMSkewX] = fMat[kMSkewY] =
reed@google.comf244f902011-09-06 21:02:36 +0000311 fMat[kMPersp0] = fMat[kMPersp1] = 0;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000312
reed@google.comf244f902011-09-06 21:02:36 +0000313 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
314 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000315}
316
317void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000318 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
319 this->reset();
320 } else {
321 fMat[kMScaleX] = sx;
322 fMat[kMScaleY] = sy;
323 fMat[kMPersp2] = kMatrix22Elem;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324
reed@google.comf244f902011-09-06 21:02:36 +0000325 fMat[kMTransX] = fMat[kMTransY] =
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000326 fMat[kMSkewX] = fMat[kMSkewY] =
reed@google.comf244f902011-09-06 21:02:36 +0000327 fMat[kMPersp0] = fMat[kMPersp1] = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000328
reed@google.comf244f902011-09-06 21:02:36 +0000329 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
330 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000331}
332
bsalomon@google.com5c638652011-07-18 19:31:59 +0000333bool SkMatrix::setIDiv(int divx, int divy) {
334 if (!divx || !divy) {
335 return false;
336 }
337 this->setScale(SK_Scalar1 / divx, SK_Scalar1 / divy);
338 return true;
339}
340
reed@android.com8a1c16f2008-12-17 15:59:43 +0000341bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
342 SkMatrix m;
343 m.setScale(sx, sy, px, py);
344 return this->preConcat(m);
345}
346
347bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000348 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
349 return true;
350 }
351
reed@google.com3fb51872011-06-01 15:11:22 +0000352#ifdef SK_SCALAR_IS_FIXED
reed@android.com8a1c16f2008-12-17 15:59:43 +0000353 SkMatrix m;
354 m.setScale(sx, sy);
355 return this->preConcat(m);
reed@google.com3fb51872011-06-01 15:11:22 +0000356#else
357 // the assumption is that these multiplies are very cheap, and that
358 // a full concat and/or just computing the matrix type is more expensive.
359 // Also, the fixed-point case checks for overflow, but the float doesn't,
360 // so we can get away with these blind multiplies.
361
362 fMat[kMScaleX] = SkScalarMul(fMat[kMScaleX], sx);
363 fMat[kMSkewY] = SkScalarMul(fMat[kMSkewY], sx);
364 fMat[kMPersp0] = SkScalarMul(fMat[kMPersp0], sx);
365
366 fMat[kMSkewX] = SkScalarMul(fMat[kMSkewX], sy);
367 fMat[kMScaleY] = SkScalarMul(fMat[kMScaleY], sy);
368 fMat[kMPersp1] = SkScalarMul(fMat[kMPersp1], sy);
369
370 this->orTypeMask(kScale_Mask);
371 return true;
372#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000373}
374
375bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
reed@google.comf244f902011-09-06 21:02:36 +0000376 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
377 return true;
378 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000379 SkMatrix m;
380 m.setScale(sx, sy, px, py);
381 return this->postConcat(m);
382}
383
384bool SkMatrix::postScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000385 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
386 return true;
387 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000388 SkMatrix m;
389 m.setScale(sx, sy);
390 return this->postConcat(m);
391}
392
393#ifdef SK_SCALAR_IS_FIXED
394 static inline SkFixed roundidiv(SkFixed numer, int denom) {
395 int ns = numer >> 31;
396 int ds = denom >> 31;
397 numer = (numer ^ ns) - ns;
398 denom = (denom ^ ds) - ds;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000399
reed@android.com8a1c16f2008-12-17 15:59:43 +0000400 SkFixed answer = (numer + (denom >> 1)) / denom;
401 int as = ns ^ ds;
402 return (answer ^ as) - as;
403 }
404#endif
405
406// this guy perhaps can go away, if we have a fract/high-precision way to
407// scale matrices
408bool SkMatrix::postIDiv(int divx, int divy) {
409 if (divx == 0 || divy == 0) {
410 return false;
411 }
412
413#ifdef SK_SCALAR_IS_FIXED
414 fMat[kMScaleX] = roundidiv(fMat[kMScaleX], divx);
415 fMat[kMSkewX] = roundidiv(fMat[kMSkewX], divx);
416 fMat[kMTransX] = roundidiv(fMat[kMTransX], divx);
417
418 fMat[kMScaleY] = roundidiv(fMat[kMScaleY], divy);
419 fMat[kMSkewY] = roundidiv(fMat[kMSkewY], divy);
420 fMat[kMTransY] = roundidiv(fMat[kMTransY], divy);
421#else
422 const float invX = 1.f / divx;
423 const float invY = 1.f / divy;
424
425 fMat[kMScaleX] *= invX;
426 fMat[kMSkewX] *= invX;
427 fMat[kMTransX] *= invX;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000428
reed@android.com8a1c16f2008-12-17 15:59:43 +0000429 fMat[kMScaleY] *= invY;
430 fMat[kMSkewY] *= invY;
431 fMat[kMTransY] *= invY;
432#endif
433
434 this->setTypeMask(kUnknown_Mask);
435 return true;
436}
437
438////////////////////////////////////////////////////////////////////////////////////
439
440void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
441 SkScalar px, SkScalar py) {
442 const SkScalar oneMinusCosV = SK_Scalar1 - cosV;
443
444 fMat[kMScaleX] = cosV;
445 fMat[kMSkewX] = -sinV;
446 fMat[kMTransX] = SkScalarMul(sinV, py) + SkScalarMul(oneMinusCosV, px);
447
448 fMat[kMSkewY] = sinV;
449 fMat[kMScaleY] = cosV;
450 fMat[kMTransY] = SkScalarMul(-sinV, px) + SkScalarMul(oneMinusCosV, py);
451
452 fMat[kMPersp0] = fMat[kMPersp1] = 0;
453 fMat[kMPersp2] = kMatrix22Elem;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000454
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000455 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000456}
457
458void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
459 fMat[kMScaleX] = cosV;
460 fMat[kMSkewX] = -sinV;
461 fMat[kMTransX] = 0;
462
463 fMat[kMSkewY] = sinV;
464 fMat[kMScaleY] = cosV;
465 fMat[kMTransY] = 0;
466
467 fMat[kMPersp0] = fMat[kMPersp1] = 0;
468 fMat[kMPersp2] = kMatrix22Elem;
469
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000470 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000471}
472
473void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
474 SkScalar sinV, cosV;
475 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
476 this->setSinCos(sinV, cosV, px, py);
477}
478
479void SkMatrix::setRotate(SkScalar degrees) {
480 SkScalar sinV, cosV;
481 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
482 this->setSinCos(sinV, cosV);
483}
484
485bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
486 SkMatrix m;
487 m.setRotate(degrees, px, py);
488 return this->preConcat(m);
489}
490
491bool SkMatrix::preRotate(SkScalar degrees) {
492 SkMatrix m;
493 m.setRotate(degrees);
494 return this->preConcat(m);
495}
496
497bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
498 SkMatrix m;
499 m.setRotate(degrees, px, py);
500 return this->postConcat(m);
501}
502
503bool SkMatrix::postRotate(SkScalar degrees) {
504 SkMatrix m;
505 m.setRotate(degrees);
506 return this->postConcat(m);
507}
508
509////////////////////////////////////////////////////////////////////////////////////
510
511void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
512 fMat[kMScaleX] = SK_Scalar1;
513 fMat[kMSkewX] = sx;
514 fMat[kMTransX] = SkScalarMul(-sx, py);
515
516 fMat[kMSkewY] = sy;
517 fMat[kMScaleY] = SK_Scalar1;
518 fMat[kMTransY] = SkScalarMul(-sy, px);
519
520 fMat[kMPersp0] = fMat[kMPersp1] = 0;
521 fMat[kMPersp2] = kMatrix22Elem;
522
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000523 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000524}
525
526void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
527 fMat[kMScaleX] = SK_Scalar1;
528 fMat[kMSkewX] = sx;
529 fMat[kMTransX] = 0;
530
531 fMat[kMSkewY] = sy;
532 fMat[kMScaleY] = SK_Scalar1;
533 fMat[kMTransY] = 0;
534
535 fMat[kMPersp0] = fMat[kMPersp1] = 0;
536 fMat[kMPersp2] = kMatrix22Elem;
537
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000538 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000539}
540
541bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
542 SkMatrix m;
543 m.setSkew(sx, sy, px, py);
544 return this->preConcat(m);
545}
546
547bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
548 SkMatrix m;
549 m.setSkew(sx, sy);
550 return this->preConcat(m);
551}
552
553bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
554 SkMatrix m;
555 m.setSkew(sx, sy, px, py);
556 return this->postConcat(m);
557}
558
559bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
560 SkMatrix m;
561 m.setSkew(sx, sy);
562 return this->postConcat(m);
563}
564
565///////////////////////////////////////////////////////////////////////////////
566
567bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
568 ScaleToFit align)
569{
570 if (src.isEmpty()) {
571 this->reset();
572 return false;
573 }
574
575 if (dst.isEmpty()) {
reed@android.com4516f472009-06-29 16:25:36 +0000576 sk_bzero(fMat, 8 * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000577 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
578 } else {
579 SkScalar tx, sx = SkScalarDiv(dst.width(), src.width());
580 SkScalar ty, sy = SkScalarDiv(dst.height(), src.height());
581 bool xLarger = false;
582
583 if (align != kFill_ScaleToFit) {
584 if (sx > sy) {
585 xLarger = true;
586 sx = sy;
587 } else {
588 sy = sx;
589 }
590 }
591
592 tx = dst.fLeft - SkScalarMul(src.fLeft, sx);
593 ty = dst.fTop - SkScalarMul(src.fTop, sy);
594 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
595 SkScalar diff;
596
597 if (xLarger) {
598 diff = dst.width() - SkScalarMul(src.width(), sy);
599 } else {
600 diff = dst.height() - SkScalarMul(src.height(), sy);
601 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000602
reed@android.com8a1c16f2008-12-17 15:59:43 +0000603 if (align == kCenter_ScaleToFit) {
604 diff = SkScalarHalf(diff);
605 }
606
607 if (xLarger) {
608 tx += diff;
609 } else {
610 ty += diff;
611 }
612 }
613
614 fMat[kMScaleX] = sx;
615 fMat[kMScaleY] = sy;
616 fMat[kMTransX] = tx;
617 fMat[kMTransY] = ty;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000618 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +0000619 fMat[kMPersp0] = fMat[kMPersp1] = 0;
620
reed@google.com97cd69c2012-10-12 14:35:48 +0000621 unsigned mask = kRectStaysRect_Mask;
622 if (sx != SK_Scalar1 || sy != SK_Scalar1) {
623 mask |= kScale_Mask;
624 }
625 if (tx || ty) {
626 mask |= kTranslate_Mask;
627 }
628 this->setTypeMask(mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000629 }
630 // shared cleanup
631 fMat[kMPersp2] = kMatrix22Elem;
632 return true;
633}
634
635///////////////////////////////////////////////////////////////////////////////
636
637#ifdef SK_SCALAR_IS_FLOAT
638 static inline int fixmuladdmul(float a, float b, float c, float d,
639 float* result) {
reed@android.comab7ac022009-09-18 13:38:43 +0000640 *result = SkDoubleToFloat((double)a * b + (double)c * d);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000641 return true;
642 }
643
644 static inline bool rowcol3(const float row[], const float col[],
645 float* result) {
646 *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
647 return true;
648 }
649
650 static inline int negifaddoverflows(float& result, float a, float b) {
651 result = a + b;
652 return 0;
653 }
654#else
655 static inline bool fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d,
656 SkFixed* result) {
657 Sk64 tmp1, tmp2;
658 tmp1.setMul(a, b);
659 tmp2.setMul(c, d);
660 tmp1.add(tmp2);
661 if (tmp1.isFixed()) {
662 *result = tmp1.getFixed();
663 return true;
664 }
665 return false;
666 }
667
reed@android.com8a1c16f2008-12-17 15:59:43 +0000668 static inline SkFixed fracmuladdmul(SkFixed a, SkFract b, SkFixed c,
669 SkFract d) {
670 Sk64 tmp1, tmp2;
671 tmp1.setMul(a, b);
672 tmp2.setMul(c, d);
673 tmp1.add(tmp2);
674 return tmp1.getFract();
675 }
676
677 static inline bool rowcol3(const SkFixed row[], const SkFixed col[],
678 SkFixed* result) {
679 Sk64 tmp1, tmp2;
680
681 tmp1.setMul(row[0], col[0]); // N * fixed
682 tmp2.setMul(row[1], col[3]); // N * fixed
683 tmp1.add(tmp2);
684
685 tmp2.setMul(row[2], col[6]); // N * fract
686 tmp2.roundRight(14); // make it fixed
687 tmp1.add(tmp2);
688
689 if (tmp1.isFixed()) {
690 *result = tmp1.getFixed();
691 return true;
692 }
693 return false;
694 }
695
696 static inline int negifaddoverflows(SkFixed& result, SkFixed a, SkFixed b) {
697 SkFixed c = a + b;
698 result = c;
699 return (c ^ a) & (c ^ b);
700 }
701#endif
702
703static void normalize_perspective(SkScalar mat[9]) {
704 if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > kMatrix22Elem) {
705 for (int i = 0; i < 9; i++)
706 mat[i] = SkScalarHalf(mat[i]);
707 }
708}
709
710bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000711 TypeMask aType = a.getPerspectiveTypeMaskOnly();
712 TypeMask bType = b.getPerspectiveTypeMaskOnly();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000714 if (a.isTriviallyIdentity()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000715 *this = b;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000716 } else if (b.isTriviallyIdentity()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000717 *this = a;
718 } else {
719 SkMatrix tmp;
720
721 if ((aType | bType) & kPerspective_Mask) {
722 if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) {
723 return false;
724 }
725 if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) {
726 return false;
727 }
728 if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) {
729 return false;
730 }
731
732 if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) {
733 return false;
734 }
735 if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) {
736 return false;
737 }
738 if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) {
739 return false;
740 }
741
742 if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) {
743 return false;
744 }
745 if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) {
746 return false;
747 }
748 if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) {
749 return false;
750 }
751
752 normalize_perspective(tmp.fMat);
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000753 tmp.setTypeMask(kUnknown_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000754 } else { // not perspective
755 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
756 a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
757 return false;
758 }
759 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX],
760 a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) {
761 return false;
762 }
763 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX],
764 a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) {
765 return false;
766 }
767 if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX],
768 a.fMat[kMTransX]) < 0) {
769 return false;
770 }
771
772 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX],
773 a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) {
774 return false;
775 }
776 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX],
777 a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) {
778 return false;
779 }
780 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX],
781 a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) {
782 return false;
783 }
784 if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY],
785 a.fMat[kMTransY]) < 0) {
786 return false;
787 }
788
789 tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
790 tmp.fMat[kMPersp2] = kMatrix22Elem;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000791 //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
792 //SkASSERT(!(tmp.getType() & kPerspective_Mask));
793 tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000794 }
795 *this = tmp;
796 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000797 return true;
798}
799
800bool SkMatrix::preConcat(const SkMatrix& mat) {
801 // check for identity first, so we don't do a needless copy of ourselves
802 // to ourselves inside setConcat()
803 return mat.isIdentity() || this->setConcat(*this, mat);
804}
805
806bool SkMatrix::postConcat(const SkMatrix& mat) {
807 // check for identity first, so we don't do a needless copy of ourselves
808 // to ourselves inside setConcat()
809 return mat.isIdentity() || this->setConcat(mat, *this);
810}
811
812///////////////////////////////////////////////////////////////////////////////
813
reed@android.com0b9e2db2009-09-16 17:00:17 +0000814/* Matrix inversion is very expensive, but also the place where keeping
815 precision may be most important (here and matrix concat). Hence to avoid
816 bitmap blitting artifacts when walking the inverse, we use doubles for
817 the intermediate math, even though we know that is more expensive.
818 The fixed counter part is us using Sk64 for temp calculations.
819 */
820
reed@android.com8a1c16f2008-12-17 15:59:43 +0000821#ifdef SK_SCALAR_IS_FLOAT
reed@android.com0b9e2db2009-09-16 17:00:17 +0000822 typedef double SkDetScalar;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000823 #define SkPerspMul(a, b) SkScalarMul(a, b)
reed@android.com0b9e2db2009-09-16 17:00:17 +0000824 #define SkScalarMulShift(a, b, s) SkDoubleToFloat((a) * (b))
825 static double sk_inv_determinant(const float mat[9], int isPerspective,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000826 int* /* (only used in Fixed case) */) {
827 double det;
828
829 if (isPerspective) {
830 det = mat[SkMatrix::kMScaleX] * ((double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp2] - (double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp1]) +
831 mat[SkMatrix::kMSkewX] * ((double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp0] - (double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp2]) +
832 mat[SkMatrix::kMTransX] * ((double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp1] - (double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp0]);
833 } else {
834 det = (double)mat[SkMatrix::kMScaleX] * mat[SkMatrix::kMScaleY] - (double)mat[SkMatrix::kMSkewX] * mat[SkMatrix::kMSkewY];
835 }
836
senorblanco@chromium.org0e21ec02010-07-20 15:20:01 +0000837 // Since the determinant is on the order of the cube of the matrix members,
838 // compare to the cube of the default nearly-zero constant (although an
839 // estimate of the condition number would be better if it wasn't so expensive).
840 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000841 return 0;
842 }
reed@android.com0b9e2db2009-09-16 17:00:17 +0000843 return 1.0 / det;
844 }
reed@android.com0b9e2db2009-09-16 17:00:17 +0000845 // we declar a,b,c,d to all be doubles, because we want to perform
846 // double-precision muls and subtract, even though the original values are
847 // from the matrix, which are floats.
848 static float inline mul_diff_scale(double a, double b, double c, double d,
849 double scale) {
850 return SkDoubleToFloat((a * b - c * d) * scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000851 }
852#else
reed@android.com0b9e2db2009-09-16 17:00:17 +0000853 typedef SkFixed SkDetScalar;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000854 #define SkPerspMul(a, b) SkFractMul(a, b)
855 #define SkScalarMulShift(a, b, s) SkMulShift(a, b, s)
856 static void set_muladdmul(Sk64* dst, int32_t a, int32_t b, int32_t c,
857 int32_t d) {
858 Sk64 tmp;
859 dst->setMul(a, b);
860 tmp.setMul(c, d);
861 dst->add(tmp);
862 }
863
864 static SkFixed sk_inv_determinant(const SkFixed mat[9], int isPerspective,
865 int* shift) {
866 Sk64 tmp1, tmp2;
867
868 if (isPerspective) {
869 tmp1.setMul(mat[SkMatrix::kMScaleX], fracmuladdmul(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], -mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1]));
870 tmp2.setMul(mat[SkMatrix::kMSkewX], fracmuladdmul(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], -mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2]));
871 tmp1.add(tmp2);
872 tmp2.setMul(mat[SkMatrix::kMTransX], fracmuladdmul(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], -mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]));
873 tmp1.add(tmp2);
874 } else {
875 tmp1.setMul(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY]);
876 tmp2.setMul(mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
877 tmp1.sub(tmp2);
878 }
879
880 int s = tmp1.getClzAbs();
881 *shift = s;
882
883 SkFixed denom;
884 if (s <= 32) {
885 denom = tmp1.getShiftRight(33 - s);
886 } else {
887 denom = (int32_t)tmp1.fLo << (s - 33);
888 }
889
890 if (denom == 0) {
891 return 0;
892 }
893 /** This could perhaps be a special fractdiv function, since both of its
894 arguments are known to have bit 31 clear and bit 30 set (when they
895 are made positive), thus eliminating the need for calling clz()
896 */
897 return SkFractDiv(SK_Fract1, denom);
898 }
899#endif
900
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000901void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
902 affine[kAScaleX] = SK_Scalar1;
903 affine[kASkewY] = 0;
904 affine[kASkewX] = 0;
905 affine[kAScaleY] = SK_Scalar1;
906 affine[kATransX] = 0;
907 affine[kATransY] = 0;
908}
909
910bool SkMatrix::asAffine(SkScalar affine[6]) const {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000911 if (this->hasPerspective()) {
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000912 return false;
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000913 }
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000914 if (affine) {
915 affine[kAScaleX] = this->fMat[kMScaleX];
916 affine[kASkewY] = this->fMat[kMSkewY];
917 affine[kASkewX] = this->fMat[kMSkewX];
918 affine[kAScaleY] = this->fMat[kMScaleY];
919 affine[kATransX] = this->fMat[kMTransX];
920 affine[kATransY] = this->fMat[kMTransY];
921 }
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000922 return true;
923}
924
bsalomon@google.com683c3c72012-10-31 16:50:38 +0000925bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
926 SkASSERT(!this->isIdentity());
reed@google.com2fb96cc2013-01-04 17:02:33 +0000927
928 TypeMask mask = this->getType();
929
930 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
reed@google.come40591d2013-01-30 15:47:42 +0000931 bool invertible = true;
reed@google.com2fb96cc2013-01-04 17:02:33 +0000932 if (inv) {
933 if (mask & kScale_Mask) {
934 SkScalar invX = fMat[kMScaleX];
935 SkScalar invY = fMat[kMScaleY];
936 if (0 == invX || 0 == invY) {
937 return false;
938 }
939 invX = SkScalarInvert(invX);
940 invY = SkScalarInvert(invY);
941
942 // Must be careful when writing to inv, since it may be the
943 // same memory as this.
944
945 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
946 inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
947
948 inv->fMat[kMScaleX] = invX;
949 inv->fMat[kMScaleY] = invY;
950 inv->fMat[kMPersp2] = kMatrix22Elem;
951 inv->fMat[kMTransX] = -SkScalarMul(fMat[kMTransX], invX);
952 inv->fMat[kMTransY] = -SkScalarMul(fMat[kMTransY], invY);
953
954 inv->setTypeMask(mask | kRectStaysRect_Mask);
955 } else {
956 // translate only
957 inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
958 }
reed@google.come40591d2013-01-30 15:47:42 +0000959 } else { // inv is NULL, just check if we're invertible
960 if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
961 invertible = false;
962 }
reed@google.com2fb96cc2013-01-04 17:02:33 +0000963 }
reed@google.come40591d2013-01-30 15:47:42 +0000964 return invertible;
reed@google.com2fb96cc2013-01-04 17:02:33 +0000965 }
reed@google.com4a1362a2013-01-04 18:52:16 +0000966
reed@google.com2fb96cc2013-01-04 17:02:33 +0000967 int isPersp = mask & kPerspective_Mask;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000968 int shift;
reed@android.com0b9e2db2009-09-16 17:00:17 +0000969 SkDetScalar scale = sk_inv_determinant(fMat, isPersp, &shift);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000970
971 if (scale == 0) { // underflow
972 return false;
973 }
974
975 if (inv) {
976 SkMatrix tmp;
bsalomon@google.comcf9b7502011-08-01 13:26:01 +0000977 if (inv == this) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000978 inv = &tmp;
bsalomon@google.comcf9b7502011-08-01 13:26:01 +0000979 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000980
981 if (isPersp) {
982 shift = 61 - shift;
983 inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift);
984 inv->fMat[kMSkewX] = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX], fMat[kMPersp2]), scale, shift);
985 inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift);
986
987 inv->fMat[kMSkewY] = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY], fMat[kMPersp2]), scale, shift);
988 inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX], fMat[kMPersp0]), scale, shift);
989 inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift);
990
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000991 inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000992 inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift);
993 inv->fMat[kMPersp2] = SkScalarMulShift(SkScalarMul(fMat[kMScaleX], fMat[kMScaleY]) - SkScalarMul(fMat[kMSkewX], fMat[kMSkewY]), scale, shift);
994#ifdef SK_SCALAR_IS_FIXED
995 if (SkAbs32(inv->fMat[kMPersp2]) > SK_Fixed1) {
996 Sk64 tmp;
997
998 tmp.set(SK_Fract1);
999 tmp.shiftLeft(16);
1000 tmp.div(inv->fMat[kMPersp2], Sk64::kRound_DivOption);
1001
1002 SkFract scale = tmp.get32();
1003
1004 for (int i = 0; i < 9; i++) {
1005 inv->fMat[i] = SkFractMul(inv->fMat[i], scale);
1006 }
1007 }
1008 inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
1009#endif
1010 } else { // not perspective
1011#ifdef SK_SCALAR_IS_FIXED
1012 Sk64 tx, ty;
1013 int clzNumer;
1014
1015 // check the 2x2 for overflow
1016 {
1017 int32_t value = SkAbs32(fMat[kMScaleY]);
1018 value |= SkAbs32(fMat[kMSkewX]);
1019 value |= SkAbs32(fMat[kMScaleX]);
1020 value |= SkAbs32(fMat[kMSkewY]);
1021 clzNumer = SkCLZ(value);
1022 if (shift - clzNumer > 31)
1023 return false; // overflow
1024 }
1025
1026 set_muladdmul(&tx, fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX]);
1027 set_muladdmul(&ty, fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY]);
1028 // check tx,ty for overflow
1029 clzNumer = SkCLZ(SkAbs32(tx.fHi) | SkAbs32(ty.fHi));
1030 if (shift - clzNumer > 14) {
1031 return false; // overflow
1032 }
1033
1034 int fixedShift = 61 - shift;
1035 int sk64shift = 44 - shift + clzNumer;
1036
1037 inv->fMat[kMScaleX] = SkMulShift(fMat[kMScaleY], scale, fixedShift);
1038 inv->fMat[kMSkewX] = SkMulShift(-fMat[kMSkewX], scale, fixedShift);
1039 inv->fMat[kMTransX] = SkMulShift(tx.getShiftRight(33 - clzNumer), scale, sk64shift);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001040
reed@android.com8a1c16f2008-12-17 15:59:43 +00001041 inv->fMat[kMSkewY] = SkMulShift(-fMat[kMSkewY], scale, fixedShift);
1042 inv->fMat[kMScaleY] = SkMulShift(fMat[kMScaleX], scale, fixedShift);
1043 inv->fMat[kMTransY] = SkMulShift(ty.getShiftRight(33 - clzNumer), scale, sk64shift);
1044#else
reed@android.com0b9e2db2009-09-16 17:00:17 +00001045 inv->fMat[kMScaleX] = SkDoubleToFloat(fMat[kMScaleY] * scale);
1046 inv->fMat[kMSkewX] = SkDoubleToFloat(-fMat[kMSkewX] * scale);
1047 inv->fMat[kMTransX] = mul_diff_scale(fMat[kMSkewX], fMat[kMTransY],
1048 fMat[kMScaleY], fMat[kMTransX], scale);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001049
reed@android.com0b9e2db2009-09-16 17:00:17 +00001050 inv->fMat[kMSkewY] = SkDoubleToFloat(-fMat[kMSkewY] * scale);
1051 inv->fMat[kMScaleY] = SkDoubleToFloat(fMat[kMScaleX] * scale);
1052 inv->fMat[kMTransY] = mul_diff_scale(fMat[kMSkewY], fMat[kMTransX],
1053 fMat[kMScaleX], fMat[kMTransY], scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001054#endif
1055 inv->fMat[kMPersp0] = 0;
1056 inv->fMat[kMPersp1] = 0;
1057 inv->fMat[kMPersp2] = kMatrix22Elem;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001058
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 }
1060
junov@chromium.org6fc56992012-07-12 14:01:32 +00001061 inv->setTypeMask(fTypeMask);
1062
reed@android.com8a1c16f2008-12-17 15:59:43 +00001063 if (inv == &tmp) {
1064 *(SkMatrix*)this = tmp;
1065 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001066 }
1067 return true;
1068}
1069
1070///////////////////////////////////////////////////////////////////////////////
1071
1072void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
1073 const SkPoint src[], int count) {
1074 SkASSERT(m.getType() == 0);
1075
1076 if (dst != src && count > 0)
1077 memcpy(dst, src, count * sizeof(SkPoint));
1078}
1079
1080void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
1081 const SkPoint src[], int count) {
1082 SkASSERT(m.getType() == kTranslate_Mask);
1083
1084 if (count > 0) {
1085 SkScalar tx = m.fMat[kMTransX];
1086 SkScalar ty = m.fMat[kMTransY];
1087 do {
1088 dst->fY = src->fY + ty;
1089 dst->fX = src->fX + tx;
1090 src += 1;
1091 dst += 1;
1092 } while (--count);
1093 }
1094}
1095
1096void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
1097 const SkPoint src[], int count) {
1098 SkASSERT(m.getType() == kScale_Mask);
1099
1100 if (count > 0) {
1101 SkScalar mx = m.fMat[kMScaleX];
1102 SkScalar my = m.fMat[kMScaleY];
1103 do {
1104 dst->fY = SkScalarMul(src->fY, my);
1105 dst->fX = SkScalarMul(src->fX, mx);
1106 src += 1;
1107 dst += 1;
1108 } while (--count);
1109 }
1110}
1111
1112void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
1113 const SkPoint src[], int count) {
1114 SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
1115
1116 if (count > 0) {
1117 SkScalar mx = m.fMat[kMScaleX];
1118 SkScalar my = m.fMat[kMScaleY];
1119 SkScalar tx = m.fMat[kMTransX];
1120 SkScalar ty = m.fMat[kMTransY];
1121 do {
1122 dst->fY = SkScalarMulAdd(src->fY, my, ty);
1123 dst->fX = SkScalarMulAdd(src->fX, mx, tx);
1124 src += 1;
1125 dst += 1;
1126 } while (--count);
1127 }
1128}
1129
1130void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
1131 const SkPoint src[], int count) {
1132 SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
1133
1134 if (count > 0) {
1135 SkScalar mx = m.fMat[kMScaleX];
1136 SkScalar my = m.fMat[kMScaleY];
1137 SkScalar kx = m.fMat[kMSkewX];
1138 SkScalar ky = m.fMat[kMSkewY];
1139 do {
1140 SkScalar sy = src->fY;
1141 SkScalar sx = src->fX;
1142 src += 1;
1143 dst->fY = SkScalarMul(sx, ky) + SkScalarMul(sy, my);
1144 dst->fX = SkScalarMul(sx, mx) + SkScalarMul(sy, kx);
1145 dst += 1;
1146 } while (--count);
1147 }
1148}
1149
1150void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
1151 const SkPoint src[], int count) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001152 SkASSERT(!m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001153
1154 if (count > 0) {
1155 SkScalar mx = m.fMat[kMScaleX];
1156 SkScalar my = m.fMat[kMScaleY];
1157 SkScalar kx = m.fMat[kMSkewX];
1158 SkScalar ky = m.fMat[kMSkewY];
1159 SkScalar tx = m.fMat[kMTransX];
1160 SkScalar ty = m.fMat[kMTransY];
1161 do {
1162 SkScalar sy = src->fY;
1163 SkScalar sx = src->fX;
1164 src += 1;
1165 dst->fY = SkScalarMul(sx, ky) + SkScalarMulAdd(sy, my, ty);
1166 dst->fX = SkScalarMul(sx, mx) + SkScalarMulAdd(sy, kx, tx);
1167 dst += 1;
1168 } while (--count);
1169 }
1170}
1171
1172void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
1173 const SkPoint src[], int count) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001174 SkASSERT(m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001175
1176#ifdef SK_SCALAR_IS_FIXED
1177 SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]);
1178#endif
1179
1180 if (count > 0) {
1181 do {
1182 SkScalar sy = src->fY;
1183 SkScalar sx = src->fX;
1184 src += 1;
1185
1186 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1187 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1188 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1189 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1190#ifdef SK_SCALAR_IS_FIXED
1191 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
1192 SkFractMul(sy, m.fMat[kMPersp1]) + persp2;
1193#else
1194 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1195 SkScalarMulAdd(sy, m.fMat[kMPersp1], m.fMat[kMPersp2]);
1196#endif
1197 if (z) {
1198 z = SkScalarFastInvert(z);
1199 }
1200
1201 dst->fY = SkScalarMul(y, z);
1202 dst->fX = SkScalarMul(x, z);
1203 dst += 1;
1204 } while (--count);
1205 }
1206}
1207
1208const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
1209 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
1210 SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts,
1211 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
1212 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
1213 // repeat the persp proc 8 times
1214 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1215 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1216 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1217 SkMatrix::Persp_pts, SkMatrix::Persp_pts
1218};
1219
1220void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
egdaniel@google.com259fbaf2013-08-15 21:12:11 +00001221 SkASSERT((dst && src && count > 0) || 0 == count);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001222 // no partial overlap
bungeman@google.com3dc82c42013-10-11 19:11:10 +00001223 SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001224
1225 this->getMapPtsProc()(*this, dst, src, count);
1226}
1227
1228///////////////////////////////////////////////////////////////////////////////
1229
egdaniel@google.com259fbaf2013-08-15 21:12:11 +00001230void SkMatrix::mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const {
1231 SkASSERT((dst && src && count > 0) || 0 == count);
1232 // no partial overlap
1233 SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= 3*count);
1234
1235 if (count > 0) {
1236 if (this->isIdentity()) {
1237 memcpy(dst, src, 3*count*sizeof(SkScalar));
1238 return;
1239 }
1240 do {
1241 SkScalar sx = src[0];
1242 SkScalar sy = src[1];
1243 SkScalar sw = src[2];
1244 src += 3;
1245
1246 SkScalar x = SkScalarMul(sx, fMat[kMScaleX]) +
1247 SkScalarMul(sy, fMat[kMSkewX]) +
1248 SkScalarMul(sw, fMat[kMTransX]);
1249 SkScalar y = SkScalarMul(sx, fMat[kMSkewY]) +
1250 SkScalarMul(sy, fMat[kMScaleY]) +
1251 SkScalarMul(sw, fMat[kMTransY]);
1252 SkScalar w = SkScalarMul(sx, fMat[kMPersp0]) +
1253 SkScalarMul(sy, fMat[kMPersp1]) +
1254 SkScalarMul(sw, fMat[kMPersp2]);
1255
1256 dst[0] = x;
1257 dst[1] = y;
1258 dst[2] = w;
1259 dst += 3;
1260 } while (--count);
1261 }
1262}
1263
1264///////////////////////////////////////////////////////////////////////////////
1265
reed@android.com8a1c16f2008-12-17 15:59:43 +00001266void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001267 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001268 SkPoint origin;
1269
1270 MapXYProc proc = this->getMapXYProc();
1271 proc(*this, 0, 0, &origin);
1272
1273 for (int i = count - 1; i >= 0; --i) {
1274 SkPoint tmp;
1275
1276 proc(*this, src[i].fX, src[i].fY, &tmp);
1277 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1278 }
1279 } else {
1280 SkMatrix tmp = *this;
1281
1282 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1283 tmp.clearTypeMask(kTranslate_Mask);
1284 tmp.mapPoints(dst, src, count);
1285 }
1286}
1287
1288bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
1289 SkASSERT(dst && &src);
1290
1291 if (this->rectStaysRect()) {
1292 this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
1293 dst->sort();
1294 return true;
1295 } else {
1296 SkPoint quad[4];
1297
1298 src.toQuad(quad);
1299 this->mapPoints(quad, quad, 4);
1300 dst->set(quad, 4);
1301 return false;
1302 }
1303}
1304
1305SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1306 SkVector vec[2];
1307
1308 vec[0].set(radius, 0);
1309 vec[1].set(0, radius);
1310 this->mapVectors(vec, 2);
1311
1312 SkScalar d0 = vec[0].length();
1313 SkScalar d1 = vec[1].length();
1314
1315 return SkScalarMean(d0, d1);
1316}
1317
1318///////////////////////////////////////////////////////////////////////////////
1319
1320void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1321 SkPoint* pt) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001322 SkASSERT(m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001323
1324 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1325 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1326 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1327 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1328#ifdef SK_SCALAR_IS_FIXED
1329 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
1330 SkFractMul(sy, m.fMat[kMPersp1]) +
1331 SkFractToFixed(m.fMat[kMPersp2]);
1332#else
1333 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1334 SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1335#endif
1336 if (z) {
1337 z = SkScalarFastInvert(z);
1338 }
1339 pt->fX = SkScalarMul(x, z);
1340 pt->fY = SkScalarMul(y, z);
1341}
1342
1343#ifdef SK_SCALAR_IS_FIXED
1344static SkFixed fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d) {
1345 Sk64 tmp, tmp1;
1346
1347 tmp.setMul(a, b);
1348 tmp1.setMul(c, d);
1349 return tmp.addGetFixed(tmp1);
1350// tmp.add(tmp1);
1351// return tmp.getFixed();
1352}
1353#endif
1354
1355void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1356 SkPoint* pt) {
1357 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001358
reed@android.com8a1c16f2008-12-17 15:59:43 +00001359#ifdef SK_SCALAR_IS_FIXED
1360 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) +
1361 m.fMat[kMTransX];
1362 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) +
1363 m.fMat[kMTransY];
1364#else
1365 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1366 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1367 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1368 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1369#endif
1370}
1371
1372void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1373 SkPoint* pt) {
1374 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1375 SkASSERT(0 == m.fMat[kMTransX]);
1376 SkASSERT(0 == m.fMat[kMTransY]);
1377
1378#ifdef SK_SCALAR_IS_FIXED
1379 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]);
1380 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]);
1381#else
1382 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1383 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1384 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1385 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1386#endif
1387}
1388
1389void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1390 SkPoint* pt) {
1391 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1392 == kScale_Mask);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001393
reed@android.com8a1c16f2008-12-17 15:59:43 +00001394 pt->fX = SkScalarMulAdd(sx, m.fMat[kMScaleX], m.fMat[kMTransX]);
1395 pt->fY = SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1396}
1397
1398void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1399 SkPoint* pt) {
1400 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1401 == kScale_Mask);
1402 SkASSERT(0 == m.fMat[kMTransX]);
1403 SkASSERT(0 == m.fMat[kMTransY]);
1404
1405 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]);
1406 pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]);
1407}
1408
1409void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1410 SkPoint* pt) {
1411 SkASSERT(m.getType() == kTranslate_Mask);
1412
1413 pt->fX = sx + m.fMat[kMTransX];
1414 pt->fY = sy + m.fMat[kMTransY];
1415}
1416
1417void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1418 SkPoint* pt) {
1419 SkASSERT(0 == m.getType());
1420
1421 pt->fX = sx;
1422 pt->fY = sy;
1423}
1424
1425const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1426 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1427 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1428 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1429 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1430 // repeat the persp proc 8 times
1431 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1432 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1433 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1434 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1435};
1436
1437///////////////////////////////////////////////////////////////////////////////
1438
1439// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1440#ifdef SK_SCALAR_IS_FIXED
1441 typedef SkFract SkPerspElemType;
1442 #define PerspNearlyZero(x) (SkAbs32(x) < (SK_Fract1 >> 26))
1443#else
1444 typedef float SkPerspElemType;
1445 #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1446#endif
1447
1448bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
1449 if (PerspNearlyZero(fMat[kMPersp0])) {
1450 if (stepX || stepY) {
1451 if (PerspNearlyZero(fMat[kMPersp1]) &&
1452 PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem)) {
1453 if (stepX) {
1454 *stepX = SkScalarToFixed(fMat[kMScaleX]);
1455 }
1456 if (stepY) {
1457 *stepY = SkScalarToFixed(fMat[kMSkewY]);
1458 }
1459 } else {
1460#ifdef SK_SCALAR_IS_FIXED
1461 SkFixed z = SkFractMul(y, fMat[kMPersp1]) +
1462 SkFractToFixed(fMat[kMPersp2]);
1463#else
1464 float z = y * fMat[kMPersp1] + fMat[kMPersp2];
1465#endif
1466 if (stepX) {
1467 *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z));
1468 }
1469 if (stepY) {
1470 *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z));
1471 }
1472 }
1473 }
1474 return true;
1475 }
1476 return false;
1477}
1478
1479///////////////////////////////////////////////////////////////////////////////
1480
1481#include "SkPerspIter.h"
1482
1483SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
1484 : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
1485 SkPoint pt;
1486
1487 SkMatrix::Persp_xy(m, x0, y0, &pt);
1488 fX = SkScalarToFixed(pt.fX);
1489 fY = SkScalarToFixed(pt.fY);
1490}
1491
1492int SkPerspIter::next() {
1493 int n = fCount;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001494
reed@android.com8a1c16f2008-12-17 15:59:43 +00001495 if (0 == n) {
1496 return 0;
1497 }
1498 SkPoint pt;
1499 SkFixed x = fX;
1500 SkFixed y = fY;
1501 SkFixed dx, dy;
1502
1503 if (n >= kCount) {
1504 n = kCount;
1505 fSX += SkIntToScalar(kCount);
1506 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1507 fX = SkScalarToFixed(pt.fX);
1508 fY = SkScalarToFixed(pt.fY);
1509 dx = (fX - x) >> kShift;
1510 dy = (fY - y) >> kShift;
1511 } else {
1512 fSX += SkIntToScalar(n);
1513 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1514 fX = SkScalarToFixed(pt.fX);
1515 fY = SkScalarToFixed(pt.fY);
1516 dx = (fX - x) / n;
1517 dy = (fY - y) / n;
1518 }
1519
1520 SkFixed* p = fStorage;
1521 for (int i = 0; i < n; i++) {
1522 *p++ = x; x += dx;
1523 *p++ = y; y += dy;
1524 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001525
reed@android.com8a1c16f2008-12-17 15:59:43 +00001526 fCount -= n;
1527 return n;
1528}
1529
1530///////////////////////////////////////////////////////////////////////////////
1531
1532#ifdef SK_SCALAR_IS_FIXED
1533
1534static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1535 SkFixed x = SK_Fixed1, y = SK_Fixed1;
1536 SkPoint pt1, pt2;
1537 Sk64 w1, w2;
1538
1539 if (count > 1) {
1540 pt1.fX = poly[1].fX - poly[0].fX;
1541 pt1.fY = poly[1].fY - poly[0].fY;
1542 y = SkPoint::Length(pt1.fX, pt1.fY);
1543 if (y == 0) {
1544 return false;
1545 }
1546 switch (count) {
1547 case 2:
1548 break;
1549 case 3:
1550 pt2.fX = poly[0].fY - poly[2].fY;
1551 pt2.fY = poly[2].fX - poly[0].fX;
1552 goto CALC_X;
1553 default:
1554 pt2.fX = poly[0].fY - poly[3].fY;
1555 pt2.fY = poly[3].fX - poly[0].fX;
1556 CALC_X:
1557 w1.setMul(pt1.fX, pt2.fX);
1558 w2.setMul(pt1.fY, pt2.fY);
1559 w1.add(w2);
1560 w1.div(y, Sk64::kRound_DivOption);
1561 if (!w1.is32()) {
1562 return false;
1563 }
1564 x = w1.get32();
1565 break;
1566 }
1567 }
1568 pt->set(x, y);
1569 return true;
1570}
1571
1572bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1573 const SkPoint& scalePt) {
1574 // need to check if SkFixedDiv overflows...
1575
1576 const SkFixed scale = scalePt.fY;
1577 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1578 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[0].fX - srcPt[1].fX, scale);
1579 dst->fMat[kMPersp0] = 0;
1580 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale);
1581 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1582 dst->fMat[kMPersp1] = 0;
1583 dst->fMat[kMTransX] = srcPt[0].fX;
1584 dst->fMat[kMTransY] = srcPt[0].fY;
1585 dst->fMat[kMPersp2] = SK_Fract1;
1586 dst->setTypeMask(kUnknown_Mask);
1587 return true;
1588}
1589
1590bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1591 const SkPoint& scale) {
1592 // really, need to check if SkFixedDiv overflow'd
1593
1594 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[2].fX - srcPt[0].fX, scale.fX);
1595 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[2].fY - srcPt[0].fY, scale.fX);
1596 dst->fMat[kMPersp0] = 0;
1597 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale.fY);
1598 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale.fY);
1599 dst->fMat[kMPersp1] = 0;
1600 dst->fMat[kMTransX] = srcPt[0].fX;
1601 dst->fMat[kMTransY] = srcPt[0].fY;
1602 dst->fMat[kMPersp2] = SK_Fract1;
1603 dst->setTypeMask(kUnknown_Mask);
1604 return true;
1605}
1606
1607bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1608 const SkPoint& scale) {
1609 SkFract a1, a2;
1610 SkFixed x0, y0, x1, y1, x2, y2;
1611
1612 x0 = srcPt[2].fX - srcPt[0].fX;
1613 y0 = srcPt[2].fY - srcPt[0].fY;
1614 x1 = srcPt[2].fX - srcPt[1].fX;
1615 y1 = srcPt[2].fY - srcPt[1].fY;
1616 x2 = srcPt[2].fX - srcPt[3].fX;
1617 y2 = srcPt[2].fY - srcPt[3].fY;
1618
1619 /* check if abs(x2) > abs(y2) */
1620 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1621 SkFixed denom = SkMulDiv(x1, y2, x2) - y1;
1622 if (0 == denom) {
1623 return false;
1624 }
1625 a1 = SkFractDiv(SkMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1626 } else {
1627 SkFixed denom = x1 - SkMulDiv(y1, x2, y2);
1628 if (0 == denom) {
1629 return false;
1630 }
1631 a1 = SkFractDiv(x0 - x1 - SkMulDiv(y0 - y1, x2, y2), denom);
1632 }
1633
1634 /* check if abs(x1) > abs(y1) */
1635 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1636 SkFixed denom = y2 - SkMulDiv(x2, y1, x1);
1637 if (0 == denom) {
1638 return false;
1639 }
1640 a2 = SkFractDiv(y0 - y2 - SkMulDiv(x0 - x2, y1, x1), denom);
1641 } else {
1642 SkFixed denom = SkMulDiv(y2, x1, y1) - x2;
1643 if (0 == denom) {
1644 return false;
1645 }
1646 a2 = SkFractDiv(SkMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1647 }
1648
1649 // need to check if SkFixedDiv overflows...
1650 dst->fMat[kMScaleX] = SkFixedDiv(SkFractMul(a2, srcPt[3].fX) +
1651 srcPt[3].fX - srcPt[0].fX, scale.fX);
1652 dst->fMat[kMSkewY] = SkFixedDiv(SkFractMul(a2, srcPt[3].fY) +
1653 srcPt[3].fY - srcPt[0].fY, scale.fX);
1654 dst->fMat[kMPersp0] = SkFixedDiv(a2, scale.fX);
1655 dst->fMat[kMSkewX] = SkFixedDiv(SkFractMul(a1, srcPt[1].fX) +
1656 srcPt[1].fX - srcPt[0].fX, scale.fY);
1657 dst->fMat[kMScaleY] = SkFixedDiv(SkFractMul(a1, srcPt[1].fY) +
1658 srcPt[1].fY - srcPt[0].fY, scale.fY);
1659 dst->fMat[kMPersp1] = SkFixedDiv(a1, scale.fY);
1660 dst->fMat[kMTransX] = srcPt[0].fX;
1661 dst->fMat[kMTransY] = srcPt[0].fY;
1662 dst->fMat[kMPersp2] = SK_Fract1;
1663 dst->setTypeMask(kUnknown_Mask);
1664 return true;
1665}
1666
1667#else /* Scalar is float */
1668
1669static inline bool checkForZero(float x) {
1670 return x*x == 0;
1671}
1672
1673static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1674 float x = 1, y = 1;
1675 SkPoint pt1, pt2;
1676
1677 if (count > 1) {
1678 pt1.fX = poly[1].fX - poly[0].fX;
1679 pt1.fY = poly[1].fY - poly[0].fY;
1680 y = SkPoint::Length(pt1.fX, pt1.fY);
1681 if (checkForZero(y)) {
1682 return false;
1683 }
1684 switch (count) {
1685 case 2:
1686 break;
1687 case 3:
1688 pt2.fX = poly[0].fY - poly[2].fY;
1689 pt2.fY = poly[2].fX - poly[0].fX;
1690 goto CALC_X;
1691 default:
1692 pt2.fX = poly[0].fY - poly[3].fY;
1693 pt2.fY = poly[3].fX - poly[0].fX;
1694 CALC_X:
1695 x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) +
1696 SkScalarMul(pt1.fY, pt2.fY), y);
1697 break;
1698 }
1699 }
1700 pt->set(x, y);
1701 return true;
1702}
1703
1704bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1705 const SkPoint& scale) {
1706 float invScale = 1 / scale.fY;
1707
1708 dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1709 dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
1710 dst->fMat[kMPersp0] = 0;
1711 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1712 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1713 dst->fMat[kMPersp1] = 0;
1714 dst->fMat[kMTransX] = srcPt[0].fX;
1715 dst->fMat[kMTransY] = srcPt[0].fY;
1716 dst->fMat[kMPersp2] = 1;
1717 dst->setTypeMask(kUnknown_Mask);
1718 return true;
1719}
1720
1721bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1722 const SkPoint& scale) {
1723 float invScale = 1 / scale.fX;
1724 dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
1725 dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
1726 dst->fMat[kMPersp0] = 0;
1727
1728 invScale = 1 / scale.fY;
1729 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1730 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1731 dst->fMat[kMPersp1] = 0;
1732
1733 dst->fMat[kMTransX] = srcPt[0].fX;
1734 dst->fMat[kMTransY] = srcPt[0].fY;
1735 dst->fMat[kMPersp2] = 1;
1736 dst->setTypeMask(kUnknown_Mask);
1737 return true;
1738}
1739
1740bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1741 const SkPoint& scale) {
1742 float a1, a2;
1743 float x0, y0, x1, y1, x2, y2;
1744
1745 x0 = srcPt[2].fX - srcPt[0].fX;
1746 y0 = srcPt[2].fY - srcPt[0].fY;
1747 x1 = srcPt[2].fX - srcPt[1].fX;
1748 y1 = srcPt[2].fY - srcPt[1].fY;
1749 x2 = srcPt[2].fX - srcPt[3].fX;
1750 y2 = srcPt[2].fY - srcPt[3].fY;
1751
1752 /* check if abs(x2) > abs(y2) */
1753 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1754 float denom = SkScalarMulDiv(x1, y2, x2) - y1;
1755 if (checkForZero(denom)) {
1756 return false;
1757 }
1758 a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1759 } else {
1760 float denom = x1 - SkScalarMulDiv(y1, x2, y2);
1761 if (checkForZero(denom)) {
1762 return false;
1763 }
1764 a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), denom);
1765 }
1766
1767 /* check if abs(x1) > abs(y1) */
1768 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1769 float denom = y2 - SkScalarMulDiv(x2, y1, x1);
1770 if (checkForZero(denom)) {
1771 return false;
1772 }
1773 a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), denom);
1774 } else {
1775 float denom = SkScalarMulDiv(y2, x1, y1) - x2;
1776 if (checkForZero(denom)) {
1777 return false;
1778 }
1779 a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1780 }
1781
1782 float invScale = 1 / scale.fX;
1783 dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) +
1784 srcPt[3].fX - srcPt[0].fX, invScale);
1785 dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) +
1786 srcPt[3].fY - srcPt[0].fY, invScale);
1787 dst->fMat[kMPersp0] = SkScalarMul(a2, invScale);
1788 invScale = 1 / scale.fY;
1789 dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) +
1790 srcPt[1].fX - srcPt[0].fX, invScale);
1791 dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) +
1792 srcPt[1].fY - srcPt[0].fY, invScale);
1793 dst->fMat[kMPersp1] = SkScalarMul(a1, invScale);
1794 dst->fMat[kMTransX] = srcPt[0].fX;
1795 dst->fMat[kMTransY] = srcPt[0].fY;
1796 dst->fMat[kMPersp2] = 1;
1797 dst->setTypeMask(kUnknown_Mask);
1798 return true;
1799}
1800
1801#endif
1802
1803typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
1804
1805/* Taken from Rob Johnson's original sample code in QuickDraw GX
1806*/
1807bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
1808 int count) {
1809 if ((unsigned)count > 4) {
1810 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1811 return false;
1812 }
1813
1814 if (0 == count) {
1815 this->reset();
1816 return true;
1817 }
1818 if (1 == count) {
1819 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1820 return true;
1821 }
1822
1823 SkPoint scale;
1824 if (!poly_to_point(&scale, src, count) ||
1825 SkScalarNearlyZero(scale.fX) ||
1826 SkScalarNearlyZero(scale.fY)) {
1827 return false;
1828 }
1829
1830 static const PolyMapProc gPolyMapProcs[] = {
1831 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1832 };
1833 PolyMapProc proc = gPolyMapProcs[count - 2];
1834
1835 SkMatrix tempMap, result;
1836 tempMap.setTypeMask(kUnknown_Mask);
1837
1838 if (!proc(src, &tempMap, scale)) {
1839 return false;
1840 }
1841 if (!tempMap.invert(&result)) {
1842 return false;
1843 }
1844 if (!proc(dst, &tempMap, scale)) {
1845 return false;
1846 }
1847 if (!result.setConcat(tempMap, result)) {
1848 return false;
1849 }
1850 *this = result;
1851 return true;
1852}
1853
1854///////////////////////////////////////////////////////////////////////////////
1855
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001856SkScalar SkMatrix::getMaxStretch() const {
1857 TypeMask mask = this->getType();
1858
bsalomon@google.com38396322011-09-09 19:32:04 +00001859 if (this->hasPerspective()) {
1860 return -SK_Scalar1;
1861 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001862 if (this->isIdentity()) {
bsalomon@google.com38396322011-09-09 19:32:04 +00001863 return SK_Scalar1;
1864 }
1865 if (!(mask & kAffine_Mask)) {
1866 return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
1867 SkScalarAbs(fMat[kMScaleY]));
1868 }
1869 // ignore the translation part of the matrix, just look at 2x2 portion.
1870 // compute singular values, take largest abs value.
1871 // [a b; b c] = A^T*A
1872 SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
1873 SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
1874 SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
1875 SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
1876 SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) +
1877 SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
1878 // eigenvalues of A^T*A are the squared singular values of A.
1879 // characteristic equation is det((A^T*A) - l*I) = 0
1880 // l^2 - (a + c)l + (ac-b^2)
1881 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1882 // and roots are guaraunteed to be pos and real).
1883 SkScalar largerRoot;
1884 SkScalar bSqd = SkScalarMul(b,b);
1885 // if upper left 2x2 is orthogonal save some math
jvanverth@google.comc490f802013-03-04 13:56:38 +00001886 if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
bsalomon@google.com38396322011-09-09 19:32:04 +00001887 largerRoot = SkMaxScalar(a, c);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001888 } else {
bsalomon@google.com38396322011-09-09 19:32:04 +00001889 SkScalar aminusc = a - c;
1890 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1891 SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
1892 largerRoot = apluscdiv2 + x;
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001893 }
bsalomon@google.com38396322011-09-09 19:32:04 +00001894 return SkScalarSqrt(largerRoot);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001895}
1896
commit-bot@chromium.org21a705d2013-10-10 21:58:31 +00001897DEF_SK_ONCE(reset_identity_matrix, SkMatrix* identity) {
1898 identity->reset();
1899}
1900
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001901const SkMatrix& SkMatrix::I() {
commit-bot@chromium.org21a705d2013-10-10 21:58:31 +00001902 // If you can use C++11 now, you might consider replacing this with a constexpr constructor.
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001903 static SkMatrix gIdentity;
commit-bot@chromium.org21a705d2013-10-10 21:58:31 +00001904 SK_ONCE(reset_identity_matrix, &gIdentity);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001905 return gIdentity;
tomhudson@google.com1f902872012-06-01 13:15:47 +00001906}
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001907
1908const SkMatrix& SkMatrix::InvalidMatrix() {
1909 static SkMatrix gInvalid;
1910 static bool gOnce;
1911 if (!gOnce) {
1912 gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1913 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1914 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
1915 gInvalid.getType(); // force the type to be computed
1916 gOnce = true;
1917 }
1918 return gInvalid;
1919}
1920
1921///////////////////////////////////////////////////////////////////////////////
1922
djsollen@google.com94e75ee2012-06-08 18:30:46 +00001923uint32_t SkMatrix::writeToMemory(void* buffer) const {
reed@android.com0ad336f2009-06-29 16:02:20 +00001924 // TODO write less for simple matrices
1925 if (buffer) {
1926 memcpy(buffer, fMat, 9 * sizeof(SkScalar));
1927 }
1928 return 9 * sizeof(SkScalar);
1929}
1930
djsollen@google.com94e75ee2012-06-08 18:30:46 +00001931uint32_t SkMatrix::readFromMemory(const void* buffer) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001932 if (buffer) {
1933 memcpy(fMat, buffer, 9 * sizeof(SkScalar));
1934 this->setTypeMask(kUnknown_Mask);
1935 }
reed@android.com0ad336f2009-06-29 16:02:20 +00001936 return 9 * sizeof(SkScalar);
1937}
1938
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001939#ifdef SK_DEVELOPER
reed@android.com8a1c16f2008-12-17 15:59:43 +00001940void SkMatrix::dump() const {
1941 SkString str;
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001942 this->toString(&str);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001943 SkDebugf("%s\n", str.c_str());
1944}
1945
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001946void SkMatrix::toString(SkString* str) const {
1947 str->appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
reed@android.com8a1c16f2008-12-17 15:59:43 +00001948#ifdef SK_SCALAR_IS_FLOAT
1949 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1950 fMat[6], fMat[7], fMat[8]);
1951#else
1952 SkFixedToFloat(fMat[0]), SkFixedToFloat(fMat[1]), SkFixedToFloat(fMat[2]),
1953 SkFixedToFloat(fMat[3]), SkFixedToFloat(fMat[4]), SkFixedToFloat(fMat[5]),
1954 SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
1955#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001956}
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001957#endif
reed@google.comad514302013-01-02 20:19:45 +00001958
1959///////////////////////////////////////////////////////////////////////////////
1960
1961#include "SkMatrixUtils.h"
1962
reed@google.comae573582013-01-03 15:22:40 +00001963bool SkTreatAsSprite(const SkMatrix& mat, int width, int height,
reed@google.comad514302013-01-02 20:19:45 +00001964 unsigned subpixelBits) {
reed@google.comae573582013-01-03 15:22:40 +00001965 // quick reject on affine or perspective
reed@google.comad514302013-01-02 20:19:45 +00001966 if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
1967 return false;
1968 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001969
reed@google.comad514302013-01-02 20:19:45 +00001970 // quick success check
1971 if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1972 return true;
1973 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001974
reed@google.comad514302013-01-02 20:19:45 +00001975 // mapRect supports negative scales, so we eliminate those first
1976 if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1977 return false;
1978 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001979
reed@google.comad514302013-01-02 20:19:45 +00001980 SkRect dst;
reed@google.comae573582013-01-03 15:22:40 +00001981 SkIRect isrc = { 0, 0, width, height };
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00001982
reed@google.comad514302013-01-02 20:19:45 +00001983 {
reed@google.comae573582013-01-03 15:22:40 +00001984 SkRect src;
1985 src.set(isrc);
1986 mat.mapRect(&dst, src);
reed@google.comad514302013-01-02 20:19:45 +00001987 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001988
reed@google.comae573582013-01-03 15:22:40 +00001989 // just apply the translate to isrc
1990 isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1991 SkScalarRoundToInt(mat.getTranslateY()));
1992
reed@google.comad514302013-01-02 20:19:45 +00001993 if (subpixelBits) {
1994 isrc.fLeft <<= subpixelBits;
1995 isrc.fTop <<= subpixelBits;
1996 isrc.fRight <<= subpixelBits;
1997 isrc.fBottom <<= subpixelBits;
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001998
reed@google.comad514302013-01-02 20:19:45 +00001999 const float scale = 1 << subpixelBits;
2000 dst.fLeft *= scale;
2001 dst.fTop *= scale;
2002 dst.fRight *= scale;
2003 dst.fBottom *= scale;
2004 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00002005
reed@google.comae573582013-01-03 15:22:40 +00002006 SkIRect idst;
reed@google.comad514302013-01-02 20:19:45 +00002007 dst.round(&idst);
2008 return isrc == idst;
2009}
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002010
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002011// A square matrix M can be decomposed (via polar decomposition) into two matrices --
2012// an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
2013// where U is another orthogonal matrix and W is a scale matrix. These can be recombined
2014// to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
2015//
2016// The one wrinkle is that traditionally Q may contain a reflection -- the
2017// calculation has been rejiggered to put that reflection into W.
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002018bool SkDecomposeUpper2x2(const SkMatrix& matrix,
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002019 SkPoint* rotation1,
2020 SkPoint* scale,
2021 SkPoint* rotation2) {
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002022
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002023 SkScalar A = matrix[SkMatrix::kMScaleX];
2024 SkScalar B = matrix[SkMatrix::kMSkewX];
2025 SkScalar C = matrix[SkMatrix::kMSkewY];
2026 SkScalar D = matrix[SkMatrix::kMScaleY];
2027
commit-bot@chromium.org4dcd0622013-07-29 14:43:31 +00002028 if (is_degenerate_2x2(A, B, C, D)) {
2029 return false;
2030 }
2031
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002032 double w1, w2;
2033 SkScalar cos1, sin1;
2034 SkScalar cos2, sin2;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002035
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002036 // do polar decomposition (M = Q*S)
2037 SkScalar cosQ, sinQ;
2038 double Sa, Sb, Sd;
2039 // if M is already symmetric (i.e., M = I*S)
2040 if (SkScalarNearlyEqual(B, C)) {
2041 cosQ = SK_Scalar1;
2042 sinQ = 0;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002043
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002044 Sa = A;
2045 Sb = B;
2046 Sd = D;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002047 } else {
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002048 cosQ = A + D;
2049 sinQ = C - B;
2050 SkScalar reciplen = SK_Scalar1/SkScalarSqrt(cosQ*cosQ + sinQ*sinQ);
2051 cosQ *= reciplen;
2052 sinQ *= reciplen;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002053
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002054 // S = Q^-1*M
2055 // we don't calc Sc since it's symmetric
2056 Sa = A*cosQ + C*sinQ;
2057 Sb = B*cosQ + D*sinQ;
2058 Sd = -B*sinQ + D*cosQ;
2059 }
skia.committer@gmail.com5c561cb2013-07-25 07:01:00 +00002060
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002061 // Now we need to compute eigenvalues of S (our scale factors)
2062 // and eigenvectors (bases for our rotation)
2063 // From this, should be able to reconstruct S as U*W*U^T
jvanverth@google.com25f72ed2013-09-03 19:46:16 +00002064 if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002065 // already diagonalized
2066 cos1 = SK_Scalar1;
2067 sin1 = 0;
2068 w1 = Sa;
2069 w2 = Sd;
2070 cos2 = cosQ;
2071 sin2 = sinQ;
skia.committer@gmail.com85092f02013-09-04 07:01:39 +00002072 } else {
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002073 double diff = Sa - Sd;
2074 double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
2075 double trace = Sa + Sd;
2076 if (diff > 0) {
2077 w1 = 0.5*(trace + discriminant);
2078 w2 = 0.5*(trace - discriminant);
2079 } else {
2080 w1 = 0.5*(trace - discriminant);
2081 w2 = 0.5*(trace + discriminant);
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002082 }
skia.committer@gmail.com85092f02013-09-04 07:01:39 +00002083
jvanverth@google.com25f72ed2013-09-03 19:46:16 +00002084 cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002085 SkScalar reciplen = SK_Scalar1/SkScalarSqrt(cos1*cos1 + sin1*sin1);
2086 cos1 *= reciplen;
2087 sin1 *= reciplen;
skia.committer@gmail.com85092f02013-09-04 07:01:39 +00002088
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002089 // rotation 2 is composition of Q and U
2090 cos2 = cos1*cosQ - sin1*sinQ;
2091 sin2 = sin1*cosQ + cos1*sinQ;
skia.committer@gmail.com85092f02013-09-04 07:01:39 +00002092
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002093 // rotation 1 is U^T
2094 sin1 = -sin1;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002095 }
2096
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002097 if (NULL != scale) {
jvanverth@google.com25f72ed2013-09-03 19:46:16 +00002098 scale->fX = SkDoubleToScalar(w1);
2099 scale->fY = SkDoubleToScalar(w2);
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002100 }
2101 if (NULL != rotation1) {
commit-bot@chromium.org5b2e2642013-09-03 19:08:14 +00002102 rotation1->fX = cos1;
2103 rotation1->fY = sin1;
2104 }
2105 if (NULL != rotation2) {
2106 rotation2->fX = cos2;
2107 rotation2->fY = sin2;
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002108 }
2109
2110 return true;
2111}