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