blob: 51450faee7769a5b328d98cb68472631571267af [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
2/*
3 * Copyright 2006 The Android Open Source Project
4 *
5 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
7 */
8
reed@android.com8a1c16f2008-12-17 15:59:43 +00009
10#include "SkMatrix.h"
11#include "Sk64.h"
12#include "SkFloatBits.h"
reed@android.com31745582009-07-08 14:46:11 +000013#include "SkScalarCompare.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014#include "SkString.h"
15
16#ifdef SK_SCALAR_IS_FLOAT
17 #define kMatrix22Elem SK_Scalar1
reed@android.comab7ac022009-09-18 13:38:43 +000018
19 static inline float SkDoubleToFloat(double x) {
20 return static_cast<float>(x);
21 }
reed@android.com8a1c16f2008-12-17 15:59:43 +000022#else
23 #define kMatrix22Elem SK_Fract1
24#endif
25
26/* [scale-x skew-x trans-x] [X] [X']
27 [skew-y scale-y trans-y] * [Y] = [Y']
28 [persp-0 persp-1 persp-2] [1] [1 ]
29*/
30
31void SkMatrix::reset() {
32 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000033 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +000034 fMat[kMTransX] = fMat[kMTransY] =
35 fMat[kMPersp0] = fMat[kMPersp1] = 0;
36 fMat[kMPersp2] = kMatrix22Elem;
37
38 this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
39}
40
reed@android.com8a1c16f2008-12-17 15:59:43 +000041// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
42enum {
43 kTranslate_Shift,
44 kScale_Shift,
45 kAffine_Shift,
46 kPerspective_Shift,
47 kRectStaysRect_Shift
48};
49
50#ifdef SK_SCALAR_IS_FLOAT
51 static const int32_t kScalar1Int = 0x3f800000;
52 static const int32_t kPersp1Int = 0x3f800000;
53#else
54 #define scalarAsInt(x) (x)
55 static const int32_t kScalar1Int = (1 << 16);
56 static const int32_t kPersp1Int = (1 << 30);
57#endif
58
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000059uint8_t SkMatrix::computePerspectiveTypeMask() const {
junov@chromium.org6fc56992012-07-12 14:01:32 +000060#ifdef SK_SCALAR_SLOW_COMPARES
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000061 if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
62 SkScalarAs2sCompliment(fMat[kMPersp1]) |
63 (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
junov@chromium.org6fc56992012-07-12 14:01:32 +000064 return SkToU8(kORableMasks);
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000065 }
junov@chromium.org6fc56992012-07-12 14:01:32 +000066#else
67 // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
68 // is a win, but replacing those below is not. We don't yet understand
69 // that result.
70 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 ||
71 fMat[kMPersp2] != kMatrix22Elem) {
rmistry@google.comfbfcd562012-08-23 18:09:54 +000072 // If this is a perspective transform, we return true for all other
bsalomon@google.com19263b12012-07-13 13:36:38 +000073 // transform flags - this does not disable any optimizations, respects
rmistry@google.comfbfcd562012-08-23 18:09:54 +000074 // the rule that the type mask must be conservative, and speeds up
junov@chromium.org6fc56992012-07-12 14:01:32 +000075 // type mask computation.
76 return SkToU8(kORableMasks);
77 }
78#endif
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000079
junov@chromium.org6fc56992012-07-12 14:01:32 +000080 return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
tomhudson@google.comdd5f7442011-08-30 15:13:55 +000081}
82
reed@android.com8a1c16f2008-12-17 15:59:43 +000083uint8_t SkMatrix::computeTypeMask() const {
84 unsigned mask = 0;
85
tomhudson@google.comac385252011-06-06 15:18:28 +000086#ifdef SK_SCALAR_SLOW_COMPARES
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
88 SkScalarAs2sCompliment(fMat[kMPersp1]) |
89 (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
junov@chromium.org6fc56992012-07-12 14:01:32 +000090 return SkToU8(kORableMasks);
reed@android.com8a1c16f2008-12-17 15:59:43 +000091 }
tomhudson@google.comac385252011-06-06 15:18:28 +000092
reed@android.com8a1c16f2008-12-17 15:59:43 +000093 if (SkScalarAs2sCompliment(fMat[kMTransX]) |
94 SkScalarAs2sCompliment(fMat[kMTransY])) {
95 mask |= kTranslate_Mask;
96 }
tomhudson@google.comac385252011-06-06 15:18:28 +000097#else
tomhudson@google.comac385252011-06-06 15:18:28 +000098 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 ||
tomhudson@google.com521ed7c2011-06-06 17:21:44 +000099 fMat[kMPersp2] != kMatrix22Elem) {
junov@chromium.org6fc56992012-07-12 14:01:32 +0000100 // Once it is determined that that this is a perspective transform,
101 // all other flags are moot as far as optimizations are concerned.
102 return SkToU8(kORableMasks);
tomhudson@google.comac385252011-06-06 15:18:28 +0000103 }
104
105 if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
106 mask |= kTranslate_Mask;
107 }
108#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109
110 int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
111 int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
112 int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
113 int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
tomhudson@google.comac385252011-06-06 15:18:28 +0000114
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 if (m01 | m10) {
junov@chromium.org6fc56992012-07-12 14:01:32 +0000116 // The skew components may be scale-inducing, unless we are dealing
117 // with a pure rotation. Testing for a pure rotation is expensive,
118 // so we opt for being conservative by always setting the scale bit.
119 // along with affine.
120 // By doing this, we are also ensuring that matrices have the same
121 // type masks as their inverses.
122 mask |= kAffine_Mask | kScale_Mask;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000123
junov@chromium.org6fc56992012-07-12 14:01:32 +0000124 // For rectStaysRect, in the affine case, we only need check that
125 // the primary diagonal is all zeros and that the secondary diagonal
126 // is all non-zero.
tomhudson@google.comac385252011-06-06 15:18:28 +0000127
reed@android.com8a1c16f2008-12-17 15:59:43 +0000128 // map non-zero to 1
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 m01 = m01 != 0;
130 m10 = m10 != 0;
tomhudson@google.comac385252011-06-06 15:18:28 +0000131
junov@chromium.org6fc56992012-07-12 14:01:32 +0000132 int dp0 = 0 == (m00 | m11) ; // true if both are 0
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 int ds1 = m01 & m10; // true if both are 1
tomhudson@google.comac385252011-06-06 15:18:28 +0000134
junov@chromium.org6fc56992012-07-12 14:01:32 +0000135 mask |= (dp0 & ds1) << kRectStaysRect_Shift;
136 } else {
137 // Only test for scale explicitly if not affine, since affine sets the
138 // scale bit.
139 if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) {
140 mask |= kScale_Mask;
141 }
142
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000143 // Not affine, therefore we already know secondary diagonal is
junov@chromium.org6fc56992012-07-12 14:01:32 +0000144 // all zeros, so we just need to check that primary diagonal is
145 // all non-zero.
146
147 // map non-zero to 1
148 m00 = m00 != 0;
149 m11 = m11 != 0;
150
151 // record if the (p)rimary diagonal is all non-zero
152 mask |= (m00 & m11) << kRectStaysRect_Shift;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153 }
154
155 return SkToU8(mask);
156}
157
158///////////////////////////////////////////////////////////////////////////////
159
reed@google.com3fb51872011-06-01 15:11:22 +0000160#ifdef SK_SCALAR_IS_FLOAT
161
162bool operator==(const SkMatrix& a, const SkMatrix& b) {
163 const SkScalar* SK_RESTRICT ma = a.fMat;
164 const SkScalar* SK_RESTRICT mb = b.fMat;
165
166 return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
167 ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
168 ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
169}
170
171#endif
172
173///////////////////////////////////////////////////////////////////////////////
174
reed@android.com8a1c16f2008-12-17 15:59:43 +0000175void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
reed@android.com31745582009-07-08 14:46:11 +0000176 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 fMat[kMTransX] = dx;
178 fMat[kMTransY] = dy;
179
180 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000181 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +0000182 fMat[kMPersp0] = fMat[kMPersp1] = 0;
183 fMat[kMPersp2] = kMatrix22Elem;
184
185 this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
186 } else {
187 this->reset();
188 }
189}
190
191bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000192 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 SkMatrix m;
194 m.setTranslate(dx, dy);
195 return this->preConcat(m);
196 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000197
reed@android.com31745582009-07-08 14:46:11 +0000198 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) +
200 SkScalarMul(fMat[kMSkewX], dy);
201 fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
202 SkScalarMul(fMat[kMScaleY], dy);
203
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000204 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 }
206 return true;
207}
208
209bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000210 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000211 SkMatrix m;
212 m.setTranslate(dx, dy);
213 return this->postConcat(m);
214 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000215
reed@android.com31745582009-07-08 14:46:11 +0000216 if (SkScalarToCompareType(dx) || SkScalarToCompareType(dy)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000217 fMat[kMTransX] += dx;
218 fMat[kMTransY] += dy;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000219 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 }
221 return true;
222}
223
224///////////////////////////////////////////////////////////////////////////////
225
226void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
reed@google.comf244f902011-09-06 21:02:36 +0000227 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
228 this->reset();
229 } else {
230 fMat[kMScaleX] = sx;
231 fMat[kMScaleY] = sy;
232 fMat[kMTransX] = px - SkScalarMul(sx, px);
233 fMat[kMTransY] = py - SkScalarMul(sy, py);
234 fMat[kMPersp2] = kMatrix22Elem;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000235
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000236 fMat[kMSkewX] = fMat[kMSkewY] =
reed@google.comf244f902011-09-06 21:02:36 +0000237 fMat[kMPersp0] = fMat[kMPersp1] = 0;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000238
reed@google.comf244f902011-09-06 21:02:36 +0000239 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
240 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000241}
242
243void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000244 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
245 this->reset();
246 } else {
247 fMat[kMScaleX] = sx;
248 fMat[kMScaleY] = sy;
249 fMat[kMPersp2] = kMatrix22Elem;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250
reed@google.comf244f902011-09-06 21:02:36 +0000251 fMat[kMTransX] = fMat[kMTransY] =
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000252 fMat[kMSkewX] = fMat[kMSkewY] =
reed@google.comf244f902011-09-06 21:02:36 +0000253 fMat[kMPersp0] = fMat[kMPersp1] = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000254
reed@google.comf244f902011-09-06 21:02:36 +0000255 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
256 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000257}
258
bsalomon@google.com5c638652011-07-18 19:31:59 +0000259bool SkMatrix::setIDiv(int divx, int divy) {
260 if (!divx || !divy) {
261 return false;
262 }
263 this->setScale(SK_Scalar1 / divx, SK_Scalar1 / divy);
264 return true;
265}
266
reed@android.com8a1c16f2008-12-17 15:59:43 +0000267bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
268 SkMatrix m;
269 m.setScale(sx, sy, px, py);
270 return this->preConcat(m);
271}
272
273bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000274 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
275 return true;
276 }
277
reed@google.com3fb51872011-06-01 15:11:22 +0000278#ifdef SK_SCALAR_IS_FIXED
reed@android.com8a1c16f2008-12-17 15:59:43 +0000279 SkMatrix m;
280 m.setScale(sx, sy);
281 return this->preConcat(m);
reed@google.com3fb51872011-06-01 15:11:22 +0000282#else
283 // the assumption is that these multiplies are very cheap, and that
284 // a full concat and/or just computing the matrix type is more expensive.
285 // Also, the fixed-point case checks for overflow, but the float doesn't,
286 // so we can get away with these blind multiplies.
287
288 fMat[kMScaleX] = SkScalarMul(fMat[kMScaleX], sx);
289 fMat[kMSkewY] = SkScalarMul(fMat[kMSkewY], sx);
290 fMat[kMPersp0] = SkScalarMul(fMat[kMPersp0], sx);
291
292 fMat[kMSkewX] = SkScalarMul(fMat[kMSkewX], sy);
293 fMat[kMScaleY] = SkScalarMul(fMat[kMScaleY], sy);
294 fMat[kMPersp1] = SkScalarMul(fMat[kMPersp1], sy);
295
296 this->orTypeMask(kScale_Mask);
297 return true;
298#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000299}
300
301bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
reed@google.comf244f902011-09-06 21:02:36 +0000302 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
303 return true;
304 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 SkMatrix m;
306 m.setScale(sx, sy, px, py);
307 return this->postConcat(m);
308}
309
310bool SkMatrix::postScale(SkScalar sx, SkScalar sy) {
reed@google.comf244f902011-09-06 21:02:36 +0000311 if (SK_Scalar1 == sx && SK_Scalar1 == sy) {
312 return true;
313 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000314 SkMatrix m;
315 m.setScale(sx, sy);
316 return this->postConcat(m);
317}
318
319#ifdef SK_SCALAR_IS_FIXED
320 static inline SkFixed roundidiv(SkFixed numer, int denom) {
321 int ns = numer >> 31;
322 int ds = denom >> 31;
323 numer = (numer ^ ns) - ns;
324 denom = (denom ^ ds) - ds;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000325
reed@android.com8a1c16f2008-12-17 15:59:43 +0000326 SkFixed answer = (numer + (denom >> 1)) / denom;
327 int as = ns ^ ds;
328 return (answer ^ as) - as;
329 }
330#endif
331
332// this guy perhaps can go away, if we have a fract/high-precision way to
333// scale matrices
334bool SkMatrix::postIDiv(int divx, int divy) {
335 if (divx == 0 || divy == 0) {
336 return false;
337 }
338
339#ifdef SK_SCALAR_IS_FIXED
340 fMat[kMScaleX] = roundidiv(fMat[kMScaleX], divx);
341 fMat[kMSkewX] = roundidiv(fMat[kMSkewX], divx);
342 fMat[kMTransX] = roundidiv(fMat[kMTransX], divx);
343
344 fMat[kMScaleY] = roundidiv(fMat[kMScaleY], divy);
345 fMat[kMSkewY] = roundidiv(fMat[kMSkewY], divy);
346 fMat[kMTransY] = roundidiv(fMat[kMTransY], divy);
347#else
348 const float invX = 1.f / divx;
349 const float invY = 1.f / divy;
350
351 fMat[kMScaleX] *= invX;
352 fMat[kMSkewX] *= invX;
353 fMat[kMTransX] *= invX;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000354
reed@android.com8a1c16f2008-12-17 15:59:43 +0000355 fMat[kMScaleY] *= invY;
356 fMat[kMSkewY] *= invY;
357 fMat[kMTransY] *= invY;
358#endif
359
360 this->setTypeMask(kUnknown_Mask);
361 return true;
362}
363
364////////////////////////////////////////////////////////////////////////////////////
365
366void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
367 SkScalar px, SkScalar py) {
368 const SkScalar oneMinusCosV = SK_Scalar1 - cosV;
369
370 fMat[kMScaleX] = cosV;
371 fMat[kMSkewX] = -sinV;
372 fMat[kMTransX] = SkScalarMul(sinV, py) + SkScalarMul(oneMinusCosV, px);
373
374 fMat[kMSkewY] = sinV;
375 fMat[kMScaleY] = cosV;
376 fMat[kMTransY] = SkScalarMul(-sinV, px) + SkScalarMul(oneMinusCosV, py);
377
378 fMat[kMPersp0] = fMat[kMPersp1] = 0;
379 fMat[kMPersp2] = kMatrix22Elem;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000380
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000381 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000382}
383
384void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
385 fMat[kMScaleX] = cosV;
386 fMat[kMSkewX] = -sinV;
387 fMat[kMTransX] = 0;
388
389 fMat[kMSkewY] = sinV;
390 fMat[kMScaleY] = cosV;
391 fMat[kMTransY] = 0;
392
393 fMat[kMPersp0] = fMat[kMPersp1] = 0;
394 fMat[kMPersp2] = kMatrix22Elem;
395
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000396 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000397}
398
399void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
400 SkScalar sinV, cosV;
401 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
402 this->setSinCos(sinV, cosV, px, py);
403}
404
405void SkMatrix::setRotate(SkScalar degrees) {
406 SkScalar sinV, cosV;
407 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
408 this->setSinCos(sinV, cosV);
409}
410
411bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
412 SkMatrix m;
413 m.setRotate(degrees, px, py);
414 return this->preConcat(m);
415}
416
417bool SkMatrix::preRotate(SkScalar degrees) {
418 SkMatrix m;
419 m.setRotate(degrees);
420 return this->preConcat(m);
421}
422
423bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
424 SkMatrix m;
425 m.setRotate(degrees, px, py);
426 return this->postConcat(m);
427}
428
429bool SkMatrix::postRotate(SkScalar degrees) {
430 SkMatrix m;
431 m.setRotate(degrees);
432 return this->postConcat(m);
433}
434
435////////////////////////////////////////////////////////////////////////////////////
436
437void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
438 fMat[kMScaleX] = SK_Scalar1;
439 fMat[kMSkewX] = sx;
440 fMat[kMTransX] = SkScalarMul(-sx, py);
441
442 fMat[kMSkewY] = sy;
443 fMat[kMScaleY] = SK_Scalar1;
444 fMat[kMTransY] = SkScalarMul(-sy, px);
445
446 fMat[kMPersp0] = fMat[kMPersp1] = 0;
447 fMat[kMPersp2] = kMatrix22Elem;
448
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000449 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000450}
451
452void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
453 fMat[kMScaleX] = SK_Scalar1;
454 fMat[kMSkewX] = sx;
455 fMat[kMTransX] = 0;
456
457 fMat[kMSkewY] = sy;
458 fMat[kMScaleY] = SK_Scalar1;
459 fMat[kMTransY] = 0;
460
461 fMat[kMPersp0] = fMat[kMPersp1] = 0;
462 fMat[kMPersp2] = kMatrix22Elem;
463
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000464 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000465}
466
467bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
468 SkMatrix m;
469 m.setSkew(sx, sy, px, py);
470 return this->preConcat(m);
471}
472
473bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
474 SkMatrix m;
475 m.setSkew(sx, sy);
476 return this->preConcat(m);
477}
478
479bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
480 SkMatrix m;
481 m.setSkew(sx, sy, px, py);
482 return this->postConcat(m);
483}
484
485bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
486 SkMatrix m;
487 m.setSkew(sx, sy);
488 return this->postConcat(m);
489}
490
491///////////////////////////////////////////////////////////////////////////////
492
493bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
494 ScaleToFit align)
495{
496 if (src.isEmpty()) {
497 this->reset();
498 return false;
499 }
500
501 if (dst.isEmpty()) {
reed@android.com4516f472009-06-29 16:25:36 +0000502 sk_bzero(fMat, 8 * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000503 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
504 } else {
505 SkScalar tx, sx = SkScalarDiv(dst.width(), src.width());
506 SkScalar ty, sy = SkScalarDiv(dst.height(), src.height());
507 bool xLarger = false;
508
509 if (align != kFill_ScaleToFit) {
510 if (sx > sy) {
511 xLarger = true;
512 sx = sy;
513 } else {
514 sy = sx;
515 }
516 }
517
518 tx = dst.fLeft - SkScalarMul(src.fLeft, sx);
519 ty = dst.fTop - SkScalarMul(src.fTop, sy);
520 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
521 SkScalar diff;
522
523 if (xLarger) {
524 diff = dst.width() - SkScalarMul(src.width(), sy);
525 } else {
526 diff = dst.height() - SkScalarMul(src.height(), sy);
527 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000528
reed@android.com8a1c16f2008-12-17 15:59:43 +0000529 if (align == kCenter_ScaleToFit) {
530 diff = SkScalarHalf(diff);
531 }
532
533 if (xLarger) {
534 tx += diff;
535 } else {
536 ty += diff;
537 }
538 }
539
540 fMat[kMScaleX] = sx;
541 fMat[kMScaleY] = sy;
542 fMat[kMTransX] = tx;
543 fMat[kMTransY] = ty;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000544 fMat[kMSkewX] = fMat[kMSkewY] =
reed@android.com8a1c16f2008-12-17 15:59:43 +0000545 fMat[kMPersp0] = fMat[kMPersp1] = 0;
546
547 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
548 }
549 // shared cleanup
550 fMat[kMPersp2] = kMatrix22Elem;
551 return true;
552}
553
554///////////////////////////////////////////////////////////////////////////////
555
556#ifdef SK_SCALAR_IS_FLOAT
557 static inline int fixmuladdmul(float a, float b, float c, float d,
558 float* result) {
reed@android.comab7ac022009-09-18 13:38:43 +0000559 *result = SkDoubleToFloat((double)a * b + (double)c * d);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000560 return true;
561 }
562
563 static inline bool rowcol3(const float row[], const float col[],
564 float* result) {
565 *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
566 return true;
567 }
568
569 static inline int negifaddoverflows(float& result, float a, float b) {
570 result = a + b;
571 return 0;
572 }
573#else
574 static inline bool fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d,
575 SkFixed* result) {
576 Sk64 tmp1, tmp2;
577 tmp1.setMul(a, b);
578 tmp2.setMul(c, d);
579 tmp1.add(tmp2);
580 if (tmp1.isFixed()) {
581 *result = tmp1.getFixed();
582 return true;
583 }
584 return false;
585 }
586
reed@android.com8a1c16f2008-12-17 15:59:43 +0000587 static inline SkFixed fracmuladdmul(SkFixed a, SkFract b, SkFixed c,
588 SkFract d) {
589 Sk64 tmp1, tmp2;
590 tmp1.setMul(a, b);
591 tmp2.setMul(c, d);
592 tmp1.add(tmp2);
593 return tmp1.getFract();
594 }
595
596 static inline bool rowcol3(const SkFixed row[], const SkFixed col[],
597 SkFixed* result) {
598 Sk64 tmp1, tmp2;
599
600 tmp1.setMul(row[0], col[0]); // N * fixed
601 tmp2.setMul(row[1], col[3]); // N * fixed
602 tmp1.add(tmp2);
603
604 tmp2.setMul(row[2], col[6]); // N * fract
605 tmp2.roundRight(14); // make it fixed
606 tmp1.add(tmp2);
607
608 if (tmp1.isFixed()) {
609 *result = tmp1.getFixed();
610 return true;
611 }
612 return false;
613 }
614
615 static inline int negifaddoverflows(SkFixed& result, SkFixed a, SkFixed b) {
616 SkFixed c = a + b;
617 result = c;
618 return (c ^ a) & (c ^ b);
619 }
620#endif
621
622static void normalize_perspective(SkScalar mat[9]) {
623 if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > kMatrix22Elem) {
624 for (int i = 0; i < 9; i++)
625 mat[i] = SkScalarHalf(mat[i]);
626 }
627}
628
629bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000630 TypeMask aType = a.getPerspectiveTypeMaskOnly();
631 TypeMask bType = b.getPerspectiveTypeMaskOnly();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000632
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000633 if (a.isTriviallyIdentity()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000634 *this = b;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000635 } else if (b.isTriviallyIdentity()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000636 *this = a;
637 } else {
638 SkMatrix tmp;
639
640 if ((aType | bType) & kPerspective_Mask) {
641 if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) {
642 return false;
643 }
644 if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) {
645 return false;
646 }
647 if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) {
648 return false;
649 }
650
651 if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) {
652 return false;
653 }
654 if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) {
655 return false;
656 }
657 if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) {
658 return false;
659 }
660
661 if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) {
662 return false;
663 }
664 if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) {
665 return false;
666 }
667 if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) {
668 return false;
669 }
670
671 normalize_perspective(tmp.fMat);
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000672 tmp.setTypeMask(kUnknown_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000673 } else { // not perspective
674 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
675 a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
676 return false;
677 }
678 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX],
679 a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) {
680 return false;
681 }
682 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX],
683 a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) {
684 return false;
685 }
686 if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX],
687 a.fMat[kMTransX]) < 0) {
688 return false;
689 }
690
691 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX],
692 a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) {
693 return false;
694 }
695 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX],
696 a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) {
697 return false;
698 }
699 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX],
700 a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) {
701 return false;
702 }
703 if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY],
704 a.fMat[kMTransY]) < 0) {
705 return false;
706 }
707
708 tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
709 tmp.fMat[kMPersp2] = kMatrix22Elem;
tomhudson@google.comdd5f7442011-08-30 15:13:55 +0000710 //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
711 //SkASSERT(!(tmp.getType() & kPerspective_Mask));
712 tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000713 }
714 *this = tmp;
715 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000716 return true;
717}
718
719bool SkMatrix::preConcat(const SkMatrix& mat) {
720 // check for identity first, so we don't do a needless copy of ourselves
721 // to ourselves inside setConcat()
722 return mat.isIdentity() || this->setConcat(*this, mat);
723}
724
725bool SkMatrix::postConcat(const SkMatrix& mat) {
726 // check for identity first, so we don't do a needless copy of ourselves
727 // to ourselves inside setConcat()
728 return mat.isIdentity() || this->setConcat(mat, *this);
729}
730
731///////////////////////////////////////////////////////////////////////////////
732
reed@android.com0b9e2db2009-09-16 17:00:17 +0000733/* Matrix inversion is very expensive, but also the place where keeping
734 precision may be most important (here and matrix concat). Hence to avoid
735 bitmap blitting artifacts when walking the inverse, we use doubles for
736 the intermediate math, even though we know that is more expensive.
737 The fixed counter part is us using Sk64 for temp calculations.
738 */
739
reed@android.com8a1c16f2008-12-17 15:59:43 +0000740#ifdef SK_SCALAR_IS_FLOAT
reed@android.com0b9e2db2009-09-16 17:00:17 +0000741 typedef double SkDetScalar;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000742 #define SkPerspMul(a, b) SkScalarMul(a, b)
reed@android.com0b9e2db2009-09-16 17:00:17 +0000743 #define SkScalarMulShift(a, b, s) SkDoubleToFloat((a) * (b))
744 static double sk_inv_determinant(const float mat[9], int isPerspective,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000745 int* /* (only used in Fixed case) */) {
746 double det;
747
748 if (isPerspective) {
749 det = mat[SkMatrix::kMScaleX] * ((double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp2] - (double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp1]) +
750 mat[SkMatrix::kMSkewX] * ((double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp0] - (double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp2]) +
751 mat[SkMatrix::kMTransX] * ((double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp1] - (double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp0]);
752 } else {
753 det = (double)mat[SkMatrix::kMScaleX] * mat[SkMatrix::kMScaleY] - (double)mat[SkMatrix::kMSkewX] * mat[SkMatrix::kMSkewY];
754 }
755
senorblanco@chromium.org0e21ec02010-07-20 15:20:01 +0000756 // Since the determinant is on the order of the cube of the matrix members,
757 // compare to the cube of the default nearly-zero constant (although an
758 // estimate of the condition number would be better if it wasn't so expensive).
759 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000760 return 0;
761 }
reed@android.com0b9e2db2009-09-16 17:00:17 +0000762 return 1.0 / det;
763 }
reed@android.com0b9e2db2009-09-16 17:00:17 +0000764 // we declar a,b,c,d to all be doubles, because we want to perform
765 // double-precision muls and subtract, even though the original values are
766 // from the matrix, which are floats.
767 static float inline mul_diff_scale(double a, double b, double c, double d,
768 double scale) {
769 return SkDoubleToFloat((a * b - c * d) * scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000770 }
771#else
reed@android.com0b9e2db2009-09-16 17:00:17 +0000772 typedef SkFixed SkDetScalar;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000773 #define SkPerspMul(a, b) SkFractMul(a, b)
774 #define SkScalarMulShift(a, b, s) SkMulShift(a, b, s)
775 static void set_muladdmul(Sk64* dst, int32_t a, int32_t b, int32_t c,
776 int32_t d) {
777 Sk64 tmp;
778 dst->setMul(a, b);
779 tmp.setMul(c, d);
780 dst->add(tmp);
781 }
782
783 static SkFixed sk_inv_determinant(const SkFixed mat[9], int isPerspective,
784 int* shift) {
785 Sk64 tmp1, tmp2;
786
787 if (isPerspective) {
788 tmp1.setMul(mat[SkMatrix::kMScaleX], fracmuladdmul(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], -mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1]));
789 tmp2.setMul(mat[SkMatrix::kMSkewX], fracmuladdmul(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], -mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2]));
790 tmp1.add(tmp2);
791 tmp2.setMul(mat[SkMatrix::kMTransX], fracmuladdmul(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], -mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]));
792 tmp1.add(tmp2);
793 } else {
794 tmp1.setMul(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY]);
795 tmp2.setMul(mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
796 tmp1.sub(tmp2);
797 }
798
799 int s = tmp1.getClzAbs();
800 *shift = s;
801
802 SkFixed denom;
803 if (s <= 32) {
804 denom = tmp1.getShiftRight(33 - s);
805 } else {
806 denom = (int32_t)tmp1.fLo << (s - 33);
807 }
808
809 if (denom == 0) {
810 return 0;
811 }
812 /** This could perhaps be a special fractdiv function, since both of its
813 arguments are known to have bit 31 clear and bit 30 set (when they
814 are made positive), thus eliminating the need for calling clz()
815 */
816 return SkFractDiv(SK_Fract1, denom);
817 }
818#endif
819
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000820void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
821 affine[kAScaleX] = SK_Scalar1;
822 affine[kASkewY] = 0;
823 affine[kASkewX] = 0;
824 affine[kAScaleY] = SK_Scalar1;
825 affine[kATransX] = 0;
826 affine[kATransY] = 0;
827}
828
829bool SkMatrix::asAffine(SkScalar affine[6]) const {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000830 if (this->hasPerspective()) {
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000831 return false;
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000832 }
bungeman@google.com1ddd7c32011-07-13 19:41:55 +0000833 if (affine) {
834 affine[kAScaleX] = this->fMat[kMScaleX];
835 affine[kASkewY] = this->fMat[kMSkewY];
836 affine[kASkewX] = this->fMat[kMSkewX];
837 affine[kAScaleY] = this->fMat[kMScaleY];
838 affine[kATransX] = this->fMat[kMTransX];
839 affine[kATransY] = this->fMat[kMTransY];
840 }
vandebo@chromium.orgddbbd802010-10-26 19:45:06 +0000841 return true;
842}
843
reed@android.com8a1c16f2008-12-17 15:59:43 +0000844bool SkMatrix::invert(SkMatrix* inv) const {
tomhudson@google.com8d430182011-06-06 19:11:19 +0000845 int isPersp = this->hasPerspective();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000846 int shift;
reed@android.com0b9e2db2009-09-16 17:00:17 +0000847 SkDetScalar scale = sk_inv_determinant(fMat, isPersp, &shift);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000848
849 if (scale == 0) { // underflow
850 return false;
851 }
852
853 if (inv) {
854 SkMatrix tmp;
bsalomon@google.comcf9b7502011-08-01 13:26:01 +0000855 if (inv == this) {
reed@android.com8a1c16f2008-12-17 15:59:43 +0000856 inv = &tmp;
bsalomon@google.comcf9b7502011-08-01 13:26:01 +0000857 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000858
859 if (isPersp) {
860 shift = 61 - shift;
861 inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift);
862 inv->fMat[kMSkewX] = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX], fMat[kMPersp2]), scale, shift);
863 inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift);
864
865 inv->fMat[kMSkewY] = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY], fMat[kMPersp2]), scale, shift);
866 inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX], fMat[kMPersp0]), scale, shift);
867 inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift);
868
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000869 inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000870 inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift);
871 inv->fMat[kMPersp2] = SkScalarMulShift(SkScalarMul(fMat[kMScaleX], fMat[kMScaleY]) - SkScalarMul(fMat[kMSkewX], fMat[kMSkewY]), scale, shift);
872#ifdef SK_SCALAR_IS_FIXED
873 if (SkAbs32(inv->fMat[kMPersp2]) > SK_Fixed1) {
874 Sk64 tmp;
875
876 tmp.set(SK_Fract1);
877 tmp.shiftLeft(16);
878 tmp.div(inv->fMat[kMPersp2], Sk64::kRound_DivOption);
879
880 SkFract scale = tmp.get32();
881
882 for (int i = 0; i < 9; i++) {
883 inv->fMat[i] = SkFractMul(inv->fMat[i], scale);
884 }
885 }
886 inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
887#endif
888 } else { // not perspective
889#ifdef SK_SCALAR_IS_FIXED
890 Sk64 tx, ty;
891 int clzNumer;
892
893 // check the 2x2 for overflow
894 {
895 int32_t value = SkAbs32(fMat[kMScaleY]);
896 value |= SkAbs32(fMat[kMSkewX]);
897 value |= SkAbs32(fMat[kMScaleX]);
898 value |= SkAbs32(fMat[kMSkewY]);
899 clzNumer = SkCLZ(value);
900 if (shift - clzNumer > 31)
901 return false; // overflow
902 }
903
904 set_muladdmul(&tx, fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX]);
905 set_muladdmul(&ty, fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY]);
906 // check tx,ty for overflow
907 clzNumer = SkCLZ(SkAbs32(tx.fHi) | SkAbs32(ty.fHi));
908 if (shift - clzNumer > 14) {
909 return false; // overflow
910 }
911
912 int fixedShift = 61 - shift;
913 int sk64shift = 44 - shift + clzNumer;
914
915 inv->fMat[kMScaleX] = SkMulShift(fMat[kMScaleY], scale, fixedShift);
916 inv->fMat[kMSkewX] = SkMulShift(-fMat[kMSkewX], scale, fixedShift);
917 inv->fMat[kMTransX] = SkMulShift(tx.getShiftRight(33 - clzNumer), scale, sk64shift);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000918
reed@android.com8a1c16f2008-12-17 15:59:43 +0000919 inv->fMat[kMSkewY] = SkMulShift(-fMat[kMSkewY], scale, fixedShift);
920 inv->fMat[kMScaleY] = SkMulShift(fMat[kMScaleX], scale, fixedShift);
921 inv->fMat[kMTransY] = SkMulShift(ty.getShiftRight(33 - clzNumer), scale, sk64shift);
922#else
reed@android.com0b9e2db2009-09-16 17:00:17 +0000923 inv->fMat[kMScaleX] = SkDoubleToFloat(fMat[kMScaleY] * scale);
924 inv->fMat[kMSkewX] = SkDoubleToFloat(-fMat[kMSkewX] * scale);
925 inv->fMat[kMTransX] = mul_diff_scale(fMat[kMSkewX], fMat[kMTransY],
926 fMat[kMScaleY], fMat[kMTransX], scale);
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000927
reed@android.com0b9e2db2009-09-16 17:00:17 +0000928 inv->fMat[kMSkewY] = SkDoubleToFloat(-fMat[kMSkewY] * scale);
929 inv->fMat[kMScaleY] = SkDoubleToFloat(fMat[kMScaleX] * scale);
930 inv->fMat[kMTransY] = mul_diff_scale(fMat[kMSkewY], fMat[kMTransX],
931 fMat[kMScaleX], fMat[kMTransY], scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000932#endif
933 inv->fMat[kMPersp0] = 0;
934 inv->fMat[kMPersp1] = 0;
935 inv->fMat[kMPersp2] = kMatrix22Elem;
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000936
reed@android.com8a1c16f2008-12-17 15:59:43 +0000937 }
938
junov@chromium.org6fc56992012-07-12 14:01:32 +0000939 inv->setTypeMask(fTypeMask);
940
reed@android.com8a1c16f2008-12-17 15:59:43 +0000941 if (inv == &tmp) {
942 *(SkMatrix*)this = tmp;
943 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000944 }
945 return true;
946}
947
948///////////////////////////////////////////////////////////////////////////////
949
950void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
951 const SkPoint src[], int count) {
952 SkASSERT(m.getType() == 0);
953
954 if (dst != src && count > 0)
955 memcpy(dst, src, count * sizeof(SkPoint));
956}
957
958void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
959 const SkPoint src[], int count) {
960 SkASSERT(m.getType() == kTranslate_Mask);
961
962 if (count > 0) {
963 SkScalar tx = m.fMat[kMTransX];
964 SkScalar ty = m.fMat[kMTransY];
965 do {
966 dst->fY = src->fY + ty;
967 dst->fX = src->fX + tx;
968 src += 1;
969 dst += 1;
970 } while (--count);
971 }
972}
973
974void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
975 const SkPoint src[], int count) {
976 SkASSERT(m.getType() == kScale_Mask);
977
978 if (count > 0) {
979 SkScalar mx = m.fMat[kMScaleX];
980 SkScalar my = m.fMat[kMScaleY];
981 do {
982 dst->fY = SkScalarMul(src->fY, my);
983 dst->fX = SkScalarMul(src->fX, mx);
984 src += 1;
985 dst += 1;
986 } while (--count);
987 }
988}
989
990void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
991 const SkPoint src[], int count) {
992 SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
993
994 if (count > 0) {
995 SkScalar mx = m.fMat[kMScaleX];
996 SkScalar my = m.fMat[kMScaleY];
997 SkScalar tx = m.fMat[kMTransX];
998 SkScalar ty = m.fMat[kMTransY];
999 do {
1000 dst->fY = SkScalarMulAdd(src->fY, my, ty);
1001 dst->fX = SkScalarMulAdd(src->fX, mx, tx);
1002 src += 1;
1003 dst += 1;
1004 } while (--count);
1005 }
1006}
1007
1008void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
1009 const SkPoint src[], int count) {
1010 SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
1011
1012 if (count > 0) {
1013 SkScalar mx = m.fMat[kMScaleX];
1014 SkScalar my = m.fMat[kMScaleY];
1015 SkScalar kx = m.fMat[kMSkewX];
1016 SkScalar ky = m.fMat[kMSkewY];
1017 do {
1018 SkScalar sy = src->fY;
1019 SkScalar sx = src->fX;
1020 src += 1;
1021 dst->fY = SkScalarMul(sx, ky) + SkScalarMul(sy, my);
1022 dst->fX = SkScalarMul(sx, mx) + SkScalarMul(sy, kx);
1023 dst += 1;
1024 } while (--count);
1025 }
1026}
1027
1028void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
1029 const SkPoint src[], int count) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001030 SkASSERT(!m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001031
1032 if (count > 0) {
1033 SkScalar mx = m.fMat[kMScaleX];
1034 SkScalar my = m.fMat[kMScaleY];
1035 SkScalar kx = m.fMat[kMSkewX];
1036 SkScalar ky = m.fMat[kMSkewY];
1037 SkScalar tx = m.fMat[kMTransX];
1038 SkScalar ty = m.fMat[kMTransY];
1039 do {
1040 SkScalar sy = src->fY;
1041 SkScalar sx = src->fX;
1042 src += 1;
1043 dst->fY = SkScalarMul(sx, ky) + SkScalarMulAdd(sy, my, ty);
1044 dst->fX = SkScalarMul(sx, mx) + SkScalarMulAdd(sy, kx, tx);
1045 dst += 1;
1046 } while (--count);
1047 }
1048}
1049
1050void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
1051 const SkPoint src[], int count) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001052 SkASSERT(m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001053
1054#ifdef SK_SCALAR_IS_FIXED
1055 SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]);
1056#endif
1057
1058 if (count > 0) {
1059 do {
1060 SkScalar sy = src->fY;
1061 SkScalar sx = src->fX;
1062 src += 1;
1063
1064 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1065 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1066 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1067 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1068#ifdef SK_SCALAR_IS_FIXED
1069 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
1070 SkFractMul(sy, m.fMat[kMPersp1]) + persp2;
1071#else
1072 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1073 SkScalarMulAdd(sy, m.fMat[kMPersp1], m.fMat[kMPersp2]);
1074#endif
1075 if (z) {
1076 z = SkScalarFastInvert(z);
1077 }
1078
1079 dst->fY = SkScalarMul(y, z);
1080 dst->fX = SkScalarMul(x, z);
1081 dst += 1;
1082 } while (--count);
1083 }
1084}
1085
1086const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
1087 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
1088 SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts,
1089 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
1090 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
1091 // repeat the persp proc 8 times
1092 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1093 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1094 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1095 SkMatrix::Persp_pts, SkMatrix::Persp_pts
1096};
1097
1098void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
1099 SkASSERT((dst && src && count > 0) || count == 0);
1100 // no partial overlap
1101 SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= count);
1102
1103 this->getMapPtsProc()(*this, dst, src, count);
1104}
1105
1106///////////////////////////////////////////////////////////////////////////////
1107
1108void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001109 if (this->hasPerspective()) {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001110 SkPoint origin;
1111
1112 MapXYProc proc = this->getMapXYProc();
1113 proc(*this, 0, 0, &origin);
1114
1115 for (int i = count - 1; i >= 0; --i) {
1116 SkPoint tmp;
1117
1118 proc(*this, src[i].fX, src[i].fY, &tmp);
1119 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1120 }
1121 } else {
1122 SkMatrix tmp = *this;
1123
1124 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1125 tmp.clearTypeMask(kTranslate_Mask);
1126 tmp.mapPoints(dst, src, count);
1127 }
1128}
1129
1130bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
1131 SkASSERT(dst && &src);
1132
1133 if (this->rectStaysRect()) {
1134 this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
1135 dst->sort();
1136 return true;
1137 } else {
1138 SkPoint quad[4];
1139
1140 src.toQuad(quad);
1141 this->mapPoints(quad, quad, 4);
1142 dst->set(quad, 4);
1143 return false;
1144 }
1145}
1146
1147SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1148 SkVector vec[2];
1149
1150 vec[0].set(radius, 0);
1151 vec[1].set(0, radius);
1152 this->mapVectors(vec, 2);
1153
1154 SkScalar d0 = vec[0].length();
1155 SkScalar d1 = vec[1].length();
1156
1157 return SkScalarMean(d0, d1);
1158}
1159
1160///////////////////////////////////////////////////////////////////////////////
1161
1162void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1163 SkPoint* pt) {
tomhudson@google.com8d430182011-06-06 19:11:19 +00001164 SkASSERT(m.hasPerspective());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001165
1166 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1167 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1168 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1169 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1170#ifdef SK_SCALAR_IS_FIXED
1171 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
1172 SkFractMul(sy, m.fMat[kMPersp1]) +
1173 SkFractToFixed(m.fMat[kMPersp2]);
1174#else
1175 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1176 SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1177#endif
1178 if (z) {
1179 z = SkScalarFastInvert(z);
1180 }
1181 pt->fX = SkScalarMul(x, z);
1182 pt->fY = SkScalarMul(y, z);
1183}
1184
1185#ifdef SK_SCALAR_IS_FIXED
1186static SkFixed fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d) {
1187 Sk64 tmp, tmp1;
1188
1189 tmp.setMul(a, b);
1190 tmp1.setMul(c, d);
1191 return tmp.addGetFixed(tmp1);
1192// tmp.add(tmp1);
1193// return tmp.getFixed();
1194}
1195#endif
1196
1197void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1198 SkPoint* pt) {
1199 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001200
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201#ifdef SK_SCALAR_IS_FIXED
1202 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) +
1203 m.fMat[kMTransX];
1204 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) +
1205 m.fMat[kMTransY];
1206#else
1207 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1208 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1209 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1210 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1211#endif
1212}
1213
1214void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1215 SkPoint* pt) {
1216 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1217 SkASSERT(0 == m.fMat[kMTransX]);
1218 SkASSERT(0 == m.fMat[kMTransY]);
1219
1220#ifdef SK_SCALAR_IS_FIXED
1221 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]);
1222 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]);
1223#else
1224 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1225 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1226 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1227 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1228#endif
1229}
1230
1231void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1232 SkPoint* pt) {
1233 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1234 == kScale_Mask);
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001235
reed@android.com8a1c16f2008-12-17 15:59:43 +00001236 pt->fX = SkScalarMulAdd(sx, m.fMat[kMScaleX], m.fMat[kMTransX]);
1237 pt->fY = SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1238}
1239
1240void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1241 SkPoint* pt) {
1242 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1243 == kScale_Mask);
1244 SkASSERT(0 == m.fMat[kMTransX]);
1245 SkASSERT(0 == m.fMat[kMTransY]);
1246
1247 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]);
1248 pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]);
1249}
1250
1251void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1252 SkPoint* pt) {
1253 SkASSERT(m.getType() == kTranslate_Mask);
1254
1255 pt->fX = sx + m.fMat[kMTransX];
1256 pt->fY = sy + m.fMat[kMTransY];
1257}
1258
1259void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1260 SkPoint* pt) {
1261 SkASSERT(0 == m.getType());
1262
1263 pt->fX = sx;
1264 pt->fY = sy;
1265}
1266
1267const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1268 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1269 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1270 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1271 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1272 // repeat the persp proc 8 times
1273 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1274 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1275 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1276 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1277};
1278
1279///////////////////////////////////////////////////////////////////////////////
1280
1281// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1282#ifdef SK_SCALAR_IS_FIXED
1283 typedef SkFract SkPerspElemType;
1284 #define PerspNearlyZero(x) (SkAbs32(x) < (SK_Fract1 >> 26))
1285#else
1286 typedef float SkPerspElemType;
1287 #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1288#endif
1289
1290bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
1291 if (PerspNearlyZero(fMat[kMPersp0])) {
1292 if (stepX || stepY) {
1293 if (PerspNearlyZero(fMat[kMPersp1]) &&
1294 PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem)) {
1295 if (stepX) {
1296 *stepX = SkScalarToFixed(fMat[kMScaleX]);
1297 }
1298 if (stepY) {
1299 *stepY = SkScalarToFixed(fMat[kMSkewY]);
1300 }
1301 } else {
1302#ifdef SK_SCALAR_IS_FIXED
1303 SkFixed z = SkFractMul(y, fMat[kMPersp1]) +
1304 SkFractToFixed(fMat[kMPersp2]);
1305#else
1306 float z = y * fMat[kMPersp1] + fMat[kMPersp2];
1307#endif
1308 if (stepX) {
1309 *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z));
1310 }
1311 if (stepY) {
1312 *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z));
1313 }
1314 }
1315 }
1316 return true;
1317 }
1318 return false;
1319}
1320
1321///////////////////////////////////////////////////////////////////////////////
1322
1323#include "SkPerspIter.h"
1324
1325SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
1326 : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
1327 SkPoint pt;
1328
1329 SkMatrix::Persp_xy(m, x0, y0, &pt);
1330 fX = SkScalarToFixed(pt.fX);
1331 fY = SkScalarToFixed(pt.fY);
1332}
1333
1334int SkPerspIter::next() {
1335 int n = fCount;
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001336
reed@android.com8a1c16f2008-12-17 15:59:43 +00001337 if (0 == n) {
1338 return 0;
1339 }
1340 SkPoint pt;
1341 SkFixed x = fX;
1342 SkFixed y = fY;
1343 SkFixed dx, dy;
1344
1345 if (n >= kCount) {
1346 n = kCount;
1347 fSX += SkIntToScalar(kCount);
1348 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1349 fX = SkScalarToFixed(pt.fX);
1350 fY = SkScalarToFixed(pt.fY);
1351 dx = (fX - x) >> kShift;
1352 dy = (fY - y) >> kShift;
1353 } else {
1354 fSX += SkIntToScalar(n);
1355 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1356 fX = SkScalarToFixed(pt.fX);
1357 fY = SkScalarToFixed(pt.fY);
1358 dx = (fX - x) / n;
1359 dy = (fY - y) / n;
1360 }
1361
1362 SkFixed* p = fStorage;
1363 for (int i = 0; i < n; i++) {
1364 *p++ = x; x += dx;
1365 *p++ = y; y += dy;
1366 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +00001367
reed@android.com8a1c16f2008-12-17 15:59:43 +00001368 fCount -= n;
1369 return n;
1370}
1371
1372///////////////////////////////////////////////////////////////////////////////
1373
1374#ifdef SK_SCALAR_IS_FIXED
1375
1376static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1377 SkFixed x = SK_Fixed1, y = SK_Fixed1;
1378 SkPoint pt1, pt2;
1379 Sk64 w1, w2;
1380
1381 if (count > 1) {
1382 pt1.fX = poly[1].fX - poly[0].fX;
1383 pt1.fY = poly[1].fY - poly[0].fY;
1384 y = SkPoint::Length(pt1.fX, pt1.fY);
1385 if (y == 0) {
1386 return false;
1387 }
1388 switch (count) {
1389 case 2:
1390 break;
1391 case 3:
1392 pt2.fX = poly[0].fY - poly[2].fY;
1393 pt2.fY = poly[2].fX - poly[0].fX;
1394 goto CALC_X;
1395 default:
1396 pt2.fX = poly[0].fY - poly[3].fY;
1397 pt2.fY = poly[3].fX - poly[0].fX;
1398 CALC_X:
1399 w1.setMul(pt1.fX, pt2.fX);
1400 w2.setMul(pt1.fY, pt2.fY);
1401 w1.add(w2);
1402 w1.div(y, Sk64::kRound_DivOption);
1403 if (!w1.is32()) {
1404 return false;
1405 }
1406 x = w1.get32();
1407 break;
1408 }
1409 }
1410 pt->set(x, y);
1411 return true;
1412}
1413
1414bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1415 const SkPoint& scalePt) {
1416 // need to check if SkFixedDiv overflows...
1417
1418 const SkFixed scale = scalePt.fY;
1419 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1420 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[0].fX - srcPt[1].fX, scale);
1421 dst->fMat[kMPersp0] = 0;
1422 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale);
1423 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1424 dst->fMat[kMPersp1] = 0;
1425 dst->fMat[kMTransX] = srcPt[0].fX;
1426 dst->fMat[kMTransY] = srcPt[0].fY;
1427 dst->fMat[kMPersp2] = SK_Fract1;
1428 dst->setTypeMask(kUnknown_Mask);
1429 return true;
1430}
1431
1432bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1433 const SkPoint& scale) {
1434 // really, need to check if SkFixedDiv overflow'd
1435
1436 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[2].fX - srcPt[0].fX, scale.fX);
1437 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[2].fY - srcPt[0].fY, scale.fX);
1438 dst->fMat[kMPersp0] = 0;
1439 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale.fY);
1440 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale.fY);
1441 dst->fMat[kMPersp1] = 0;
1442 dst->fMat[kMTransX] = srcPt[0].fX;
1443 dst->fMat[kMTransY] = srcPt[0].fY;
1444 dst->fMat[kMPersp2] = SK_Fract1;
1445 dst->setTypeMask(kUnknown_Mask);
1446 return true;
1447}
1448
1449bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1450 const SkPoint& scale) {
1451 SkFract a1, a2;
1452 SkFixed x0, y0, x1, y1, x2, y2;
1453
1454 x0 = srcPt[2].fX - srcPt[0].fX;
1455 y0 = srcPt[2].fY - srcPt[0].fY;
1456 x1 = srcPt[2].fX - srcPt[1].fX;
1457 y1 = srcPt[2].fY - srcPt[1].fY;
1458 x2 = srcPt[2].fX - srcPt[3].fX;
1459 y2 = srcPt[2].fY - srcPt[3].fY;
1460
1461 /* check if abs(x2) > abs(y2) */
1462 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1463 SkFixed denom = SkMulDiv(x1, y2, x2) - y1;
1464 if (0 == denom) {
1465 return false;
1466 }
1467 a1 = SkFractDiv(SkMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1468 } else {
1469 SkFixed denom = x1 - SkMulDiv(y1, x2, y2);
1470 if (0 == denom) {
1471 return false;
1472 }
1473 a1 = SkFractDiv(x0 - x1 - SkMulDiv(y0 - y1, x2, y2), denom);
1474 }
1475
1476 /* check if abs(x1) > abs(y1) */
1477 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1478 SkFixed denom = y2 - SkMulDiv(x2, y1, x1);
1479 if (0 == denom) {
1480 return false;
1481 }
1482 a2 = SkFractDiv(y0 - y2 - SkMulDiv(x0 - x2, y1, x1), denom);
1483 } else {
1484 SkFixed denom = SkMulDiv(y2, x1, y1) - x2;
1485 if (0 == denom) {
1486 return false;
1487 }
1488 a2 = SkFractDiv(SkMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1489 }
1490
1491 // need to check if SkFixedDiv overflows...
1492 dst->fMat[kMScaleX] = SkFixedDiv(SkFractMul(a2, srcPt[3].fX) +
1493 srcPt[3].fX - srcPt[0].fX, scale.fX);
1494 dst->fMat[kMSkewY] = SkFixedDiv(SkFractMul(a2, srcPt[3].fY) +
1495 srcPt[3].fY - srcPt[0].fY, scale.fX);
1496 dst->fMat[kMPersp0] = SkFixedDiv(a2, scale.fX);
1497 dst->fMat[kMSkewX] = SkFixedDiv(SkFractMul(a1, srcPt[1].fX) +
1498 srcPt[1].fX - srcPt[0].fX, scale.fY);
1499 dst->fMat[kMScaleY] = SkFixedDiv(SkFractMul(a1, srcPt[1].fY) +
1500 srcPt[1].fY - srcPt[0].fY, scale.fY);
1501 dst->fMat[kMPersp1] = SkFixedDiv(a1, scale.fY);
1502 dst->fMat[kMTransX] = srcPt[0].fX;
1503 dst->fMat[kMTransY] = srcPt[0].fY;
1504 dst->fMat[kMPersp2] = SK_Fract1;
1505 dst->setTypeMask(kUnknown_Mask);
1506 return true;
1507}
1508
1509#else /* Scalar is float */
1510
1511static inline bool checkForZero(float x) {
1512 return x*x == 0;
1513}
1514
1515static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1516 float x = 1, y = 1;
1517 SkPoint pt1, pt2;
1518
1519 if (count > 1) {
1520 pt1.fX = poly[1].fX - poly[0].fX;
1521 pt1.fY = poly[1].fY - poly[0].fY;
1522 y = SkPoint::Length(pt1.fX, pt1.fY);
1523 if (checkForZero(y)) {
1524 return false;
1525 }
1526 switch (count) {
1527 case 2:
1528 break;
1529 case 3:
1530 pt2.fX = poly[0].fY - poly[2].fY;
1531 pt2.fY = poly[2].fX - poly[0].fX;
1532 goto CALC_X;
1533 default:
1534 pt2.fX = poly[0].fY - poly[3].fY;
1535 pt2.fY = poly[3].fX - poly[0].fX;
1536 CALC_X:
1537 x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) +
1538 SkScalarMul(pt1.fY, pt2.fY), y);
1539 break;
1540 }
1541 }
1542 pt->set(x, y);
1543 return true;
1544}
1545
1546bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1547 const SkPoint& scale) {
1548 float invScale = 1 / scale.fY;
1549
1550 dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1551 dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
1552 dst->fMat[kMPersp0] = 0;
1553 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1554 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1555 dst->fMat[kMPersp1] = 0;
1556 dst->fMat[kMTransX] = srcPt[0].fX;
1557 dst->fMat[kMTransY] = srcPt[0].fY;
1558 dst->fMat[kMPersp2] = 1;
1559 dst->setTypeMask(kUnknown_Mask);
1560 return true;
1561}
1562
1563bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1564 const SkPoint& scale) {
1565 float invScale = 1 / scale.fX;
1566 dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
1567 dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
1568 dst->fMat[kMPersp0] = 0;
1569
1570 invScale = 1 / scale.fY;
1571 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1572 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1573 dst->fMat[kMPersp1] = 0;
1574
1575 dst->fMat[kMTransX] = srcPt[0].fX;
1576 dst->fMat[kMTransY] = srcPt[0].fY;
1577 dst->fMat[kMPersp2] = 1;
1578 dst->setTypeMask(kUnknown_Mask);
1579 return true;
1580}
1581
1582bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1583 const SkPoint& scale) {
1584 float a1, a2;
1585 float x0, y0, x1, y1, x2, y2;
1586
1587 x0 = srcPt[2].fX - srcPt[0].fX;
1588 y0 = srcPt[2].fY - srcPt[0].fY;
1589 x1 = srcPt[2].fX - srcPt[1].fX;
1590 y1 = srcPt[2].fY - srcPt[1].fY;
1591 x2 = srcPt[2].fX - srcPt[3].fX;
1592 y2 = srcPt[2].fY - srcPt[3].fY;
1593
1594 /* check if abs(x2) > abs(y2) */
1595 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1596 float denom = SkScalarMulDiv(x1, y2, x2) - y1;
1597 if (checkForZero(denom)) {
1598 return false;
1599 }
1600 a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1601 } else {
1602 float denom = x1 - SkScalarMulDiv(y1, x2, y2);
1603 if (checkForZero(denom)) {
1604 return false;
1605 }
1606 a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), denom);
1607 }
1608
1609 /* check if abs(x1) > abs(y1) */
1610 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1611 float denom = y2 - SkScalarMulDiv(x2, y1, x1);
1612 if (checkForZero(denom)) {
1613 return false;
1614 }
1615 a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), denom);
1616 } else {
1617 float denom = SkScalarMulDiv(y2, x1, y1) - x2;
1618 if (checkForZero(denom)) {
1619 return false;
1620 }
1621 a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1622 }
1623
1624 float invScale = 1 / scale.fX;
1625 dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) +
1626 srcPt[3].fX - srcPt[0].fX, invScale);
1627 dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) +
1628 srcPt[3].fY - srcPt[0].fY, invScale);
1629 dst->fMat[kMPersp0] = SkScalarMul(a2, invScale);
1630 invScale = 1 / scale.fY;
1631 dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) +
1632 srcPt[1].fX - srcPt[0].fX, invScale);
1633 dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) +
1634 srcPt[1].fY - srcPt[0].fY, invScale);
1635 dst->fMat[kMPersp1] = SkScalarMul(a1, invScale);
1636 dst->fMat[kMTransX] = srcPt[0].fX;
1637 dst->fMat[kMTransY] = srcPt[0].fY;
1638 dst->fMat[kMPersp2] = 1;
1639 dst->setTypeMask(kUnknown_Mask);
1640 return true;
1641}
1642
1643#endif
1644
1645typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
1646
1647/* Taken from Rob Johnson's original sample code in QuickDraw GX
1648*/
1649bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
1650 int count) {
1651 if ((unsigned)count > 4) {
1652 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1653 return false;
1654 }
1655
1656 if (0 == count) {
1657 this->reset();
1658 return true;
1659 }
1660 if (1 == count) {
1661 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1662 return true;
1663 }
1664
1665 SkPoint scale;
1666 if (!poly_to_point(&scale, src, count) ||
1667 SkScalarNearlyZero(scale.fX) ||
1668 SkScalarNearlyZero(scale.fY)) {
1669 return false;
1670 }
1671
1672 static const PolyMapProc gPolyMapProcs[] = {
1673 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1674 };
1675 PolyMapProc proc = gPolyMapProcs[count - 2];
1676
1677 SkMatrix tempMap, result;
1678 tempMap.setTypeMask(kUnknown_Mask);
1679
1680 if (!proc(src, &tempMap, scale)) {
1681 return false;
1682 }
1683 if (!tempMap.invert(&result)) {
1684 return false;
1685 }
1686 if (!proc(dst, &tempMap, scale)) {
1687 return false;
1688 }
1689 if (!result.setConcat(tempMap, result)) {
1690 return false;
1691 }
1692 *this = result;
1693 return true;
1694}
1695
1696///////////////////////////////////////////////////////////////////////////////
1697
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001698SkScalar SkMatrix::getMaxStretch() const {
1699 TypeMask mask = this->getType();
1700
bsalomon@google.com38396322011-09-09 19:32:04 +00001701 if (this->hasPerspective()) {
1702 return -SK_Scalar1;
1703 }
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001704 if (this->isIdentity()) {
bsalomon@google.com38396322011-09-09 19:32:04 +00001705 return SK_Scalar1;
1706 }
1707 if (!(mask & kAffine_Mask)) {
1708 return SkMaxScalar(SkScalarAbs(fMat[kMScaleX]),
1709 SkScalarAbs(fMat[kMScaleY]));
1710 }
1711 // ignore the translation part of the matrix, just look at 2x2 portion.
1712 // compute singular values, take largest abs value.
1713 // [a b; b c] = A^T*A
1714 SkScalar a = SkScalarMul(fMat[kMScaleX], fMat[kMScaleX]) +
1715 SkScalarMul(fMat[kMSkewY], fMat[kMSkewY]);
1716 SkScalar b = SkScalarMul(fMat[kMScaleX], fMat[kMSkewX]) +
1717 SkScalarMul(fMat[kMScaleY], fMat[kMSkewY]);
1718 SkScalar c = SkScalarMul(fMat[kMSkewX], fMat[kMSkewX]) +
1719 SkScalarMul(fMat[kMScaleY], fMat[kMScaleY]);
1720 // eigenvalues of A^T*A are the squared singular values of A.
1721 // characteristic equation is det((A^T*A) - l*I) = 0
1722 // l^2 - (a + c)l + (ac-b^2)
1723 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1724 // and roots are guaraunteed to be pos and real).
1725 SkScalar largerRoot;
1726 SkScalar bSqd = SkScalarMul(b,b);
1727 // if upper left 2x2 is orthogonal save some math
1728 if (bSqd <= SK_ScalarNearlyZero) {
1729 largerRoot = SkMaxScalar(a, c);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001730 } else {
bsalomon@google.com38396322011-09-09 19:32:04 +00001731 SkScalar aminusc = a - c;
1732 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1733 SkScalar x = SkScalarHalf(SkScalarSqrt(SkScalarMul(aminusc, aminusc) + 4 * bSqd));
1734 largerRoot = apluscdiv2 + x;
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001735 }
bsalomon@google.com38396322011-09-09 19:32:04 +00001736 return SkScalarSqrt(largerRoot);
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001737}
1738
1739const SkMatrix& SkMatrix::I() {
1740 static SkMatrix gIdentity;
1741 static bool gOnce;
1742 if (!gOnce) {
1743 gIdentity.reset();
1744 gOnce = true;
1745 }
1746 return gIdentity;
tomhudson@google.com1f902872012-06-01 13:15:47 +00001747}
bsalomon@google.comcc4dac32011-05-10 13:52:42 +00001748
1749const SkMatrix& SkMatrix::InvalidMatrix() {
1750 static SkMatrix gInvalid;
1751 static bool gOnce;
1752 if (!gOnce) {
1753 gInvalid.setAll(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1754 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1755 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
1756 gInvalid.getType(); // force the type to be computed
1757 gOnce = true;
1758 }
1759 return gInvalid;
1760}
1761
1762///////////////////////////////////////////////////////////////////////////////
1763
djsollen@google.com94e75ee2012-06-08 18:30:46 +00001764uint32_t SkMatrix::writeToMemory(void* buffer) const {
reed@android.com0ad336f2009-06-29 16:02:20 +00001765 // TODO write less for simple matrices
1766 if (buffer) {
1767 memcpy(buffer, fMat, 9 * sizeof(SkScalar));
1768 }
1769 return 9 * sizeof(SkScalar);
1770}
1771
djsollen@google.com94e75ee2012-06-08 18:30:46 +00001772uint32_t SkMatrix::readFromMemory(const void* buffer) {
reed@android.comf2b98d62010-12-20 18:26:13 +00001773 if (buffer) {
1774 memcpy(fMat, buffer, 9 * sizeof(SkScalar));
1775 this->setTypeMask(kUnknown_Mask);
1776 }
reed@android.com0ad336f2009-06-29 16:02:20 +00001777 return 9 * sizeof(SkScalar);
1778}
1779
reed@android.com8a1c16f2008-12-17 15:59:43 +00001780void SkMatrix::dump() const {
1781 SkString str;
1782 this->toDumpString(&str);
1783 SkDebugf("%s\n", str.c_str());
1784}
1785
1786void SkMatrix::toDumpString(SkString* str) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001787 str->printf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
1788#ifdef SK_SCALAR_IS_FLOAT
1789 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1790 fMat[6], fMat[7], fMat[8]);
1791#else
1792 SkFixedToFloat(fMat[0]), SkFixedToFloat(fMat[1]), SkFixedToFloat(fMat[2]),
1793 SkFixedToFloat(fMat[3]), SkFixedToFloat(fMat[4]), SkFixedToFloat(fMat[5]),
1794 SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
1795#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +00001796}