blob: 64edd67e8796a8c9ddf3c92fd55b144dd8e2980a [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"
reed@android.com31745582009-07-08 14:46:11 +000011#include "SkScalarCompare.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000012#include "SkString.h"
13
14#ifdef SK_SCALAR_IS_FLOAT
15 #define kMatrix22Elem SK_Scalar1
reed@android.comab7ac022009-09-18 13:38:43 +000016
17 static inline float SkDoubleToFloat(double x) {
18 return static_cast<float>(x);
19 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000020#else
21 #define kMatrix22Elem SK_Fract1
22#endif
23
24/* [scale-x skew-x trans-x] [X] [X']
25 [skew-y scale-y trans-y] * [Y] = [Y']
26 [persp-0 persp-1 persp-2] [1] [1 ]
27*/
28
29void SkMatrix::reset() {
30 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000031 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +000032 fMat[kMTransX] = fMat[kMTransY] =
33 fMat[kMPersp0] = fMat[kMPersp1] = 0;
34 fMat[kMPersp2] = kMatrix22Elem;
35
36 this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
37}
38
reed@android.com8a1c16f2008-12-17 15:59:43 +000039// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
40enum {
41 kTranslate_Shift,
42 kScale_Shift,
43 kAffine_Shift,
44 kPerspective_Shift,
45 kRectStaysRect_Shift
46};
47
48#ifdef SK_SCALAR_IS_FLOAT
49 static const int32_t kScalar1Int = 0x3f800000;
50 static const int32_t kPersp1Int = 0x3f800000;
51#else
52 #define scalarAsInt(x) (x)
53 static const int32_t kScalar1Int = (1 << 16);
54 static const int32_t kPersp1Int = (1 << 30);
55#endif
56
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
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000173bool SkMatrix::isSimilarity(SkScalar tol) const {
174 // if identity or translate matrix
175 TypeMask mask = this->getType();
176 if (mask <= kTranslate_Mask) {
177 return true;
178 }
179 if (mask & kPerspective_Mask) {
180 return false;
181 }
182
183 SkScalar mx = fMat[kMScaleX];
184 SkScalar my = fMat[kMScaleY];
185 // if no skew, can just compare scale factors
186 if (!(mask & kAffine_Mask)) {
187 return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
188 }
189 SkScalar sx = fMat[kMSkewX];
190 SkScalar sy = fMat[kMSkewY];
191
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000192 // TODO: I (rphillips) think there should be an || in here (see preservesRightAngles)
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000193 // degenerate matrix, non-similarity
194 if (SkScalarNearlyZero(mx) && SkScalarNearlyZero(my)
195 && SkScalarNearlyZero(sx) && SkScalarNearlyZero(sy)) {
196 return false;
197 }
198
199 // it has scales and skews, but it could also be rotation, check it out.
200 SkVector vec[2];
201 vec[0].set(mx, sx);
202 vec[1].set(sy, my);
203
204 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
205 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000206 SkScalarSquare(tol));
207}
208
209bool SkMatrix::preservesRightAngles(SkScalar tol) const {
210 TypeMask mask = this->getType();
skia.committer@gmail.com07d3a652013-04-10 07:01:15 +0000211
robertphillips@google.comdf3695e2013-04-09 14:01:44 +0000212 if (mask <= (SkMatrix::kTranslate_Mask | SkMatrix::kScale_Mask)) {
213 // identity, translate and/or scale
214 return true;
215 }
216 if (mask & kPerspective_Mask) {
217 return false;
218 }
219
220 SkASSERT(mask & kAffine_Mask);
221
222 SkScalar mx = fMat[kMScaleX];
223 SkScalar my = fMat[kMScaleY];
224 SkScalar sx = fMat[kMSkewX];
225 SkScalar sy = fMat[kMSkewY];
226
227 if ((SkScalarNearlyZero(mx) && SkScalarNearlyZero(sx)) ||
228 (SkScalarNearlyZero(my) && SkScalarNearlyZero(sy))) {
229 // degenerate matrix
230 return false;
231 }
232
233 // it has scales and skews, but it could also be rotation, check it out.
234 SkVector vec[2];
235 vec[0].set(mx, sx);
236 vec[1].set(sy, my);
237
238 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol)) &&
239 SkScalarNearlyEqual(vec[0].lengthSqd(), vec[1].lengthSqd(),
240 SkScalarSquare(tol));
jvanverth@google.com46d3d392013-01-22 13:34:01 +0000241}
242
243///////////////////////////////////////////////////////////////////////////////
244
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
reed@android.com31745582009-07-08 14:46:11 +0000246 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247 fMat[kMTransX] = dx;
248 fMat[kMTransY] = dy;
249
250 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000251 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +0000252 fMat[kMPersp0] = fMat[kMPersp1] = 0;
253 fMat[kMPersp2] = kMatrix22Elem;
254
255 this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
256 } else {
257 this->reset();
258 }
259}
260
261bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000262 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 SkMatrix m;
264 m.setTranslate(dx, dy);
265 return this->preConcat(m);
266 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000267
reed@android.com31745582009-07-08 14:46:11 +0000268 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000269 fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) +
270 SkScalarMul(fMat[kMSkewX], dy);
271 fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
272 SkScalarMul(fMat[kMScaleY], dy);
273
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000274 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000275 }
276 return true;
277}
278
279bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000280 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000281 SkMatrix m;
282 m.setTranslate(dx, dy);
283 return this->postConcat(m);
284 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000285
reed@android.com31745582009-07-08 14:46:11 +0000286 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287 fMat[kMTransX] += dx;
288 fMat[kMTransY] += dy;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000289 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000290 }
291 return true;
292}
293
294///////////////////////////////////////////////////////////////////////////////
295
296void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
reed@google.comf244f902011-09-06 21:02:36 +0000297 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
298 this->reset();
299 } else {
300 fMat[kMScaleX] = sx;
301 fMat[kMScaleY] = sy;
302 fMat[kMTransX] = px - SkScalarMul(sx, px);
303 fMat[kMTransY] = py - SkScalarMul(sy, py);
304 fMat[kMPersp2] = kMatrix22Elem;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000306 fMat[kMSkewX] = fMat[kMSkewY] =
reed@google.comf244f902011-09-06 21:02:36 +0000307 fMat[kMPersp0] = fMat[kMPersp1] = 0;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000308
reed@google.comf244f902011-09-06 21:02:36 +0000309 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
310 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000311}
312
313void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000314 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
315 this->reset();
316 } else {
317 fMat[kMScaleX] = sx;
318 fMat[kMScaleY] = sy;
319 fMat[kMPersp2] = kMatrix22Elem;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000320
reed@google.comf244f902011-09-06 21:02:36 +0000321 fMat[kMTransX] = fMat[kMTransY] =
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000322 fMat[kMSkewX] = fMat[kMSkewY] =
reed@google.comf244f902011-09-06 21:02:36 +0000323 fMat[kMPersp0] = fMat[kMPersp1] = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000324
reed@google.comf244f902011-09-06 21:02:36 +0000325 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
326 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000327}
328
bsalomon@google.com5c638652011-07-18 19:31:59 +0000329bool SkMatrix::setIDiv(int divx, int divy) {
330 if (!divx || !divy) {
331 return false;
332 }
333 this->setScale(SK_Scalar1 / divx, SK_Scalar1 / divy);
334 return true;
335}
336
reed@android.com8a1c16f2008-12-17 15:59:43 +0000337bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
338 SkMatrix m;
339 m.setScale(sx, sy, px, py);
340 return this->preConcat(m);
341}
342
343bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000344 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
345 return true;
346 }
347
reed@google.com3fb51872011-06-01 15:11:22 +0000348#ifdef SK_SCALAR_IS_FIXED
reed@android.com8a1c16f2008-12-17 15:59:43 +0000349 SkMatrix m;
350 m.setScale(sx, sy);
351 return this->preConcat(m);
reed@google.com3fb51872011-06-01 15:11:22 +0000352#else
353 // the assumption is that these multiplies are very cheap, and that
354 // a full concat and/or just computing the matrix type is more expensive.
355 // Also, the fixed-point case checks for overflow, but the float doesn't,
356 // so we can get away with these blind multiplies.
357
358 fMat[kMScaleX] = SkScalarMul(fMat[kMScaleX], sx);
359 fMat[kMSkewY] = SkScalarMul(fMat[kMSkewY], sx);
360 fMat[kMPersp0] = SkScalarMul(fMat[kMPersp0], sx);
361
362 fMat[kMSkewX] = SkScalarMul(fMat[kMSkewX], sy);
363 fMat[kMScaleY] = SkScalarMul(fMat[kMScaleY], sy);
364 fMat[kMPersp1] = SkScalarMul(fMat[kMPersp1], sy);
365
366 this->orTypeMask(kScale_Mask);
367 return true;
368#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000369}
370
371bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
reed@google.comf244f902011-09-06 21:02:36 +0000372 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
373 return true;
374 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000375 SkMatrix m;
376 m.setScale(sx, sy, px, py);
377 return this->postConcat(m);
378}
379
380bool SkMatrix::postScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000381 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
382 return true;
383 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000384 SkMatrix m;
385 m.setScale(sx, sy);
386 return this->postConcat(m);
387}
388
389#ifdef SK_SCALAR_IS_FIXED
390 static inline SkFixed roundidiv(SkFixed numer, int denom) {
391 int ns = numer >> 31;
392 int ds = denom >> 31;
393 numer = (numer ^ ns) - ns;
394 denom = (denom ^ ds) - ds;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000395
reed@android.com8a1c16f2008-12-17 15:59:43 +0000396 SkFixed answer = (numer + (denom >> 1)) / denom;
397 int as = ns ^ ds;
398 return (answer ^ as) - as;
399 }
400#endif
401
402// this guy perhaps can go away, if we have a fract/high-precision way to
403// scale matrices
404bool SkMatrix::postIDiv(int divx, int divy) {
405 if (divx == 0 || divy == 0) {
406 return false;
407 }
408
409#ifdef SK_SCALAR_IS_FIXED
410 fMat[kMScaleX] = roundidiv(fMat[kMScaleX], divx);
411 fMat[kMSkewX] = roundidiv(fMat[kMSkewX], divx);
412 fMat[kMTransX] = roundidiv(fMat[kMTransX], divx);
413
414 fMat[kMScaleY] = roundidiv(fMat[kMScaleY], divy);
415 fMat[kMSkewY] = roundidiv(fMat[kMSkewY], divy);
416 fMat[kMTransY] = roundidiv(fMat[kMTransY], divy);
417#else
418 const float invX = 1.f / divx;
419 const float invY = 1.f / divy;
420
421 fMat[kMScaleX] *= invX;
422 fMat[kMSkewX] *= invX;
423 fMat[kMTransX] *= invX;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000424
reed@android.com8a1c16f2008-12-17 15:59:43 +0000425 fMat[kMScaleY] *= invY;
426 fMat[kMSkewY] *= invY;
427 fMat[kMTransY] *= invY;
428#endif
429
430 this->setTypeMask(kUnknown_Mask);
431 return true;
432}
433
434////////////////////////////////////////////////////////////////////////////////////
435
436void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
437 SkScalar px, SkScalar py) {
438 const SkScalar oneMinusCosV = SK_Scalar1 - cosV;
439
440 fMat[kMScaleX] = cosV;
441 fMat[kMSkewX] = -sinV;
442 fMat[kMTransX] = SkScalarMul(sinV, py) + SkScalarMul(oneMinusCosV, px);
443
444 fMat[kMSkewY] = sinV;
445 fMat[kMScaleY] = cosV;
446 fMat[kMTransY] = SkScalarMul(-sinV, px) + SkScalarMul(oneMinusCosV, py);
447
448 fMat[kMPersp0] = fMat[kMPersp1] = 0;
449 fMat[kMPersp2] = kMatrix22Elem;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000450
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000451 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000452}
453
454void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
455 fMat[kMScaleX] = cosV;
456 fMat[kMSkewX] = -sinV;
457 fMat[kMTransX] = 0;
458
459 fMat[kMSkewY] = sinV;
460 fMat[kMScaleY] = cosV;
461 fMat[kMTransY] = 0;
462
463 fMat[kMPersp0] = fMat[kMPersp1] = 0;
464 fMat[kMPersp2] = kMatrix22Elem;
465
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000466 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000467}
468
469void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
470 SkScalar sinV, cosV;
471 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
472 this->setSinCos(sinV, cosV, px, py);
473}
474
475void SkMatrix::setRotate(SkScalar degrees) {
476 SkScalar sinV, cosV;
477 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
478 this->setSinCos(sinV, cosV);
479}
480
481bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
482 SkMatrix m;
483 m.setRotate(degrees, px, py);
484 return this->preConcat(m);
485}
486
487bool SkMatrix::preRotate(SkScalar degrees) {
488 SkMatrix m;
489 m.setRotate(degrees);
490 return this->preConcat(m);
491}
492
493bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
494 SkMatrix m;
495 m.setRotate(degrees, px, py);
496 return this->postConcat(m);
497}
498
499bool SkMatrix::postRotate(SkScalar degrees) {
500 SkMatrix m;
501 m.setRotate(degrees);
502 return this->postConcat(m);
503}
504
505////////////////////////////////////////////////////////////////////////////////////
506
507void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
508 fMat[kMScaleX] = SK_Scalar1;
509 fMat[kMSkewX] = sx;
510 fMat[kMTransX] = SkScalarMul(-sx, py);
511
512 fMat[kMSkewY] = sy;
513 fMat[kMScaleY] = SK_Scalar1;
514 fMat[kMTransY] = SkScalarMul(-sy, px);
515
516 fMat[kMPersp0] = fMat[kMPersp1] = 0;
517 fMat[kMPersp2] = kMatrix22Elem;
518
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000519 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000520}
521
522void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
523 fMat[kMScaleX] = SK_Scalar1;
524 fMat[kMSkewX] = sx;
525 fMat[kMTransX] = 0;
526
527 fMat[kMSkewY] = sy;
528 fMat[kMScaleY] = SK_Scalar1;
529 fMat[kMTransY] = 0;
530
531 fMat[kMPersp0] = fMat[kMPersp1] = 0;
532 fMat[kMPersp2] = kMatrix22Elem;
533
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000534 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000535}
536
537bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
538 SkMatrix m;
539 m.setSkew(sx, sy, px, py);
540 return this->preConcat(m);
541}
542
543bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
544 SkMatrix m;
545 m.setSkew(sx, sy);
546 return this->preConcat(m);
547}
548
549bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
550 SkMatrix m;
551 m.setSkew(sx, sy, px, py);
552 return this->postConcat(m);
553}
554
555bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
556 SkMatrix m;
557 m.setSkew(sx, sy);
558 return this->postConcat(m);
559}
560
561///////////////////////////////////////////////////////////////////////////////
562
563bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
564 ScaleToFit align)
565{
566 if (src.isEmpty()) {
567 this->reset();
568 return false;
569 }
570
571 if (dst.isEmpty()) {
reed@android.com4516f472009-06-29 16:25:36 +0000572 sk_bzero(fMat, 8 * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000573 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
574 } else {
575 SkScalar tx, sx = SkScalarDiv(dst.width(), src.width());
576 SkScalar ty, sy = SkScalarDiv(dst.height(), src.height());
577 bool xLarger = false;
578
579 if (align != kFill_ScaleToFit) {
580 if (sx > sy) {
581 xLarger = true;
582 sx = sy;
583 } else {
584 sy = sx;
585 }
586 }
587
588 tx = dst.fLeft - SkScalarMul(src.fLeft, sx);
589 ty = dst.fTop - SkScalarMul(src.fTop, sy);
590 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
591 SkScalar diff;
592
593 if (xLarger) {
594 diff = dst.width() - SkScalarMul(src.width(), sy);
595 } else {
596 diff = dst.height() - SkScalarMul(src.height(), sy);
597 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000598
reed@android.com8a1c16f2008-12-17 15:59:43 +0000599 if (align == kCenter_ScaleToFit) {
600 diff = SkScalarHalf(diff);
601 }
602
603 if (xLarger) {
604 tx += diff;
605 } else {
606 ty += diff;
607 }
608 }
609
610 fMat[kMScaleX] = sx;
611 fMat[kMScaleY] = sy;
612 fMat[kMTransX] = tx;
613 fMat[kMTransY] = ty;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000614 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +0000615 fMat[kMPersp0] = fMat[kMPersp1] = 0;
616
reed@google.com97cd69c2012-10-12 14:35:48 +0000617 unsigned mask = kRectStaysRect_Mask;
618 if (sx != SK_Scalar1 || sy != SK_Scalar1) {
619 mask |= kScale_Mask;
620 }
621 if (tx || ty) {
622 mask |= kTranslate_Mask;
623 }
624 this->setTypeMask(mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000625 }
626 // shared cleanup
627 fMat[kMPersp2] = kMatrix22Elem;
628 return true;
629}
630
631///////////////////////////////////////////////////////////////////////////////
632
633#ifdef SK_SCALAR_IS_FLOAT
634 static inline int fixmuladdmul(float a, float b, float c, float d,
635 float* result) {
reed@android.comab7ac022009-09-18 13:38:43 +0000636 *result = SkDoubleToFloat((double)a * b + (double)c * d);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000637 return true;
638 }
639
640 static inline bool rowcol3(const float row[], const float col[],
641 float* result) {
642 *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
643 return true;
644 }
645
646 static inline int negifaddoverflows(float& result, float a, float b) {
647 result = a + b;
648 return 0;
649 }
650#else
651 static inline bool fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d,
652 SkFixed* result) {
653 Sk64 tmp1, tmp2;
654 tmp1.setMul(a, b);
655 tmp2.setMul(c, d);
656 tmp1.add(tmp2);
657 if (tmp1.isFixed()) {
658 *result = tmp1.getFixed();
659 return true;
660 }
661 return false;
662 }
663
reed@android.com8a1c16f2008-12-17 15:59:43 +0000664 static inline SkFixed fracmuladdmul(SkFixed a, SkFract b, SkFixed c,
665 SkFract d) {
666 Sk64 tmp1, tmp2;
667 tmp1.setMul(a, b);
668 tmp2.setMul(c, d);
669 tmp1.add(tmp2);
670 return tmp1.getFract();
671 }
672
673 static inline bool rowcol3(const SkFixed row[], const SkFixed col[],
674 SkFixed* result) {
675 Sk64 tmp1, tmp2;
676
677 tmp1.setMul(row[0], col[0]); // N * fixed
678 tmp2.setMul(row[1], col[3]); // N * fixed
679 tmp1.add(tmp2);
680
681 tmp2.setMul(row[2], col[6]); // N * fract
682 tmp2.roundRight(14); // make it fixed
683 tmp1.add(tmp2);
684
685 if (tmp1.isFixed()) {
686 *result = tmp1.getFixed();
687 return true;
688 }
689 return false;
690 }
691
692 static inline int negifaddoverflows(SkFixed& result, SkFixed a, SkFixed b) {
693 SkFixed c = a + b;
694 result = c;
695 return (c ^ a) & (c ^ b);
696 }
697#endif
698
699static void normalize_perspective(SkScalar mat[9]) {
700 if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > kMatrix22Elem) {
701 for (int i = 0; i < 9; i++)
702 mat[i] = SkScalarHalf(mat[i]);
703 }
704}
705
706bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000707 TypeMask aType = a.getPerspectiveTypeMaskOnly();
708 TypeMask bType = b.getPerspectiveTypeMaskOnly();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000709
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000710 if (a.isTriviallyIdentity()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000711 *this = b;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000712 } else if (b.isTriviallyIdentity()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713 *this = a;
714 } else {
715 SkMatrix tmp;
716
717 if ((aType | bType) & kPerspective_Mask) {
718 if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) {
719 return false;
720 }
721 if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) {
722 return false;
723 }
724 if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) {
725 return false;
726 }
727
728 if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) {
729 return false;
730 }
731 if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) {
732 return false;
733 }
734 if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) {
735 return false;
736 }
737
738 if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) {
739 return false;
740 }
741 if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) {
742 return false;
743 }
744 if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) {
745 return false;
746 }
747
748 normalize_perspective(tmp.fMat);
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000749 tmp.setTypeMask(kUnknown_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000750 } else { // not perspective
751 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
752 a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
753 return false;
754 }
755 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX],
756 a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) {
757 return false;
758 }
759 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX],
760 a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) {
761 return false;
762 }
763 if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX],
764 a.fMat[kMTransX]) < 0) {
765 return false;
766 }
767
768 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX],
769 a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) {
770 return false;
771 }
772 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX],
773 a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) {
774 return false;
775 }
776 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX],
777 a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) {
778 return false;
779 }
780 if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY],
781 a.fMat[kMTransY]) < 0) {
782 return false;
783 }
784
785 tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
786 tmp.fMat[kMPersp2] = kMatrix22Elem;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000787 //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
788 //SkASSERT(!(tmp.getType() & kPerspective_Mask));
789 tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000790 }
791 *this = tmp;
792 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000793 return true;
794}
795
796bool SkMatrix::preConcat(const SkMatrix& mat) {
797 // check for identity first, so we don't do a needless copy of ourselves
798 // to ourselves inside setConcat()
799 return mat.isIdentity() || this->setConcat(*this, mat);
800}
801
802bool SkMatrix::postConcat(const SkMatrix& mat) {
803 // check for identity first, so we don't do a needless copy of ourselves
804 // to ourselves inside setConcat()
805 return mat.isIdentity() || this->setConcat(mat, *this);
806}
807
808///////////////////////////////////////////////////////////////////////////////
809
reed@android.com0b9e2db2009-09-16 17:00:17 +0000810/* Matrix inversion is very expensive, but also the place where keeping
811 precision may be most important (here and matrix concat). Hence to avoid
812 bitmap blitting artifacts when walking the inverse, we use doubles for
813 the intermediate math, even though we know that is more expensive.
814 The fixed counter part is us using Sk64 for temp calculations.
815 */
816
reed@android.com8a1c16f2008-12-17 15:59:43 +0000817#ifdef SK_SCALAR_IS_FLOAT
reed@android.com0b9e2db2009-09-16 17:00:17 +0000818 typedef double SkDetScalar;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000819 #define SkPerspMul(a, b) SkScalarMul(a, b)
reed@android.com0b9e2db2009-09-16 17:00:17 +0000820 #define SkScalarMulShift(a, b, s) SkDoubleToFloat((a) * (b))
821 static double sk_inv_determinant(const float mat[9], int isPerspective,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000822 int* /* (only used in Fixed case) */) {
823 double det;
824
825 if (isPerspective) {
826 det = mat[SkMatrix::kMScaleX] * ((double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp2] - (double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp1]) +
827 mat[SkMatrix::kMSkewX] * ((double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp0] - (double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp2]) +
828 mat[SkMatrix::kMTransX] * ((double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp1] - (double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp0]);
829 } else {
830 det = (double)mat[SkMatrix::kMScaleX] * mat[SkMatrix::kMScaleY] - (double)mat[SkMatrix::kMSkewX] * mat[SkMatrix::kMSkewY];
831 }
832
senorblanco@chromium.org0e21ec02010-07-20 15:20:01 +0000833 // Since the determinant is on the order of the cube of the matrix members,
834 // compare to the cube of the default nearly-zero constant (although an
835 // estimate of the condition number would be better if it wasn't so expensive).
836 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000837 return 0;
838 }
reed@android.com0b9e2db2009-09-16 17:00:17 +0000839 return 1.0 / det;
840 }
reed@android.com0b9e2db2009-09-16 17:00:17 +0000841 // we declar a,b,c,d to all be doubles, because we want to perform
842 // double-precision muls and subtract, even though the original values are
843 // from the matrix, which are floats.
844 static float inline mul_diff_scale(double a, double b, double c, double d,
845 double scale) {
846 return SkDoubleToFloat((a * b - c * d) * scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000847 }
848#else
reed@android.com0b9e2db2009-09-16 17:00:17 +0000849 typedef SkFixed SkDetScalar;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000850 #define SkPerspMul(a, b) SkFractMul(a, b)
851 #define SkScalarMulShift(a, b, s) SkMulShift(a, b, s)
852 static void set_muladdmul(Sk64* dst, int32_t a, int32_t b, int32_t c,
853 int32_t d) {
854 Sk64 tmp;
855 dst->setMul(a, b);
856 tmp.setMul(c, d);
857 dst->add(tmp);
858 }
859
860 static SkFixed sk_inv_determinant(const SkFixed mat[9], int isPerspective,
861 int* shift) {
862 Sk64 tmp1, tmp2;
863
864 if (isPerspective) {
865 tmp1.setMul(mat[SkMatrix::kMScaleX], fracmuladdmul(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], -mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1]));
866 tmp2.setMul(mat[SkMatrix::kMSkewX], fracmuladdmul(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], -mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2]));
867 tmp1.add(tmp2);
868 tmp2.setMul(mat[SkMatrix::kMTransX], fracmuladdmul(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], -mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]));
869 tmp1.add(tmp2);
870 } else {
871 tmp1.setMul(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY]);
872 tmp2.setMul(mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
873 tmp1.sub(tmp2);
874 }
875
876 int s = tmp1.getClzAbs();
877 *shift = s;
878
879 SkFixed denom;
880 if (s <= 32) {
881 denom = tmp1.getShiftRight(33 - s);
882 } else {
883 denom = (int32_t)tmp1.fLo << (s - 33);
884 }
885
886 if (denom == 0) {
887 return 0;
888 }
889 /** This could perhaps be a special fractdiv function, since both of its
890 arguments are known to have bit 31 clear and bit 30 set (when they
891 are made positive), thus eliminating the need for calling clz()
892 */
893 return SkFractDiv(SK_Fract1, denom);
894 }
895#endif
896
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000897void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
898 affine[kAScaleX] = SK_Scalar1;
899 affine[kASkewY] = 0;
900 affine[kASkewX] = 0;
901 affine[kAScaleY] = SK_Scalar1;
902 affine[kATransX] = 0;
903 affine[kATransY] = 0;
904}
905
906bool SkMatrix::asAffine(SkScalar affine[6]) const {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000907 if (this->hasPerspective()) {
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000908 return false;
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000909 }
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000910 if (affine) {
911 affine[kAScaleX] = this->fMat[kMScaleX];
912 affine[kASkewY] = this->fMat[kMSkewY];
913 affine[kASkewX] = this->fMat[kMSkewX];
914 affine[kAScaleY] = this->fMat[kMScaleY];
915 affine[kATransX] = this->fMat[kMTransX];
916 affine[kATransY] = this->fMat[kMTransY];
917 }
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000918 return true;
919}
920
bsalomon@google.com683c3c72012-10-31 16:50:38 +0000921bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
922 SkASSERT(!this->isIdentity());
reed@google.com2fb96cc2013-01-04 17:02:33 +0000923
924 TypeMask mask = this->getType();
925
926 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
reed@google.come40591d2013-01-30 15:47:42 +0000927 bool invertible = true;
reed@google.com2fb96cc2013-01-04 17:02:33 +0000928 if (inv) {
929 if (mask & kScale_Mask) {
930 SkScalar invX = fMat[kMScaleX];
931 SkScalar invY = fMat[kMScaleY];
932 if (0 == invX || 0 == invY) {
933 return false;
934 }
935 invX = SkScalarInvert(invX);
936 invY = SkScalarInvert(invY);
937
938 // Must be careful when writing to inv, since it may be the
939 // same memory as this.
940
941 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
942 inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
943
944 inv->fMat[kMScaleX] = invX;
945 inv->fMat[kMScaleY] = invY;
946 inv->fMat[kMPersp2] = kMatrix22Elem;
947 inv->fMat[kMTransX] = -SkScalarMul(fMat[kMTransX], invX);
948 inv->fMat[kMTransY] = -SkScalarMul(fMat[kMTransY], invY);
949
950 inv->setTypeMask(mask | kRectStaysRect_Mask);
951 } else {
952 // translate only
953 inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
954 }
reed@google.come40591d2013-01-30 15:47:42 +0000955 } else { // inv is NULL, just check if we're invertible
956 if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
957 invertible = false;
958 }
reed@google.com2fb96cc2013-01-04 17:02:33 +0000959 }
reed@google.come40591d2013-01-30 15:47:42 +0000960 return invertible;
reed@google.com2fb96cc2013-01-04 17:02:33 +0000961 }
reed@google.com4a1362a2013-01-04 18:52:16 +0000962
reed@google.com2fb96cc2013-01-04 17:02:33 +0000963 int isPersp = mask & kPerspective_Mask;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000964 int shift;
reed@android.com0b9e2db2009-09-16 17:00:17 +0000965 SkDetScalar scale = sk_inv_determinant(fMat, isPersp, &shift);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000966
967 if (scale == 0) { // underflow
968 return false;
969 }
970
971 if (inv) {
972 SkMatrix tmp;
bsalomon@google.comcf9b7502011-08-01 13:26:01 +0000973 if (inv == this) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000974 inv = &tmp;
bsalomon@google.comcf9b7502011-08-01 13:26:01 +0000975 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000976
977 if (isPersp) {
978 shift = 61 - shift;
979 inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift);
980 inv->fMat[kMSkewX] = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX], fMat[kMPersp2]), scale, shift);
981 inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift);
982
983 inv->fMat[kMSkewY] = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY], fMat[kMPersp2]), scale, shift);
984 inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX], fMat[kMPersp0]), scale, shift);
985 inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift);
986
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000987 inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000988 inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift);
989 inv->fMat[kMPersp2] = SkScalarMulShift(SkScalarMul(fMat[kMScaleX], fMat[kMScaleY]) - SkScalarMul(fMat[kMSkewX], fMat[kMSkewY]), scale, shift);
990#ifdef SK_SCALAR_IS_FIXED
991 if (SkAbs32(inv->fMat[kMPersp2]) > SK_Fixed1) {
992 Sk64 tmp;
993
994 tmp.set(SK_Fract1);
995 tmp.shiftLeft(16);
996 tmp.div(inv->fMat[kMPersp2], Sk64::kRound_DivOption);
997
998 SkFract scale = tmp.get32();
999
1000 for (int i = 0; i < 9; i++) {
1001 inv->fMat[i] = SkFractMul(inv->fMat[i], scale);
1002 }
1003 }
1004 inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
1005#endif
1006 } else { // not perspective
1007#ifdef SK_SCALAR_IS_FIXED
1008 Sk64 tx, ty;
1009 int clzNumer;
1010
1011 // check the 2x2 for overflow
1012 {
1013 int32_t value = SkAbs32(fMat[kMScaleY]);
1014 value |= SkAbs32(fMat[kMSkewX]);
1015 value |= SkAbs32(fMat[kMScaleX]);
1016 value |= SkAbs32(fMat[kMSkewY]);
1017 clzNumer = SkCLZ(value);
1018 if (shift - clzNumer > 31)
1019 return false; // overflow
1020 }
1021
1022 set_muladdmul(&tx, fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX]);
1023 set_muladdmul(&ty, fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY]);
1024 // check tx,ty for overflow
1025 clzNumer = SkCLZ(SkAbs32(tx.fHi) | SkAbs32(ty.fHi));
1026 if (shift - clzNumer > 14) {
1027 return false; // overflow
1028 }
1029
1030 int fixedShift = 61 - shift;
1031 int sk64shift = 44 - shift + clzNumer;
1032
1033 inv->fMat[kMScaleX] = SkMulShift(fMat[kMScaleY], scale, fixedShift);
1034 inv->fMat[kMSkewX] = SkMulShift(-fMat[kMSkewX], scale, fixedShift);
1035 inv->fMat[kMTransX] = SkMulShift(tx.getShiftRight(33 - clzNumer), scale, sk64shift);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001036
reed@android.com8a1c16f2008-12-17 15:59:43 +00001037 inv->fMat[kMSkewY] = SkMulShift(-fMat[kMSkewY], scale, fixedShift);
1038 inv->fMat[kMScaleY] = SkMulShift(fMat[kMScaleX], scale, fixedShift);
1039 inv->fMat[kMTransY] = SkMulShift(ty.getShiftRight(33 - clzNumer), scale, sk64shift);
1040#else
reed@android.com0b9e2db2009-09-16 17:00:17 +00001041 inv->fMat[kMScaleX] = SkDoubleToFloat(fMat[kMScaleY] * scale);
1042 inv->fMat[kMSkewX] = SkDoubleToFloat(-fMat[kMSkewX] * scale);
1043 inv->fMat[kMTransX] = mul_diff_scale(fMat[kMSkewX], fMat[kMTransY],
1044 fMat[kMScaleY], fMat[kMTransX], scale);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001045
reed@android.com0b9e2db2009-09-16 17:00:17 +00001046 inv->fMat[kMSkewY] = SkDoubleToFloat(-fMat[kMSkewY] * scale);
1047 inv->fMat[kMScaleY] = SkDoubleToFloat(fMat[kMScaleX] * scale);
1048 inv->fMat[kMTransY] = mul_diff_scale(fMat[kMSkewY], fMat[kMTransX],
1049 fMat[kMScaleX], fMat[kMTransY], scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001050#endif
1051 inv->fMat[kMPersp0] = 0;
1052 inv->fMat[kMPersp1] = 0;
1053 inv->fMat[kMPersp2] = kMatrix22Elem;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001054
reed@android.com8a1c16f2008-12-17 15:59:43 +00001055 }
1056
junov@chromium.org6fc56992012-07-12 14:01:32 +00001057 inv->setTypeMask(fTypeMask);
1058
reed@android.com8a1c16f2008-12-17 15:59:43 +00001059 if (inv == &tmp) {
1060 *(SkMatrix*)this = tmp;
1061 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001062 }
1063 return true;
1064}
1065
1066///////////////////////////////////////////////////////////////////////////////
1067
1068void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
1069 const SkPoint src[], int count) {
1070 SkASSERT(m.getType() == 0);
1071
1072 if (dst != src && count > 0)
1073 memcpy(dst, src, count * sizeof(SkPoint));
1074}
1075
1076void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
1077 const SkPoint src[], int count) {
1078 SkASSERT(m.getType() == kTranslate_Mask);
1079
1080 if (count > 0) {
1081 SkScalar tx = m.fMat[kMTransX];
1082 SkScalar ty = m.fMat[kMTransY];
1083 do {
1084 dst->fY = src->fY + ty;
1085 dst->fX = src->fX + tx;
1086 src += 1;
1087 dst += 1;
1088 } while (--count);
1089 }
1090}
1091
1092void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
1093 const SkPoint src[], int count) {
1094 SkASSERT(m.getType() == kScale_Mask);
1095
1096 if (count > 0) {
1097 SkScalar mx = m.fMat[kMScaleX];
1098 SkScalar my = m.fMat[kMScaleY];
1099 do {
1100 dst->fY = SkScalarMul(src->fY, my);
1101 dst->fX = SkScalarMul(src->fX, mx);
1102 src += 1;
1103 dst += 1;
1104 } while (--count);
1105 }
1106}
1107
1108void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
1109 const SkPoint src[], int count) {
1110 SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
1111
1112 if (count > 0) {
1113 SkScalar mx = m.fMat[kMScaleX];
1114 SkScalar my = m.fMat[kMScaleY];
1115 SkScalar tx = m.fMat[kMTransX];
1116 SkScalar ty = m.fMat[kMTransY];
1117 do {
1118 dst->fY = SkScalarMulAdd(src->fY, my, ty);
1119 dst->fX = SkScalarMulAdd(src->fX, mx, tx);
1120 src += 1;
1121 dst += 1;
1122 } while (--count);
1123 }
1124}
1125
1126void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
1127 const SkPoint src[], int count) {
1128 SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
1129
1130 if (count > 0) {
1131 SkScalar mx = m.fMat[kMScaleX];
1132 SkScalar my = m.fMat[kMScaleY];
1133 SkScalar kx = m.fMat[kMSkewX];
1134 SkScalar ky = m.fMat[kMSkewY];
1135 do {
1136 SkScalar sy = src->fY;
1137 SkScalar sx = src->fX;
1138 src += 1;
1139 dst->fY = SkScalarMul(sx, ky) + SkScalarMul(sy, my);
1140 dst->fX = SkScalarMul(sx, mx) + SkScalarMul(sy, kx);
1141 dst += 1;
1142 } while (--count);
1143 }
1144}
1145
1146void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
1147 const SkPoint src[], int count) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001148 SkASSERT(!m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001149
1150 if (count > 0) {
1151 SkScalar mx = m.fMat[kMScaleX];
1152 SkScalar my = m.fMat[kMScaleY];
1153 SkScalar kx = m.fMat[kMSkewX];
1154 SkScalar ky = m.fMat[kMSkewY];
1155 SkScalar tx = m.fMat[kMTransX];
1156 SkScalar ty = m.fMat[kMTransY];
1157 do {
1158 SkScalar sy = src->fY;
1159 SkScalar sx = src->fX;
1160 src += 1;
1161 dst->fY = SkScalarMul(sx, ky) + SkScalarMulAdd(sy, my, ty);
1162 dst->fX = SkScalarMul(sx, mx) + SkScalarMulAdd(sy, kx, tx);
1163 dst += 1;
1164 } while (--count);
1165 }
1166}
1167
1168void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
1169 const SkPoint src[], int count) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001170 SkASSERT(m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001171
1172#ifdef SK_SCALAR_IS_FIXED
1173 SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]);
1174#endif
1175
1176 if (count > 0) {
1177 do {
1178 SkScalar sy = src->fY;
1179 SkScalar sx = src->fX;
1180 src += 1;
1181
1182 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1183 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1184 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1185 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1186#ifdef SK_SCALAR_IS_FIXED
1187 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
1188 SkFractMul(sy, m.fMat[kMPersp1]) + persp2;
1189#else
1190 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1191 SkScalarMulAdd(sy, m.fMat[kMPersp1], m.fMat[kMPersp2]);
1192#endif
1193 if (z) {
1194 z = SkScalarFastInvert(z);
1195 }
1196
1197 dst->fY = SkScalarMul(y, z);
1198 dst->fX = SkScalarMul(x, z);
1199 dst += 1;
1200 } while (--count);
1201 }
1202}
1203
1204const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
1205 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
1206 SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts,
1207 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
1208 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
1209 // repeat the persp proc 8 times
1210 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1211 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1212 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1213 SkMatrix::Persp_pts, SkMatrix::Persp_pts
1214};
1215
1216void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
1217 SkASSERT((dst && src && count > 0) || count == 0);
1218 // no partial overlap
1219 SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= count);
1220
1221 this->getMapPtsProc()(*this, dst, src, count);
1222}
1223
1224///////////////////////////////////////////////////////////////////////////////
1225
1226void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001227 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001228 SkPoint origin;
1229
1230 MapXYProc proc = this->getMapXYProc();
1231 proc(*this, 0, 0, &origin);
1232
1233 for (int i = count - 1; i >= 0; --i) {
1234 SkPoint tmp;
1235
1236 proc(*this, src[i].fX, src[i].fY, &tmp);
1237 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1238 }
1239 } else {
1240 SkMatrix tmp = *this;
1241
1242 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1243 tmp.clearTypeMask(kTranslate_Mask);
1244 tmp.mapPoints(dst, src, count);
1245 }
1246}
1247
1248bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
1249 SkASSERT(dst && &src);
1250
1251 if (this->rectStaysRect()) {
1252 this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
1253 dst->sort();
1254 return true;
1255 } else {
1256 SkPoint quad[4];
1257
1258 src.toQuad(quad);
1259 this->mapPoints(quad, quad, 4);
1260 dst->set(quad, 4);
1261 return false;
1262 }
1263}
1264
1265SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1266 SkVector vec[2];
1267
1268 vec[0].set(radius, 0);
1269 vec[1].set(0, radius);
1270 this->mapVectors(vec, 2);
1271
1272 SkScalar d0 = vec[0].length();
1273 SkScalar d1 = vec[1].length();
1274
1275 return SkScalarMean(d0, d1);
1276}
1277
1278///////////////////////////////////////////////////////////////////////////////
1279
1280void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1281 SkPoint* pt) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001282 SkASSERT(m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001283
1284 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1285 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1286 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1287 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1288#ifdef SK_SCALAR_IS_FIXED
1289 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
1290 SkFractMul(sy, m.fMat[kMPersp1]) +
1291 SkFractToFixed(m.fMat[kMPersp2]);
1292#else
1293 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1294 SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1295#endif
1296 if (z) {
1297 z = SkScalarFastInvert(z);
1298 }
1299 pt->fX = SkScalarMul(x, z);
1300 pt->fY = SkScalarMul(y, z);
1301}
1302
1303#ifdef SK_SCALAR_IS_FIXED
1304static SkFixed fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d) {
1305 Sk64 tmp, tmp1;
1306
1307 tmp.setMul(a, b);
1308 tmp1.setMul(c, d);
1309 return tmp.addGetFixed(tmp1);
1310// tmp.add(tmp1);
1311// return tmp.getFixed();
1312}
1313#endif
1314
1315void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1316 SkPoint* pt) {
1317 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001318
reed@android.com8a1c16f2008-12-17 15:59:43 +00001319#ifdef SK_SCALAR_IS_FIXED
1320 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) +
1321 m.fMat[kMTransX];
1322 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) +
1323 m.fMat[kMTransY];
1324#else
1325 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1326 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1327 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1328 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1329#endif
1330}
1331
1332void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1333 SkPoint* pt) {
1334 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1335 SkASSERT(0 == m.fMat[kMTransX]);
1336 SkASSERT(0 == m.fMat[kMTransY]);
1337
1338#ifdef SK_SCALAR_IS_FIXED
1339 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]);
1340 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]);
1341#else
1342 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1343 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1344 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1345 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1346#endif
1347}
1348
1349void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1350 SkPoint* pt) {
1351 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1352 == kScale_Mask);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001353
reed@android.com8a1c16f2008-12-17 15:59:43 +00001354 pt->fX = SkScalarMulAdd(sx, m.fMat[kMScaleX], m.fMat[kMTransX]);
1355 pt->fY = SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1356}
1357
1358void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1359 SkPoint* pt) {
1360 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1361 == kScale_Mask);
1362 SkASSERT(0 == m.fMat[kMTransX]);
1363 SkASSERT(0 == m.fMat[kMTransY]);
1364
1365 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]);
1366 pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]);
1367}
1368
1369void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1370 SkPoint* pt) {
1371 SkASSERT(m.getType() == kTranslate_Mask);
1372
1373 pt->fX = sx + m.fMat[kMTransX];
1374 pt->fY = sy + m.fMat[kMTransY];
1375}
1376
1377void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1378 SkPoint* pt) {
1379 SkASSERT(0 == m.getType());
1380
1381 pt->fX = sx;
1382 pt->fY = sy;
1383}
1384
1385const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1386 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1387 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1388 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1389 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1390 // repeat the persp proc 8 times
1391 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1392 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1393 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1394 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1395};
1396
1397///////////////////////////////////////////////////////////////////////////////
1398
1399// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1400#ifdef SK_SCALAR_IS_FIXED
1401 typedef SkFract SkPerspElemType;
1402 #define PerspNearlyZero(x) (SkAbs32(x) < (SK_Fract1 >> 26))
1403#else
1404 typedef float SkPerspElemType;
1405 #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1406#endif
1407
1408bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
1409 if (PerspNearlyZero(fMat[kMPersp0])) {
1410 if (stepX || stepY) {
1411 if (PerspNearlyZero(fMat[kMPersp1]) &&
1412 PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem)) {
1413 if (stepX) {
1414 *stepX = SkScalarToFixed(fMat[kMScaleX]);
1415 }
1416 if (stepY) {
1417 *stepY = SkScalarToFixed(fMat[kMSkewY]);
1418 }
1419 } else {
1420#ifdef SK_SCALAR_IS_FIXED
1421 SkFixed z = SkFractMul(y, fMat[kMPersp1]) +
1422 SkFractToFixed(fMat[kMPersp2]);
1423#else
1424 float z = y * fMat[kMPersp1] + fMat[kMPersp2];
1425#endif
1426 if (stepX) {
1427 *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z));
1428 }
1429 if (stepY) {
1430 *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z));
1431 }
1432 }
1433 }
1434 return true;
1435 }
1436 return false;
1437}
1438
1439///////////////////////////////////////////////////////////////////////////////
1440
1441#include "SkPerspIter.h"
1442
1443SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
1444 : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
1445 SkPoint pt;
1446
1447 SkMatrix::Persp_xy(m, x0, y0, &pt);
1448 fX = SkScalarToFixed(pt.fX);
1449 fY = SkScalarToFixed(pt.fY);
1450}
1451
1452int SkPerspIter::next() {
1453 int n = fCount;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001454
reed@android.com8a1c16f2008-12-17 15:59:43 +00001455 if (0 == n) {
1456 return 0;
1457 }
1458 SkPoint pt;
1459 SkFixed x = fX;
1460 SkFixed y = fY;
1461 SkFixed dx, dy;
1462
1463 if (n >= kCount) {
1464 n = kCount;
1465 fSX += SkIntToScalar(kCount);
1466 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1467 fX = SkScalarToFixed(pt.fX);
1468 fY = SkScalarToFixed(pt.fY);
1469 dx = (fX - x) >> kShift;
1470 dy = (fY - y) >> kShift;
1471 } else {
1472 fSX += SkIntToScalar(n);
1473 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1474 fX = SkScalarToFixed(pt.fX);
1475 fY = SkScalarToFixed(pt.fY);
1476 dx = (fX - x) / n;
1477 dy = (fY - y) / n;
1478 }
1479
1480 SkFixed* p = fStorage;
1481 for (int i = 0; i < n; i++) {
1482 *p++ = x; x += dx;
1483 *p++ = y; y += dy;
1484 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001485
reed@android.com8a1c16f2008-12-17 15:59:43 +00001486 fCount -= n;
1487 return n;
1488}
1489
1490///////////////////////////////////////////////////////////////////////////////
1491
1492#ifdef SK_SCALAR_IS_FIXED
1493
1494static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1495 SkFixed x = SK_Fixed1, y = SK_Fixed1;
1496 SkPoint pt1, pt2;
1497 Sk64 w1, w2;
1498
1499 if (count > 1) {
1500 pt1.fX = poly[1].fX - poly[0].fX;
1501 pt1.fY = poly[1].fY - poly[0].fY;
1502 y = SkPoint::Length(pt1.fX, pt1.fY);
1503 if (y == 0) {
1504 return false;
1505 }
1506 switch (count) {
1507 case 2:
1508 break;
1509 case 3:
1510 pt2.fX = poly[0].fY - poly[2].fY;
1511 pt2.fY = poly[2].fX - poly[0].fX;
1512 goto CALC_X;
1513 default:
1514 pt2.fX = poly[0].fY - poly[3].fY;
1515 pt2.fY = poly[3].fX - poly[0].fX;
1516 CALC_X:
1517 w1.setMul(pt1.fX, pt2.fX);
1518 w2.setMul(pt1.fY, pt2.fY);
1519 w1.add(w2);
1520 w1.div(y, Sk64::kRound_DivOption);
1521 if (!w1.is32()) {
1522 return false;
1523 }
1524 x = w1.get32();
1525 break;
1526 }
1527 }
1528 pt->set(x, y);
1529 return true;
1530}
1531
1532bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1533 const SkPoint& scalePt) {
1534 // need to check if SkFixedDiv overflows...
1535
1536 const SkFixed scale = scalePt.fY;
1537 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1538 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[0].fX - srcPt[1].fX, scale);
1539 dst->fMat[kMPersp0] = 0;
1540 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale);
1541 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1542 dst->fMat[kMPersp1] = 0;
1543 dst->fMat[kMTransX] = srcPt[0].fX;
1544 dst->fMat[kMTransY] = srcPt[0].fY;
1545 dst->fMat[kMPersp2] = SK_Fract1;
1546 dst->setTypeMask(kUnknown_Mask);
1547 return true;
1548}
1549
1550bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1551 const SkPoint& scale) {
1552 // really, need to check if SkFixedDiv overflow'd
1553
1554 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[2].fX - srcPt[0].fX, scale.fX);
1555 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[2].fY - srcPt[0].fY, scale.fX);
1556 dst->fMat[kMPersp0] = 0;
1557 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale.fY);
1558 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale.fY);
1559 dst->fMat[kMPersp1] = 0;
1560 dst->fMat[kMTransX] = srcPt[0].fX;
1561 dst->fMat[kMTransY] = srcPt[0].fY;
1562 dst->fMat[kMPersp2] = SK_Fract1;
1563 dst->setTypeMask(kUnknown_Mask);
1564 return true;
1565}
1566
1567bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1568 const SkPoint& scale) {
1569 SkFract a1, a2;
1570 SkFixed x0, y0, x1, y1, x2, y2;
1571
1572 x0 = srcPt[2].fX - srcPt[0].fX;
1573 y0 = srcPt[2].fY - srcPt[0].fY;
1574 x1 = srcPt[2].fX - srcPt[1].fX;
1575 y1 = srcPt[2].fY - srcPt[1].fY;
1576 x2 = srcPt[2].fX - srcPt[3].fX;
1577 y2 = srcPt[2].fY - srcPt[3].fY;
1578
1579 /* check if abs(x2) > abs(y2) */
1580 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1581 SkFixed denom = SkMulDiv(x1, y2, x2) - y1;
1582 if (0 == denom) {
1583 return false;
1584 }
1585 a1 = SkFractDiv(SkMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1586 } else {
1587 SkFixed denom = x1 - SkMulDiv(y1, x2, y2);
1588 if (0 == denom) {
1589 return false;
1590 }
1591 a1 = SkFractDiv(x0 - x1 - SkMulDiv(y0 - y1, x2, y2), denom);
1592 }
1593
1594 /* check if abs(x1) > abs(y1) */
1595 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1596 SkFixed denom = y2 - SkMulDiv(x2, y1, x1);
1597 if (0 == denom) {
1598 return false;
1599 }
1600 a2 = SkFractDiv(y0 - y2 - SkMulDiv(x0 - x2, y1, x1), denom);
1601 } else {
1602 SkFixed denom = SkMulDiv(y2, x1, y1) - x2;
1603 if (0 == denom) {
1604 return false;
1605 }
1606 a2 = SkFractDiv(SkMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1607 }
1608
1609 // need to check if SkFixedDiv overflows...
1610 dst->fMat[kMScaleX] = SkFixedDiv(SkFractMul(a2, srcPt[3].fX) +
1611 srcPt[3].fX - srcPt[0].fX, scale.fX);
1612 dst->fMat[kMSkewY] = SkFixedDiv(SkFractMul(a2, srcPt[3].fY) +
1613 srcPt[3].fY - srcPt[0].fY, scale.fX);
1614 dst->fMat[kMPersp0] = SkFixedDiv(a2, scale.fX);
1615 dst->fMat[kMSkewX] = SkFixedDiv(SkFractMul(a1, srcPt[1].fX) +
1616 srcPt[1].fX - srcPt[0].fX, scale.fY);
1617 dst->fMat[kMScaleY] = SkFixedDiv(SkFractMul(a1, srcPt[1].fY) +
1618 srcPt[1].fY - srcPt[0].fY, scale.fY);
1619 dst->fMat[kMPersp1] = SkFixedDiv(a1, scale.fY);
1620 dst->fMat[kMTransX] = srcPt[0].fX;
1621 dst->fMat[kMTransY] = srcPt[0].fY;
1622 dst->fMat[kMPersp2] = SK_Fract1;
1623 dst->setTypeMask(kUnknown_Mask);
1624 return true;
1625}
1626
1627#else /* Scalar is float */
1628
1629static inline bool checkForZero(float x) {
1630 return x*x == 0;
1631}
1632
1633static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1634 float x = 1, y = 1;
1635 SkPoint pt1, pt2;
1636
1637 if (count > 1) {
1638 pt1.fX = poly[1].fX - poly[0].fX;
1639 pt1.fY = poly[1].fY - poly[0].fY;
1640 y = SkPoint::Length(pt1.fX, pt1.fY);
1641 if (checkForZero(y)) {
1642 return false;
1643 }
1644 switch (count) {
1645 case 2:
1646 break;
1647 case 3:
1648 pt2.fX = poly[0].fY - poly[2].fY;
1649 pt2.fY = poly[2].fX - poly[0].fX;
1650 goto CALC_X;
1651 default:
1652 pt2.fX = poly[0].fY - poly[3].fY;
1653 pt2.fY = poly[3].fX - poly[0].fX;
1654 CALC_X:
1655 x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) +
1656 SkScalarMul(pt1.fY, pt2.fY), y);
1657 break;
1658 }
1659 }
1660 pt->set(x, y);
1661 return true;
1662}
1663
1664bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1665 const SkPoint& scale) {
1666 float invScale = 1 / scale.fY;
1667
1668 dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1669 dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
1670 dst->fMat[kMPersp0] = 0;
1671 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1672 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1673 dst->fMat[kMPersp1] = 0;
1674 dst->fMat[kMTransX] = srcPt[0].fX;
1675 dst->fMat[kMTransY] = srcPt[0].fY;
1676 dst->fMat[kMPersp2] = 1;
1677 dst->setTypeMask(kUnknown_Mask);
1678 return true;
1679}
1680
1681bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1682 const SkPoint& scale) {
1683 float invScale = 1 / scale.fX;
1684 dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
1685 dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
1686 dst->fMat[kMPersp0] = 0;
1687
1688 invScale = 1 / scale.fY;
1689 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1690 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1691 dst->fMat[kMPersp1] = 0;
1692
1693 dst->fMat[kMTransX] = srcPt[0].fX;
1694 dst->fMat[kMTransY] = srcPt[0].fY;
1695 dst->fMat[kMPersp2] = 1;
1696 dst->setTypeMask(kUnknown_Mask);
1697 return true;
1698}
1699
1700bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1701 const SkPoint& scale) {
1702 float a1, a2;
1703 float x0, y0, x1, y1, x2, y2;
1704
1705 x0 = srcPt[2].fX - srcPt[0].fX;
1706 y0 = srcPt[2].fY - srcPt[0].fY;
1707 x1 = srcPt[2].fX - srcPt[1].fX;
1708 y1 = srcPt[2].fY - srcPt[1].fY;
1709 x2 = srcPt[2].fX - srcPt[3].fX;
1710 y2 = srcPt[2].fY - srcPt[3].fY;
1711
1712 /* check if abs(x2) > abs(y2) */
1713 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1714 float denom = SkScalarMulDiv(x1, y2, x2) - y1;
1715 if (checkForZero(denom)) {
1716 return false;
1717 }
1718 a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1719 } else {
1720 float denom = x1 - SkScalarMulDiv(y1, x2, y2);
1721 if (checkForZero(denom)) {
1722 return false;
1723 }
1724 a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), denom);
1725 }
1726
1727 /* check if abs(x1) > abs(y1) */
1728 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1729 float denom = y2 - SkScalarMulDiv(x2, y1, x1);
1730 if (checkForZero(denom)) {
1731 return false;
1732 }
1733 a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), denom);
1734 } else {
1735 float denom = SkScalarMulDiv(y2, x1, y1) - x2;
1736 if (checkForZero(denom)) {
1737 return false;
1738 }
1739 a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1740 }
1741
1742 float invScale = 1 / scale.fX;
1743 dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) +
1744 srcPt[3].fX - srcPt[0].fX, invScale);
1745 dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) +
1746 srcPt[3].fY - srcPt[0].fY, invScale);
1747 dst->fMat[kMPersp0] = SkScalarMul(a2, invScale);
1748 invScale = 1 / scale.fY;
1749 dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) +
1750 srcPt[1].fX - srcPt[0].fX, invScale);
1751 dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) +
1752 srcPt[1].fY - srcPt[0].fY, invScale);
1753 dst->fMat[kMPersp1] = SkScalarMul(a1, invScale);
1754 dst->fMat[kMTransX] = srcPt[0].fX;
1755 dst->fMat[kMTransY] = srcPt[0].fY;
1756 dst->fMat[kMPersp2] = 1;
1757 dst->setTypeMask(kUnknown_Mask);
1758 return true;
1759}
1760
1761#endif
1762
1763typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
1764
1765/* Taken from Rob Johnson's original sample code in QuickDraw GX
1766*/
1767bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
1768 int count) {
1769 if ((unsigned)count > 4) {
1770 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1771 return false;
1772 }
1773
1774 if (0 == count) {
1775 this->reset();
1776 return true;
1777 }
1778 if (1 == count) {
1779 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1780 return true;
1781 }
1782
1783 SkPoint scale;
1784 if (!poly_to_point(&scale, src, count) ||
1785 SkScalarNearlyZero(scale.fX) ||
1786 SkScalarNearlyZero(scale.fY)) {
1787 return false;
1788 }
1789
1790 static const PolyMapProc gPolyMapProcs[] = {
1791 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1792 };
1793 PolyMapProc proc = gPolyMapProcs[count - 2];
1794
1795 SkMatrix tempMap, result;
1796 tempMap.setTypeMask(kUnknown_Mask);
1797
1798 if (!proc(src, &tempMap, scale)) {
1799 return false;
1800 }
1801 if (!tempMap.invert(&result)) {
1802 return false;
1803 }
1804 if (!proc(dst, &tempMap, scale)) {
1805 return false;
1806 }
1807 if (!result.setConcat(tempMap, result)) {
1808 return false;
1809 }
1810 *this = result;
1811 return true;
1812}
1813
1814///////////////////////////////////////////////////////////////////////////////
1815
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001816SkScalar SkMatrix::getMaxStretch() const {
1817 TypeMask mask = this->getType();
1818
bsalomon@google.com38396322011-09-09 19:32:04 +00001819 if (this->hasPerspective()) {
1820 return -SK_Scalar1;
1821 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001822 if (this->isIdentity()) {
bsalomon@google.com38396322011-09-09 19:32:04 +00001823 return SK_Scalar1;
1824 }
1825 if (!(mask & kAffine_Mask)) {
1826 return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
1827 SkScalarAbs(fMat[kMScaleY]));
1828 }
1829 // ignore the translation part of the matrix, just look at 2x2 portion.
1830 // compute singular values, take largest abs value.
1831 // [a b; b c] = A^T*A
1832 SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
1833 SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
1834 SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
1835 SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
1836 SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) +
1837 SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
1838 // eigenvalues of A^T*A are the squared singular values of A.
1839 // characteristic equation is det((A^T*A) - l*I) = 0
1840 // l^2 - (a + c)l + (ac-b^2)
1841 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1842 // and roots are guaraunteed to be pos and real).
1843 SkScalar largerRoot;
1844 SkScalar bSqd = SkScalarMul(b,b);
1845 // if upper left 2x2 is orthogonal save some math
jvanverth@google.comc490f802013-03-04 13:56:38 +00001846 if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
bsalomon@google.com38396322011-09-09 19:32:04 +00001847 largerRoot = SkMaxScalar(a, c);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001848 } else {
bsalomon@google.com38396322011-09-09 19:32:04 +00001849 SkScalar aminusc = a - c;
1850 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1851 SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
1852 largerRoot = apluscdiv2 + x;
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001853 }
bsalomon@google.com38396322011-09-09 19:32:04 +00001854 return SkScalarSqrt(largerRoot);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001855}
1856
1857const SkMatrix& SkMatrix::I() {
1858 static SkMatrix gIdentity;
1859 static bool gOnce;
1860 if (!gOnce) {
1861 gIdentity.reset();
1862 gOnce = true;
1863 }
1864 return gIdentity;
tomhudson@google.com1f902872012-06-01 13:15:47 +00001865}
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001866
1867const SkMatrix& SkMatrix::InvalidMatrix() {
1868 static SkMatrix gInvalid;
1869 static bool gOnce;
1870 if (!gOnce) {
1871 gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1872 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1873 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
1874 gInvalid.getType(); // force the type to be computed
1875 gOnce = true;
1876 }
1877 return gInvalid;
1878}
1879
1880///////////////////////////////////////////////////////////////////////////////
1881
djsollen@google.com94e75ee2012-06-08 18:30:46 +00001882uint32_t SkMatrix::writeToMemory(void* buffer) const {
reed@android.com0ad336f2009-06-29 16:02:20 +00001883 // TODO write less for simple matrices
1884 if (buffer) {
1885 memcpy(buffer, fMat, 9 * sizeof(SkScalar));
1886 }
1887 return 9 * sizeof(SkScalar);
1888}
1889
djsollen@google.com94e75ee2012-06-08 18:30:46 +00001890uint32_t SkMatrix::readFromMemory(const void* buffer) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001891 if (buffer) {
1892 memcpy(fMat, buffer, 9 * sizeof(SkScalar));
1893 this->setTypeMask(kUnknown_Mask);
1894 }
reed@android.com0ad336f2009-06-29 16:02:20 +00001895 return 9 * sizeof(SkScalar);
1896}
1897
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001898#ifdef SK_DEVELOPER
reed@android.com8a1c16f2008-12-17 15:59:43 +00001899void SkMatrix::dump() const {
1900 SkString str;
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001901 this->toString(&str);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001902 SkDebugf("%s\n", str.c_str());
1903}
1904
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001905void SkMatrix::toString(SkString* str) const {
1906 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 +00001907#ifdef SK_SCALAR_IS_FLOAT
1908 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1909 fMat[6], fMat[7], fMat[8]);
1910#else
1911 SkFixedToFloat(fMat[0]), SkFixedToFloat(fMat[1]), SkFixedToFloat(fMat[2]),
1912 SkFixedToFloat(fMat[3]), SkFixedToFloat(fMat[4]), SkFixedToFloat(fMat[5]),
1913 SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
1914#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001915}
robertphillips@google.com76f9e932013-01-15 20:17:47 +00001916#endif
reed@google.comad514302013-01-02 20:19:45 +00001917
1918///////////////////////////////////////////////////////////////////////////////
1919
1920#include "SkMatrixUtils.h"
1921
reed@google.comae573582013-01-03 15:22:40 +00001922bool SkTreatAsSprite(const SkMatrix& mat, int width, int height,
reed@google.comad514302013-01-02 20:19:45 +00001923 unsigned subpixelBits) {
reed@google.comae573582013-01-03 15:22:40 +00001924 // quick reject on affine or perspective
reed@google.comad514302013-01-02 20:19:45 +00001925 if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
1926 return false;
1927 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001928
reed@google.comad514302013-01-02 20:19:45 +00001929 // quick success check
1930 if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1931 return true;
1932 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001933
reed@google.comad514302013-01-02 20:19:45 +00001934 // mapRect supports negative scales, so we eliminate those first
1935 if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1936 return false;
1937 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001938
reed@google.comad514302013-01-02 20:19:45 +00001939 SkRect dst;
reed@google.comae573582013-01-03 15:22:40 +00001940 SkIRect isrc = { 0, 0, width, height };
skia.committer@gmail.comd9f65e32013-01-04 12:07:46 +00001941
reed@google.comad514302013-01-02 20:19:45 +00001942 {
reed@google.comae573582013-01-03 15:22:40 +00001943 SkRect src;
1944 src.set(isrc);
1945 mat.mapRect(&dst, src);
reed@google.comad514302013-01-02 20:19:45 +00001946 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001947
reed@google.comae573582013-01-03 15:22:40 +00001948 // just apply the translate to isrc
1949 isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1950 SkScalarRoundToInt(mat.getTranslateY()));
1951
reed@google.comad514302013-01-02 20:19:45 +00001952 if (subpixelBits) {
1953 isrc.fLeft <<= subpixelBits;
1954 isrc.fTop <<= subpixelBits;
1955 isrc.fRight <<= subpixelBits;
1956 isrc.fBottom <<= subpixelBits;
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001957
reed@google.comad514302013-01-02 20:19:45 +00001958 const float scale = 1 << subpixelBits;
1959 dst.fLeft *= scale;
1960 dst.fTop *= scale;
1961 dst.fRight *= scale;
1962 dst.fBottom *= scale;
1963 }
skia.committer@gmail.com422188f2013-01-03 02:01:32 +00001964
reed@google.comae573582013-01-03 15:22:40 +00001965 SkIRect idst;
reed@google.comad514302013-01-02 20:19:45 +00001966 dst.round(&idst);
1967 return isrc == idst;
1968}
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00001969
1970bool SkDecomposeUpper2x2(const SkMatrix& matrix,
skia.committer@gmail.com5c561cb2013-07-25 07:01:00 +00001971 SkScalar* rotation0,
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00001972 SkScalar* xScale, SkScalar* yScale,
1973 SkScalar* rotation1) {
1974
1975 // borrowed from Jim Blinn's article "Consider the Lowly 2x2 Matrix"
1976 // Note: he uses row vectors, so we have to do some swapping of terms
1977 SkScalar A = matrix[SkMatrix::kMScaleX];
1978 SkScalar B = matrix[SkMatrix::kMSkewX];
1979 SkScalar C = matrix[SkMatrix::kMSkewY];
1980 SkScalar D = matrix[SkMatrix::kMScaleY];
1981
1982 SkScalar E = SK_ScalarHalf*(A + D);
1983 SkScalar F = SK_ScalarHalf*(A - D);
1984 SkScalar G = SK_ScalarHalf*(C + B);
1985 SkScalar H = SK_ScalarHalf*(C - B);
1986
1987 SkScalar sqrt0 = SkScalarSqrt(E*E + H*H);
1988 SkScalar sqrt1 = SkScalarSqrt(F*F + G*G);
1989
1990 SkScalar xs, ys, r0, r1;
1991
1992 // can't have zero yScale, must be degenerate
1993 if (SkScalarNearlyEqual(sqrt0, sqrt1)) {
1994 return false;
1995 }
1996 xs = sqrt0 + sqrt1;
1997 ys = sqrt0 - sqrt1;
1998
1999 // uniformly scaled rotation
2000 if (SkScalarNearlyZero(F) && SkScalarNearlyZero(G)) {
2001 SkASSERT(!SkScalarNearlyZero(E));
2002 r0 = SkScalarATan2(H, E);
2003 r1 = 0;
2004 // uniformly scaled reflection
2005 } else if (SkScalarNearlyZero(E) && SkScalarNearlyZero(H)) {
2006 SkASSERT(!SkScalarNearlyZero(F));
2007 r0 = -SkScalarATan2(G, F);
2008 r1 = 0;
2009 } else {
2010 SkASSERT(!SkScalarNearlyZero(E));
2011 SkASSERT(!SkScalarNearlyZero(F));
2012
2013 SkScalar arctan0 = SkScalarATan2(H, E);
2014 SkScalar arctan1 = SkScalarATan2(G, F);
2015 r0 = SK_ScalarHalf*(arctan0 - arctan1);
2016 r1 = SK_ScalarHalf*(arctan0 + arctan1);
skia.committer@gmail.com5c561cb2013-07-25 07:01:00 +00002017
commit-bot@chromium.org08284e42013-07-24 18:08:08 +00002018 // simplify the results
2019 const SkScalar kHalfPI = SK_ScalarHalf*SK_ScalarPI;
2020 if (SkScalarNearlyEqual(SkScalarAbs(r0), kHalfPI)) {
2021 SkScalar tmp = xs;
2022 xs = ys;
2023 ys = tmp;
2024
2025 r1 += r0;
2026 r0 = 0;
2027 } else if (SkScalarNearlyEqual(SkScalarAbs(r1), kHalfPI)) {
2028 SkScalar tmp = xs;
2029 xs = ys;
2030 ys = tmp;
2031
2032 r0 += r1;
2033 r1 = 0;
2034 }
2035 }
2036
2037 if (NULL != xScale) {
2038 *xScale = xs;
2039 }
2040 if (NULL != yScale) {
2041 *yScale = ys;
2042 }
2043 if (NULL != rotation0) {
2044 *rotation0 = r0;
2045 }
2046 if (NULL != rotation1) {
2047 *rotation1 = r1;
2048 }
2049
2050 return true;
2051}