blob: 3d2712b0735e51dd8d37db7f69d396c56dc14a5c [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"
21#include "SkString.h"
22
23#ifdef SK_SCALAR_IS_FLOAT
24 #define kMatrix22Elem SK_Scalar1
25#else
26 #define kMatrix22Elem SK_Fract1
27#endif
28
29/* [scale-x skew-x trans-x] [X] [X']
30 [skew-y scale-y trans-y] * [Y] = [Y']
31 [persp-0 persp-1 persp-2] [1] [1 ]
32*/
33
34void SkMatrix::reset() {
35 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
36 fMat[kMSkewX] = fMat[kMSkewY] =
37 fMat[kMTransX] = fMat[kMTransY] =
38 fMat[kMPersp0] = fMat[kMPersp1] = 0;
39 fMat[kMPersp2] = kMatrix22Elem;
40
41 this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
42}
43
44static inline int has_perspective(const SkMatrix& matrix) {
45 return matrix.getType() & SkMatrix::kPerspective_Mask;
46}
47
48// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
49enum {
50 kTranslate_Shift,
51 kScale_Shift,
52 kAffine_Shift,
53 kPerspective_Shift,
54 kRectStaysRect_Shift
55};
56
57#ifdef SK_SCALAR_IS_FLOAT
58 static const int32_t kScalar1Int = 0x3f800000;
59 static const int32_t kPersp1Int = 0x3f800000;
60#else
61 #define scalarAsInt(x) (x)
62 static const int32_t kScalar1Int = (1 << 16);
63 static const int32_t kPersp1Int = (1 << 30);
64#endif
65
66uint8_t SkMatrix::computeTypeMask() const {
67 unsigned mask = 0;
68
69 if (SkScalarAs2sCompliment(fMat[kMPersp0]) |
70 SkScalarAs2sCompliment(fMat[kMPersp1]) |
71 (SkScalarAs2sCompliment(fMat[kMPersp2]) - kPersp1Int)) {
72 mask |= kPerspective_Mask;
73 }
74
75 if (SkScalarAs2sCompliment(fMat[kMTransX]) |
76 SkScalarAs2sCompliment(fMat[kMTransY])) {
77 mask |= kTranslate_Mask;
78 }
79
80 int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
81 int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
82 int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
83 int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
84
85 if (m01 | m10) {
86 mask |= kAffine_Mask;
87 }
88
89 if ((m00 - kScalar1Int) | (m11 - kScalar1Int)) {
90 mask |= kScale_Mask;
91 }
92
93 if ((mask & kPerspective_Mask) == 0) {
94 // map non-zero to 1
95 m00 = m00 != 0;
96 m01 = m01 != 0;
97 m10 = m10 != 0;
98 m11 = m11 != 0;
99
100 // record if the (p)rimary and (s)econdary diagonals are all 0 or
101 // all non-zero (answer is 0 or 1)
102 int dp0 = (m00 | m11) ^ 1; // true if both are 0
103 int dp1 = m00 & m11; // true if both are 1
104 int ds0 = (m01 | m10) ^ 1; // true if both are 0
105 int ds1 = m01 & m10; // true if both are 1
106
107 // return 1 if primary is 1 and secondary is 0 or
108 // primary is 0 and secondary is 1
109 mask |= ((dp0 & ds1) | (dp1 & ds0)) << kRectStaysRect_Shift;
110 }
111
112 return SkToU8(mask);
113}
114
115///////////////////////////////////////////////////////////////////////////////
116
117void SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
118 if (SkScalarAs2sCompliment(dx) | SkScalarAs2sCompliment(dy)) {
119 fMat[kMTransX] = dx;
120 fMat[kMTransY] = dy;
121
122 fMat[kMScaleX] = fMat[kMScaleY] = SK_Scalar1;
123 fMat[kMSkewX] = fMat[kMSkewY] =
124 fMat[kMPersp0] = fMat[kMPersp1] = 0;
125 fMat[kMPersp2] = kMatrix22Elem;
126
127 this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
128 } else {
129 this->reset();
130 }
131}
132
133bool SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
134 if (has_perspective(*this)) {
135 SkMatrix m;
136 m.setTranslate(dx, dy);
137 return this->preConcat(m);
138 }
139
140 if (SkScalarAs2sCompliment(dx) | SkScalarAs2sCompliment(dy)) {
141 fMat[kMTransX] += SkScalarMul(fMat[kMScaleX], dx) +
142 SkScalarMul(fMat[kMSkewX], dy);
143 fMat[kMTransY] += SkScalarMul(fMat[kMSkewY], dx) +
144 SkScalarMul(fMat[kMScaleY], dy);
145
146 this->setTypeMask(kUnknown_Mask);
147 }
148 return true;
149}
150
151bool SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
152 if (has_perspective(*this)) {
153 SkMatrix m;
154 m.setTranslate(dx, dy);
155 return this->postConcat(m);
156 }
157
158 if (SkScalarAs2sCompliment(dx) | SkScalarAs2sCompliment(dy)) {
159 fMat[kMTransX] += dx;
160 fMat[kMTransY] += dy;
161 this->setTypeMask(kUnknown_Mask);
162 }
163 return true;
164}
165
166///////////////////////////////////////////////////////////////////////////////
167
168void SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
169 fMat[kMScaleX] = sx;
170 fMat[kMScaleY] = sy;
171 fMat[kMTransX] = px - SkScalarMul(sx, px);
172 fMat[kMTransY] = py - SkScalarMul(sy, py);
173 fMat[kMPersp2] = kMatrix22Elem;
174
175 fMat[kMSkewX] = fMat[kMSkewY] =
176 fMat[kMPersp0] = fMat[kMPersp1] = 0;
177
178 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
179}
180
181void SkMatrix::setScale(SkScalar sx, SkScalar sy) {
182 fMat[kMScaleX] = sx;
183 fMat[kMScaleY] = sy;
184 fMat[kMPersp2] = kMatrix22Elem;
185
186 fMat[kMTransX] = fMat[kMTransY] =
187 fMat[kMSkewX] = fMat[kMSkewY] =
188 fMat[kMPersp0] = fMat[kMPersp1] = 0;
189
190 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
191}
192
193bool SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
194 SkMatrix m;
195 m.setScale(sx, sy, px, py);
196 return this->preConcat(m);
197}
198
199bool SkMatrix::preScale(SkScalar sx, SkScalar sy) {
200 SkMatrix m;
201 m.setScale(sx, sy);
202 return this->preConcat(m);
203}
204
205bool SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
206 SkMatrix m;
207 m.setScale(sx, sy, px, py);
208 return this->postConcat(m);
209}
210
211bool SkMatrix::postScale(SkScalar sx, SkScalar sy) {
212 SkMatrix m;
213 m.setScale(sx, sy);
214 return this->postConcat(m);
215}
216
217#ifdef SK_SCALAR_IS_FIXED
218 static inline SkFixed roundidiv(SkFixed numer, int denom) {
219 int ns = numer >> 31;
220 int ds = denom >> 31;
221 numer = (numer ^ ns) - ns;
222 denom = (denom ^ ds) - ds;
223
224 SkFixed answer = (numer + (denom >> 1)) / denom;
225 int as = ns ^ ds;
226 return (answer ^ as) - as;
227 }
228#endif
229
230// this guy perhaps can go away, if we have a fract/high-precision way to
231// scale matrices
232bool SkMatrix::postIDiv(int divx, int divy) {
233 if (divx == 0 || divy == 0) {
234 return false;
235 }
236
237#ifdef SK_SCALAR_IS_FIXED
238 fMat[kMScaleX] = roundidiv(fMat[kMScaleX], divx);
239 fMat[kMSkewX] = roundidiv(fMat[kMSkewX], divx);
240 fMat[kMTransX] = roundidiv(fMat[kMTransX], divx);
241
242 fMat[kMScaleY] = roundidiv(fMat[kMScaleY], divy);
243 fMat[kMSkewY] = roundidiv(fMat[kMSkewY], divy);
244 fMat[kMTransY] = roundidiv(fMat[kMTransY], divy);
245#else
246 const float invX = 1.f / divx;
247 const float invY = 1.f / divy;
248
249 fMat[kMScaleX] *= invX;
250 fMat[kMSkewX] *= invX;
251 fMat[kMTransX] *= invX;
252
253 fMat[kMScaleY] *= invY;
254 fMat[kMSkewY] *= invY;
255 fMat[kMTransY] *= invY;
256#endif
257
258 this->setTypeMask(kUnknown_Mask);
259 return true;
260}
261
262////////////////////////////////////////////////////////////////////////////////////
263
264void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV,
265 SkScalar px, SkScalar py) {
266 const SkScalar oneMinusCosV = SK_Scalar1 - cosV;
267
268 fMat[kMScaleX] = cosV;
269 fMat[kMSkewX] = -sinV;
270 fMat[kMTransX] = SkScalarMul(sinV, py) + SkScalarMul(oneMinusCosV, px);
271
272 fMat[kMSkewY] = sinV;
273 fMat[kMScaleY] = cosV;
274 fMat[kMTransY] = SkScalarMul(-sinV, px) + SkScalarMul(oneMinusCosV, py);
275
276 fMat[kMPersp0] = fMat[kMPersp1] = 0;
277 fMat[kMPersp2] = kMatrix22Elem;
278
279 this->setTypeMask(kUnknown_Mask);
280}
281
282void SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
283 fMat[kMScaleX] = cosV;
284 fMat[kMSkewX] = -sinV;
285 fMat[kMTransX] = 0;
286
287 fMat[kMSkewY] = sinV;
288 fMat[kMScaleY] = cosV;
289 fMat[kMTransY] = 0;
290
291 fMat[kMPersp0] = fMat[kMPersp1] = 0;
292 fMat[kMPersp2] = kMatrix22Elem;
293
294 this->setTypeMask(kUnknown_Mask);
295}
296
297void SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
298 SkScalar sinV, cosV;
299 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
300 this->setSinCos(sinV, cosV, px, py);
301}
302
303void SkMatrix::setRotate(SkScalar degrees) {
304 SkScalar sinV, cosV;
305 sinV = SkScalarSinCos(SkDegreesToRadians(degrees), &cosV);
306 this->setSinCos(sinV, cosV);
307}
308
309bool SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
310 SkMatrix m;
311 m.setRotate(degrees, px, py);
312 return this->preConcat(m);
313}
314
315bool SkMatrix::preRotate(SkScalar degrees) {
316 SkMatrix m;
317 m.setRotate(degrees);
318 return this->preConcat(m);
319}
320
321bool SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
322 SkMatrix m;
323 m.setRotate(degrees, px, py);
324 return this->postConcat(m);
325}
326
327bool SkMatrix::postRotate(SkScalar degrees) {
328 SkMatrix m;
329 m.setRotate(degrees);
330 return this->postConcat(m);
331}
332
333////////////////////////////////////////////////////////////////////////////////////
334
335void SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
336 fMat[kMScaleX] = SK_Scalar1;
337 fMat[kMSkewX] = sx;
338 fMat[kMTransX] = SkScalarMul(-sx, py);
339
340 fMat[kMSkewY] = sy;
341 fMat[kMScaleY] = SK_Scalar1;
342 fMat[kMTransY] = SkScalarMul(-sy, px);
343
344 fMat[kMPersp0] = fMat[kMPersp1] = 0;
345 fMat[kMPersp2] = kMatrix22Elem;
346
347 this->setTypeMask(kUnknown_Mask);
348}
349
350void SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
351 fMat[kMScaleX] = SK_Scalar1;
352 fMat[kMSkewX] = sx;
353 fMat[kMTransX] = 0;
354
355 fMat[kMSkewY] = sy;
356 fMat[kMScaleY] = SK_Scalar1;
357 fMat[kMTransY] = 0;
358
359 fMat[kMPersp0] = fMat[kMPersp1] = 0;
360 fMat[kMPersp2] = kMatrix22Elem;
361
362 this->setTypeMask(kUnknown_Mask);
363}
364
365bool SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
366 SkMatrix m;
367 m.setSkew(sx, sy, px, py);
368 return this->preConcat(m);
369}
370
371bool SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
372 SkMatrix m;
373 m.setSkew(sx, sy);
374 return this->preConcat(m);
375}
376
377bool SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
378 SkMatrix m;
379 m.setSkew(sx, sy, px, py);
380 return this->postConcat(m);
381}
382
383bool SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
384 SkMatrix m;
385 m.setSkew(sx, sy);
386 return this->postConcat(m);
387}
388
389///////////////////////////////////////////////////////////////////////////////
390
391bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst,
392 ScaleToFit align)
393{
394 if (src.isEmpty()) {
395 this->reset();
396 return false;
397 }
398
399 if (dst.isEmpty()) {
reed@android.com4516f472009-06-29 16:25:36 +0000400 sk_bzero(fMat, 8 * sizeof(SkScalar));
reed@android.com8a1c16f2008-12-17 15:59:43 +0000401 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
402 } else {
403 SkScalar tx, sx = SkScalarDiv(dst.width(), src.width());
404 SkScalar ty, sy = SkScalarDiv(dst.height(), src.height());
405 bool xLarger = false;
406
407 if (align != kFill_ScaleToFit) {
408 if (sx > sy) {
409 xLarger = true;
410 sx = sy;
411 } else {
412 sy = sx;
413 }
414 }
415
416 tx = dst.fLeft - SkScalarMul(src.fLeft, sx);
417 ty = dst.fTop - SkScalarMul(src.fTop, sy);
418 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
419 SkScalar diff;
420
421 if (xLarger) {
422 diff = dst.width() - SkScalarMul(src.width(), sy);
423 } else {
424 diff = dst.height() - SkScalarMul(src.height(), sy);
425 }
426
427 if (align == kCenter_ScaleToFit) {
428 diff = SkScalarHalf(diff);
429 }
430
431 if (xLarger) {
432 tx += diff;
433 } else {
434 ty += diff;
435 }
436 }
437
438 fMat[kMScaleX] = sx;
439 fMat[kMScaleY] = sy;
440 fMat[kMTransX] = tx;
441 fMat[kMTransY] = ty;
442 fMat[kMSkewX] = fMat[kMSkewY] =
443 fMat[kMPersp0] = fMat[kMPersp1] = 0;
444
445 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
446 }
447 // shared cleanup
448 fMat[kMPersp2] = kMatrix22Elem;
449 return true;
450}
451
452///////////////////////////////////////////////////////////////////////////////
453
454#ifdef SK_SCALAR_IS_FLOAT
455 static inline int fixmuladdmul(float a, float b, float c, float d,
456 float* result) {
457 *result = a * b + c * d;
458 return true;
459 }
460
461 static inline int fixmuladdmulshiftmul(float a, float b, float c, float d,
462 int /*shift not used*/, float scale, float* result) {
463 *result = (a * b + c * d) * scale;
464 return true;
465 }
466
467 static inline bool rowcol3(const float row[], const float col[],
468 float* result) {
469 *result = row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
470 return true;
471 }
472
473 static inline int negifaddoverflows(float& result, float a, float b) {
474 result = a + b;
475 return 0;
476 }
477#else
478 static inline bool fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d,
479 SkFixed* result) {
480 Sk64 tmp1, tmp2;
481 tmp1.setMul(a, b);
482 tmp2.setMul(c, d);
483 tmp1.add(tmp2);
484 if (tmp1.isFixed()) {
485 *result = tmp1.getFixed();
486 return true;
487 }
488 return false;
489 }
490
491 static inline bool fixmuladdmulshiftmul(SkFixed a, SkFixed b, SkFixed c,
492 SkFixed d, int shift, SkFixed scale, SkFixed* result) {
493 Sk64 tmp1, tmp2;
494 tmp1.setMul(a, b);
495 tmp2.setMul(c, d);
496 tmp1.add(tmp2);
497
498 int32_t hi = SkAbs32(tmp1.fHi);
499 int afterShift = 16;
500 if (hi >> 15) {
501 int clz = 17 - SkCLZ(hi);
502 SkASSERT(clz > 0 && clz <= 16);
503 afterShift -= clz;
504 shift += clz;
505 }
506
507 tmp1.roundRight(shift + 16);
508 SkASSERT(tmp1.is32());
509
510 tmp1.setMul(tmp1.get32(), scale);
511 tmp1.roundRight(afterShift);
512 if (tmp1.is32()) {
513 *result = tmp1.get32();
514 return true;
515 }
516 return false;
517 }
518
519 static inline SkFixed fracmuladdmul(SkFixed a, SkFract b, SkFixed c,
520 SkFract d) {
521 Sk64 tmp1, tmp2;
522 tmp1.setMul(a, b);
523 tmp2.setMul(c, d);
524 tmp1.add(tmp2);
525 return tmp1.getFract();
526 }
527
528 static inline bool rowcol3(const SkFixed row[], const SkFixed col[],
529 SkFixed* result) {
530 Sk64 tmp1, tmp2;
531
532 tmp1.setMul(row[0], col[0]); // N * fixed
533 tmp2.setMul(row[1], col[3]); // N * fixed
534 tmp1.add(tmp2);
535
536 tmp2.setMul(row[2], col[6]); // N * fract
537 tmp2.roundRight(14); // make it fixed
538 tmp1.add(tmp2);
539
540 if (tmp1.isFixed()) {
541 *result = tmp1.getFixed();
542 return true;
543 }
544 return false;
545 }
546
547 static inline int negifaddoverflows(SkFixed& result, SkFixed a, SkFixed b) {
548 SkFixed c = a + b;
549 result = c;
550 return (c ^ a) & (c ^ b);
551 }
552#endif
553
554static void normalize_perspective(SkScalar mat[9]) {
555 if (SkScalarAbs(mat[SkMatrix::kMPersp2]) > kMatrix22Elem) {
556 for (int i = 0; i < 9; i++)
557 mat[i] = SkScalarHalf(mat[i]);
558 }
559}
560
561bool SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
562 TypeMask aType = a.getType();
563 TypeMask bType = b.getType();
564
565 if (0 == aType) {
566 *this = b;
567 } else if (0 == bType) {
568 *this = a;
569 } else {
570 SkMatrix tmp;
571
572 if ((aType | bType) & kPerspective_Mask) {
573 if (!rowcol3(&a.fMat[0], &b.fMat[0], &tmp.fMat[kMScaleX])) {
574 return false;
575 }
576 if (!rowcol3(&a.fMat[0], &b.fMat[1], &tmp.fMat[kMSkewX])) {
577 return false;
578 }
579 if (!rowcol3(&a.fMat[0], &b.fMat[2], &tmp.fMat[kMTransX])) {
580 return false;
581 }
582
583 if (!rowcol3(&a.fMat[3], &b.fMat[0], &tmp.fMat[kMSkewY])) {
584 return false;
585 }
586 if (!rowcol3(&a.fMat[3], &b.fMat[1], &tmp.fMat[kMScaleY])) {
587 return false;
588 }
589 if (!rowcol3(&a.fMat[3], &b.fMat[2], &tmp.fMat[kMTransY])) {
590 return false;
591 }
592
593 if (!rowcol3(&a.fMat[6], &b.fMat[0], &tmp.fMat[kMPersp0])) {
594 return false;
595 }
596 if (!rowcol3(&a.fMat[6], &b.fMat[1], &tmp.fMat[kMPersp1])) {
597 return false;
598 }
599 if (!rowcol3(&a.fMat[6], &b.fMat[2], &tmp.fMat[kMPersp2])) {
600 return false;
601 }
602
603 normalize_perspective(tmp.fMat);
604 } else { // not perspective
605 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX],
606 a.fMat[kMSkewX], b.fMat[kMSkewY], &tmp.fMat[kMScaleX])) {
607 return false;
608 }
609 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX],
610 a.fMat[kMSkewX], b.fMat[kMScaleY], &tmp.fMat[kMSkewX])) {
611 return false;
612 }
613 if (!fixmuladdmul(a.fMat[kMScaleX], b.fMat[kMTransX],
614 a.fMat[kMSkewX], b.fMat[kMTransY], &tmp.fMat[kMTransX])) {
615 return false;
616 }
617 if (negifaddoverflows(tmp.fMat[kMTransX], tmp.fMat[kMTransX],
618 a.fMat[kMTransX]) < 0) {
619 return false;
620 }
621
622 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX],
623 a.fMat[kMScaleY], b.fMat[kMSkewY], &tmp.fMat[kMSkewY])) {
624 return false;
625 }
626 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX],
627 a.fMat[kMScaleY], b.fMat[kMScaleY], &tmp.fMat[kMScaleY])) {
628 return false;
629 }
630 if (!fixmuladdmul(a.fMat[kMSkewY], b.fMat[kMTransX],
631 a.fMat[kMScaleY], b.fMat[kMTransY], &tmp.fMat[kMTransY])) {
632 return false;
633 }
634 if (negifaddoverflows(tmp.fMat[kMTransY], tmp.fMat[kMTransY],
635 a.fMat[kMTransY]) < 0) {
636 return false;
637 }
638
639 tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
640 tmp.fMat[kMPersp2] = kMatrix22Elem;
641 }
642 *this = tmp;
643 }
644 this->setTypeMask(kUnknown_Mask);
645 return true;
646}
647
648bool SkMatrix::preConcat(const SkMatrix& mat) {
649 // check for identity first, so we don't do a needless copy of ourselves
650 // to ourselves inside setConcat()
651 return mat.isIdentity() || this->setConcat(*this, mat);
652}
653
654bool SkMatrix::postConcat(const SkMatrix& mat) {
655 // check for identity first, so we don't do a needless copy of ourselves
656 // to ourselves inside setConcat()
657 return mat.isIdentity() || this->setConcat(mat, *this);
658}
659
660///////////////////////////////////////////////////////////////////////////////
661
662#ifdef SK_SCALAR_IS_FLOAT
663 #define SkPerspMul(a, b) SkScalarMul(a, b)
664 #define SkScalarMulShift(a, b, s) SkScalarMul(a, b)
665 static float sk_inv_determinant(const float mat[9], int isPerspective,
666 int* /* (only used in Fixed case) */) {
667 double det;
668
669 if (isPerspective) {
670 det = mat[SkMatrix::kMScaleX] * ((double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp2] - (double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp1]) +
671 mat[SkMatrix::kMSkewX] * ((double)mat[SkMatrix::kMTransY] * mat[SkMatrix::kMPersp0] - (double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp2]) +
672 mat[SkMatrix::kMTransX] * ((double)mat[SkMatrix::kMSkewY] * mat[SkMatrix::kMPersp1] - (double)mat[SkMatrix::kMScaleY] * mat[SkMatrix::kMPersp0]);
673 } else {
674 det = (double)mat[SkMatrix::kMScaleX] * mat[SkMatrix::kMScaleY] - (double)mat[SkMatrix::kMSkewX] * mat[SkMatrix::kMSkewY];
675 }
676
677 // Since the determinant is on the order of the square of the matrix members,
678 // compare to the square of the default nearly-zero constant
679 if (SkScalarNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
680 return 0;
681 }
682 return (float)(1.0 / det);
683 }
684#else
685 #define SkPerspMul(a, b) SkFractMul(a, b)
686 #define SkScalarMulShift(a, b, s) SkMulShift(a, b, s)
687 static void set_muladdmul(Sk64* dst, int32_t a, int32_t b, int32_t c,
688 int32_t d) {
689 Sk64 tmp;
690 dst->setMul(a, b);
691 tmp.setMul(c, d);
692 dst->add(tmp);
693 }
694
695 static SkFixed sk_inv_determinant(const SkFixed mat[9], int isPerspective,
696 int* shift) {
697 Sk64 tmp1, tmp2;
698
699 if (isPerspective) {
700 tmp1.setMul(mat[SkMatrix::kMScaleX], fracmuladdmul(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2], -mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1]));
701 tmp2.setMul(mat[SkMatrix::kMSkewX], fracmuladdmul(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0], -mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2]));
702 tmp1.add(tmp2);
703 tmp2.setMul(mat[SkMatrix::kMTransX], fracmuladdmul(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1], -mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]));
704 tmp1.add(tmp2);
705 } else {
706 tmp1.setMul(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY]);
707 tmp2.setMul(mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
708 tmp1.sub(tmp2);
709 }
710
711 int s = tmp1.getClzAbs();
712 *shift = s;
713
714 SkFixed denom;
715 if (s <= 32) {
716 denom = tmp1.getShiftRight(33 - s);
717 } else {
718 denom = (int32_t)tmp1.fLo << (s - 33);
719 }
720
721 if (denom == 0) {
722 return 0;
723 }
724 /** This could perhaps be a special fractdiv function, since both of its
725 arguments are known to have bit 31 clear and bit 30 set (when they
726 are made positive), thus eliminating the need for calling clz()
727 */
728 return SkFractDiv(SK_Fract1, denom);
729 }
730#endif
731
732bool SkMatrix::invert(SkMatrix* inv) const {
733 int isPersp = has_perspective(*this);
734 int shift;
735 SkScalar scale = sk_inv_determinant(fMat, isPersp, &shift);
736
737 if (scale == 0) { // underflow
738 return false;
739 }
740
741 if (inv) {
742 SkMatrix tmp;
743 if (inv == this)
744 inv = &tmp;
745
746 if (isPersp) {
747 shift = 61 - shift;
748 inv->fMat[kMScaleX] = SkScalarMulShift(SkPerspMul(fMat[kMScaleY], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransY], fMat[kMPersp1]), scale, shift);
749 inv->fMat[kMSkewX] = SkScalarMulShift(SkPerspMul(fMat[kMTransX], fMat[kMPersp1]) - SkPerspMul(fMat[kMSkewX], fMat[kMPersp2]), scale, shift);
750 inv->fMat[kMTransX] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMTransY]) - SkScalarMul(fMat[kMTransX], fMat[kMScaleY]), scale, shift);
751
752 inv->fMat[kMSkewY] = SkScalarMulShift(SkPerspMul(fMat[kMTransY], fMat[kMPersp0]) - SkPerspMul(fMat[kMSkewY], fMat[kMPersp2]), scale, shift);
753 inv->fMat[kMScaleY] = SkScalarMulShift(SkPerspMul(fMat[kMScaleX], fMat[kMPersp2]) - SkPerspMul(fMat[kMTransX], fMat[kMPersp0]), scale, shift);
754 inv->fMat[kMTransY] = SkScalarMulShift(SkScalarMul(fMat[kMTransX], fMat[kMSkewY]) - SkScalarMul(fMat[kMScaleX], fMat[kMTransY]), scale, shift);
755
756 inv->fMat[kMPersp0] = SkScalarMulShift(SkScalarMul(fMat[kMSkewY], fMat[kMPersp1]) - SkScalarMul(fMat[kMScaleY], fMat[kMPersp0]), scale, shift);
757 inv->fMat[kMPersp1] = SkScalarMulShift(SkScalarMul(fMat[kMSkewX], fMat[kMPersp0]) - SkScalarMul(fMat[kMScaleX], fMat[kMPersp1]), scale, shift);
758 inv->fMat[kMPersp2] = SkScalarMulShift(SkScalarMul(fMat[kMScaleX], fMat[kMScaleY]) - SkScalarMul(fMat[kMSkewX], fMat[kMSkewY]), scale, shift);
759#ifdef SK_SCALAR_IS_FIXED
760 if (SkAbs32(inv->fMat[kMPersp2]) > SK_Fixed1) {
761 Sk64 tmp;
762
763 tmp.set(SK_Fract1);
764 tmp.shiftLeft(16);
765 tmp.div(inv->fMat[kMPersp2], Sk64::kRound_DivOption);
766
767 SkFract scale = tmp.get32();
768
769 for (int i = 0; i < 9; i++) {
770 inv->fMat[i] = SkFractMul(inv->fMat[i], scale);
771 }
772 }
773 inv->fMat[kMPersp2] = SkFixedToFract(inv->fMat[kMPersp2]);
774#endif
775 } else { // not perspective
776#ifdef SK_SCALAR_IS_FIXED
777 Sk64 tx, ty;
778 int clzNumer;
779
780 // check the 2x2 for overflow
781 {
782 int32_t value = SkAbs32(fMat[kMScaleY]);
783 value |= SkAbs32(fMat[kMSkewX]);
784 value |= SkAbs32(fMat[kMScaleX]);
785 value |= SkAbs32(fMat[kMSkewY]);
786 clzNumer = SkCLZ(value);
787 if (shift - clzNumer > 31)
788 return false; // overflow
789 }
790
791 set_muladdmul(&tx, fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX]);
792 set_muladdmul(&ty, fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY]);
793 // check tx,ty for overflow
794 clzNumer = SkCLZ(SkAbs32(tx.fHi) | SkAbs32(ty.fHi));
795 if (shift - clzNumer > 14) {
796 return false; // overflow
797 }
798
799 int fixedShift = 61 - shift;
800 int sk64shift = 44 - shift + clzNumer;
801
802 inv->fMat[kMScaleX] = SkMulShift(fMat[kMScaleY], scale, fixedShift);
803 inv->fMat[kMSkewX] = SkMulShift(-fMat[kMSkewX], scale, fixedShift);
804 inv->fMat[kMTransX] = SkMulShift(tx.getShiftRight(33 - clzNumer), scale, sk64shift);
805
806 inv->fMat[kMSkewY] = SkMulShift(-fMat[kMSkewY], scale, fixedShift);
807 inv->fMat[kMScaleY] = SkMulShift(fMat[kMScaleX], scale, fixedShift);
808 inv->fMat[kMTransY] = SkMulShift(ty.getShiftRight(33 - clzNumer), scale, sk64shift);
809#else
810 inv->fMat[kMScaleX] = SkScalarMul(fMat[kMScaleY], scale);
811 inv->fMat[kMSkewX] = SkScalarMul(-fMat[kMSkewX], scale);
812 if (!fixmuladdmulshiftmul(fMat[kMSkewX], fMat[kMTransY], -fMat[kMScaleY], fMat[kMTransX], shift, scale, &inv->fMat[kMTransX])) {
813 return false;
814 }
815
816 inv->fMat[kMSkewY] = SkScalarMul(-fMat[kMSkewY], scale);
817 inv->fMat[kMScaleY] = SkScalarMul(fMat[kMScaleX], scale);
818 if (!fixmuladdmulshiftmul(fMat[kMSkewY], fMat[kMTransX], -fMat[kMScaleX], fMat[kMTransY], shift, scale, &inv->fMat[kMTransY])) {
819 return false;
820 }
821#endif
822 inv->fMat[kMPersp0] = 0;
823 inv->fMat[kMPersp1] = 0;
824 inv->fMat[kMPersp2] = kMatrix22Elem;
825 }
826
827 if (inv == &tmp) {
828 *(SkMatrix*)this = tmp;
829 }
830 inv->setTypeMask(kUnknown_Mask);
831 }
832 return true;
833}
834
835///////////////////////////////////////////////////////////////////////////////
836
837void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[],
838 const SkPoint src[], int count) {
839 SkASSERT(m.getType() == 0);
840
841 if (dst != src && count > 0)
842 memcpy(dst, src, count * sizeof(SkPoint));
843}
844
845void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[],
846 const SkPoint src[], int count) {
847 SkASSERT(m.getType() == kTranslate_Mask);
848
849 if (count > 0) {
850 SkScalar tx = m.fMat[kMTransX];
851 SkScalar ty = m.fMat[kMTransY];
852 do {
853 dst->fY = src->fY + ty;
854 dst->fX = src->fX + tx;
855 src += 1;
856 dst += 1;
857 } while (--count);
858 }
859}
860
861void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[],
862 const SkPoint src[], int count) {
863 SkASSERT(m.getType() == kScale_Mask);
864
865 if (count > 0) {
866 SkScalar mx = m.fMat[kMScaleX];
867 SkScalar my = m.fMat[kMScaleY];
868 do {
869 dst->fY = SkScalarMul(src->fY, my);
870 dst->fX = SkScalarMul(src->fX, mx);
871 src += 1;
872 dst += 1;
873 } while (--count);
874 }
875}
876
877void SkMatrix::ScaleTrans_pts(const SkMatrix& m, SkPoint dst[],
878 const SkPoint src[], int count) {
879 SkASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
880
881 if (count > 0) {
882 SkScalar mx = m.fMat[kMScaleX];
883 SkScalar my = m.fMat[kMScaleY];
884 SkScalar tx = m.fMat[kMTransX];
885 SkScalar ty = m.fMat[kMTransY];
886 do {
887 dst->fY = SkScalarMulAdd(src->fY, my, ty);
888 dst->fX = SkScalarMulAdd(src->fX, mx, tx);
889 src += 1;
890 dst += 1;
891 } while (--count);
892 }
893}
894
895void SkMatrix::Rot_pts(const SkMatrix& m, SkPoint dst[],
896 const SkPoint src[], int count) {
897 SkASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
898
899 if (count > 0) {
900 SkScalar mx = m.fMat[kMScaleX];
901 SkScalar my = m.fMat[kMScaleY];
902 SkScalar kx = m.fMat[kMSkewX];
903 SkScalar ky = m.fMat[kMSkewY];
904 do {
905 SkScalar sy = src->fY;
906 SkScalar sx = src->fX;
907 src += 1;
908 dst->fY = SkScalarMul(sx, ky) + SkScalarMul(sy, my);
909 dst->fX = SkScalarMul(sx, mx) + SkScalarMul(sy, kx);
910 dst += 1;
911 } while (--count);
912 }
913}
914
915void SkMatrix::RotTrans_pts(const SkMatrix& m, SkPoint dst[],
916 const SkPoint src[], int count) {
917 SkASSERT((m.getType() & kPerspective_Mask) == 0);
918
919 if (count > 0) {
920 SkScalar mx = m.fMat[kMScaleX];
921 SkScalar my = m.fMat[kMScaleY];
922 SkScalar kx = m.fMat[kMSkewX];
923 SkScalar ky = m.fMat[kMSkewY];
924 SkScalar tx = m.fMat[kMTransX];
925 SkScalar ty = m.fMat[kMTransY];
926 do {
927 SkScalar sy = src->fY;
928 SkScalar sx = src->fX;
929 src += 1;
930 dst->fY = SkScalarMul(sx, ky) + SkScalarMulAdd(sy, my, ty);
931 dst->fX = SkScalarMul(sx, mx) + SkScalarMulAdd(sy, kx, tx);
932 dst += 1;
933 } while (--count);
934 }
935}
936
937void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
938 const SkPoint src[], int count) {
939 SkASSERT(m.getType() & kPerspective_Mask);
940
941#ifdef SK_SCALAR_IS_FIXED
942 SkFixed persp2 = SkFractToFixed(m.fMat[kMPersp2]);
943#endif
944
945 if (count > 0) {
946 do {
947 SkScalar sy = src->fY;
948 SkScalar sx = src->fX;
949 src += 1;
950
951 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
952 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
953 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
954 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
955#ifdef SK_SCALAR_IS_FIXED
956 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
957 SkFractMul(sy, m.fMat[kMPersp1]) + persp2;
958#else
959 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
960 SkScalarMulAdd(sy, m.fMat[kMPersp1], m.fMat[kMPersp2]);
961#endif
962 if (z) {
963 z = SkScalarFastInvert(z);
964 }
965
966 dst->fY = SkScalarMul(y, z);
967 dst->fX = SkScalarMul(x, z);
968 dst += 1;
969 } while (--count);
970 }
971}
972
973const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
974 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
975 SkMatrix::Scale_pts, SkMatrix::ScaleTrans_pts,
976 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
977 SkMatrix::Rot_pts, SkMatrix::RotTrans_pts,
978 // repeat the persp proc 8 times
979 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
980 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
981 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
982 SkMatrix::Persp_pts, SkMatrix::Persp_pts
983};
984
985void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
986 SkASSERT((dst && src && count > 0) || count == 0);
987 // no partial overlap
988 SkASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= count);
989
990 this->getMapPtsProc()(*this, dst, src, count);
991}
992
993///////////////////////////////////////////////////////////////////////////////
994
995void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
996 if (this->getType() & kPerspective_Mask) {
997 SkPoint origin;
998
999 MapXYProc proc = this->getMapXYProc();
1000 proc(*this, 0, 0, &origin);
1001
1002 for (int i = count - 1; i >= 0; --i) {
1003 SkPoint tmp;
1004
1005 proc(*this, src[i].fX, src[i].fY, &tmp);
1006 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1007 }
1008 } else {
1009 SkMatrix tmp = *this;
1010
1011 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1012 tmp.clearTypeMask(kTranslate_Mask);
1013 tmp.mapPoints(dst, src, count);
1014 }
1015}
1016
1017bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
1018 SkASSERT(dst && &src);
1019
1020 if (this->rectStaysRect()) {
1021 this->mapPoints((SkPoint*)dst, (const SkPoint*)&src, 2);
1022 dst->sort();
1023 return true;
1024 } else {
1025 SkPoint quad[4];
1026
1027 src.toQuad(quad);
1028 this->mapPoints(quad, quad, 4);
1029 dst->set(quad, 4);
1030 return false;
1031 }
1032}
1033
1034SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1035 SkVector vec[2];
1036
1037 vec[0].set(radius, 0);
1038 vec[1].set(0, radius);
1039 this->mapVectors(vec, 2);
1040
1041 SkScalar d0 = vec[0].length();
1042 SkScalar d1 = vec[1].length();
1043
1044 return SkScalarMean(d0, d1);
1045}
1046
1047///////////////////////////////////////////////////////////////////////////////
1048
1049void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1050 SkPoint* pt) {
1051 SkASSERT(m.getType() & kPerspective_Mask);
1052
1053 SkScalar x = SkScalarMul(sx, m.fMat[kMScaleX]) +
1054 SkScalarMul(sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1055 SkScalar y = SkScalarMul(sx, m.fMat[kMSkewY]) +
1056 SkScalarMul(sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1057#ifdef SK_SCALAR_IS_FIXED
1058 SkFixed z = SkFractMul(sx, m.fMat[kMPersp0]) +
1059 SkFractMul(sy, m.fMat[kMPersp1]) +
1060 SkFractToFixed(m.fMat[kMPersp2]);
1061#else
1062 float z = SkScalarMul(sx, m.fMat[kMPersp0]) +
1063 SkScalarMul(sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1064#endif
1065 if (z) {
1066 z = SkScalarFastInvert(z);
1067 }
1068 pt->fX = SkScalarMul(x, z);
1069 pt->fY = SkScalarMul(y, z);
1070}
1071
1072#ifdef SK_SCALAR_IS_FIXED
1073static SkFixed fixmuladdmul(SkFixed a, SkFixed b, SkFixed c, SkFixed d) {
1074 Sk64 tmp, tmp1;
1075
1076 tmp.setMul(a, b);
1077 tmp1.setMul(c, d);
1078 return tmp.addGetFixed(tmp1);
1079// tmp.add(tmp1);
1080// return tmp.getFixed();
1081}
1082#endif
1083
1084void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1085 SkPoint* pt) {
1086 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1087
1088#ifdef SK_SCALAR_IS_FIXED
1089 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) +
1090 m.fMat[kMTransX];
1091 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) +
1092 m.fMat[kMTransY];
1093#else
1094 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1095 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1096 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1097 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1098#endif
1099}
1100
1101void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1102 SkPoint* pt) {
1103 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1104 SkASSERT(0 == m.fMat[kMTransX]);
1105 SkASSERT(0 == m.fMat[kMTransY]);
1106
1107#ifdef SK_SCALAR_IS_FIXED
1108 pt->fX = fixmuladdmul(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]);
1109 pt->fY = fixmuladdmul(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]);
1110#else
1111 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]) +
1112 SkScalarMulAdd(sy, m.fMat[kMSkewX], m.fMat[kMTransX]);
1113 pt->fY = SkScalarMul(sx, m.fMat[kMSkewY]) +
1114 SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1115#endif
1116}
1117
1118void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1119 SkPoint* pt) {
1120 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1121 == kScale_Mask);
1122
1123 pt->fX = SkScalarMulAdd(sx, m.fMat[kMScaleX], m.fMat[kMTransX]);
1124 pt->fY = SkScalarMulAdd(sy, m.fMat[kMScaleY], m.fMat[kMTransY]);
1125}
1126
1127void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1128 SkPoint* pt) {
1129 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1130 == kScale_Mask);
1131 SkASSERT(0 == m.fMat[kMTransX]);
1132 SkASSERT(0 == m.fMat[kMTransY]);
1133
1134 pt->fX = SkScalarMul(sx, m.fMat[kMScaleX]);
1135 pt->fY = SkScalarMul(sy, m.fMat[kMScaleY]);
1136}
1137
1138void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1139 SkPoint* pt) {
1140 SkASSERT(m.getType() == kTranslate_Mask);
1141
1142 pt->fX = sx + m.fMat[kMTransX];
1143 pt->fY = sy + m.fMat[kMTransY];
1144}
1145
1146void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1147 SkPoint* pt) {
1148 SkASSERT(0 == m.getType());
1149
1150 pt->fX = sx;
1151 pt->fY = sy;
1152}
1153
1154const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1155 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1156 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1157 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1158 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1159 // repeat the persp proc 8 times
1160 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1161 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1162 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1163 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1164};
1165
1166///////////////////////////////////////////////////////////////////////////////
1167
1168// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1169#ifdef SK_SCALAR_IS_FIXED
1170 typedef SkFract SkPerspElemType;
1171 #define PerspNearlyZero(x) (SkAbs32(x) < (SK_Fract1 >> 26))
1172#else
1173 typedef float SkPerspElemType;
1174 #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1175#endif
1176
1177bool SkMatrix::fixedStepInX(SkScalar y, SkFixed* stepX, SkFixed* stepY) const {
1178 if (PerspNearlyZero(fMat[kMPersp0])) {
1179 if (stepX || stepY) {
1180 if (PerspNearlyZero(fMat[kMPersp1]) &&
1181 PerspNearlyZero(fMat[kMPersp2] - kMatrix22Elem)) {
1182 if (stepX) {
1183 *stepX = SkScalarToFixed(fMat[kMScaleX]);
1184 }
1185 if (stepY) {
1186 *stepY = SkScalarToFixed(fMat[kMSkewY]);
1187 }
1188 } else {
1189#ifdef SK_SCALAR_IS_FIXED
1190 SkFixed z = SkFractMul(y, fMat[kMPersp1]) +
1191 SkFractToFixed(fMat[kMPersp2]);
1192#else
1193 float z = y * fMat[kMPersp1] + fMat[kMPersp2];
1194#endif
1195 if (stepX) {
1196 *stepX = SkScalarToFixed(SkScalarDiv(fMat[kMScaleX], z));
1197 }
1198 if (stepY) {
1199 *stepY = SkScalarToFixed(SkScalarDiv(fMat[kMSkewY], z));
1200 }
1201 }
1202 }
1203 return true;
1204 }
1205 return false;
1206}
1207
1208///////////////////////////////////////////////////////////////////////////////
1209
1210#include "SkPerspIter.h"
1211
1212SkPerspIter::SkPerspIter(const SkMatrix& m, SkScalar x0, SkScalar y0, int count)
1213 : fMatrix(m), fSX(x0), fSY(y0), fCount(count) {
1214 SkPoint pt;
1215
1216 SkMatrix::Persp_xy(m, x0, y0, &pt);
1217 fX = SkScalarToFixed(pt.fX);
1218 fY = SkScalarToFixed(pt.fY);
1219}
1220
1221int SkPerspIter::next() {
1222 int n = fCount;
1223
1224 if (0 == n) {
1225 return 0;
1226 }
1227 SkPoint pt;
1228 SkFixed x = fX;
1229 SkFixed y = fY;
1230 SkFixed dx, dy;
1231
1232 if (n >= kCount) {
1233 n = kCount;
1234 fSX += SkIntToScalar(kCount);
1235 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1236 fX = SkScalarToFixed(pt.fX);
1237 fY = SkScalarToFixed(pt.fY);
1238 dx = (fX - x) >> kShift;
1239 dy = (fY - y) >> kShift;
1240 } else {
1241 fSX += SkIntToScalar(n);
1242 SkMatrix::Persp_xy(fMatrix, fSX, fSY, &pt);
1243 fX = SkScalarToFixed(pt.fX);
1244 fY = SkScalarToFixed(pt.fY);
1245 dx = (fX - x) / n;
1246 dy = (fY - y) / n;
1247 }
1248
1249 SkFixed* p = fStorage;
1250 for (int i = 0; i < n; i++) {
1251 *p++ = x; x += dx;
1252 *p++ = y; y += dy;
1253 }
1254
1255 fCount -= n;
1256 return n;
1257}
1258
1259///////////////////////////////////////////////////////////////////////////////
1260
1261#ifdef SK_SCALAR_IS_FIXED
1262
1263static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1264 SkFixed x = SK_Fixed1, y = SK_Fixed1;
1265 SkPoint pt1, pt2;
1266 Sk64 w1, w2;
1267
1268 if (count > 1) {
1269 pt1.fX = poly[1].fX - poly[0].fX;
1270 pt1.fY = poly[1].fY - poly[0].fY;
1271 y = SkPoint::Length(pt1.fX, pt1.fY);
1272 if (y == 0) {
1273 return false;
1274 }
1275 switch (count) {
1276 case 2:
1277 break;
1278 case 3:
1279 pt2.fX = poly[0].fY - poly[2].fY;
1280 pt2.fY = poly[2].fX - poly[0].fX;
1281 goto CALC_X;
1282 default:
1283 pt2.fX = poly[0].fY - poly[3].fY;
1284 pt2.fY = poly[3].fX - poly[0].fX;
1285 CALC_X:
1286 w1.setMul(pt1.fX, pt2.fX);
1287 w2.setMul(pt1.fY, pt2.fY);
1288 w1.add(w2);
1289 w1.div(y, Sk64::kRound_DivOption);
1290 if (!w1.is32()) {
1291 return false;
1292 }
1293 x = w1.get32();
1294 break;
1295 }
1296 }
1297 pt->set(x, y);
1298 return true;
1299}
1300
1301bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1302 const SkPoint& scalePt) {
1303 // need to check if SkFixedDiv overflows...
1304
1305 const SkFixed scale = scalePt.fY;
1306 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1307 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[0].fX - srcPt[1].fX, scale);
1308 dst->fMat[kMPersp0] = 0;
1309 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale);
1310 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale);
1311 dst->fMat[kMPersp1] = 0;
1312 dst->fMat[kMTransX] = srcPt[0].fX;
1313 dst->fMat[kMTransY] = srcPt[0].fY;
1314 dst->fMat[kMPersp2] = SK_Fract1;
1315 dst->setTypeMask(kUnknown_Mask);
1316 return true;
1317}
1318
1319bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1320 const SkPoint& scale) {
1321 // really, need to check if SkFixedDiv overflow'd
1322
1323 dst->fMat[kMScaleX] = SkFixedDiv(srcPt[2].fX - srcPt[0].fX, scale.fX);
1324 dst->fMat[kMSkewY] = SkFixedDiv(srcPt[2].fY - srcPt[0].fY, scale.fX);
1325 dst->fMat[kMPersp0] = 0;
1326 dst->fMat[kMSkewX] = SkFixedDiv(srcPt[1].fX - srcPt[0].fX, scale.fY);
1327 dst->fMat[kMScaleY] = SkFixedDiv(srcPt[1].fY - srcPt[0].fY, scale.fY);
1328 dst->fMat[kMPersp1] = 0;
1329 dst->fMat[kMTransX] = srcPt[0].fX;
1330 dst->fMat[kMTransY] = srcPt[0].fY;
1331 dst->fMat[kMPersp2] = SK_Fract1;
1332 dst->setTypeMask(kUnknown_Mask);
1333 return true;
1334}
1335
1336bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1337 const SkPoint& scale) {
1338 SkFract a1, a2;
1339 SkFixed x0, y0, x1, y1, x2, y2;
1340
1341 x0 = srcPt[2].fX - srcPt[0].fX;
1342 y0 = srcPt[2].fY - srcPt[0].fY;
1343 x1 = srcPt[2].fX - srcPt[1].fX;
1344 y1 = srcPt[2].fY - srcPt[1].fY;
1345 x2 = srcPt[2].fX - srcPt[3].fX;
1346 y2 = srcPt[2].fY - srcPt[3].fY;
1347
1348 /* check if abs(x2) > abs(y2) */
1349 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1350 SkFixed denom = SkMulDiv(x1, y2, x2) - y1;
1351 if (0 == denom) {
1352 return false;
1353 }
1354 a1 = SkFractDiv(SkMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1355 } else {
1356 SkFixed denom = x1 - SkMulDiv(y1, x2, y2);
1357 if (0 == denom) {
1358 return false;
1359 }
1360 a1 = SkFractDiv(x0 - x1 - SkMulDiv(y0 - y1, x2, y2), denom);
1361 }
1362
1363 /* check if abs(x1) > abs(y1) */
1364 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1365 SkFixed denom = y2 - SkMulDiv(x2, y1, x1);
1366 if (0 == denom) {
1367 return false;
1368 }
1369 a2 = SkFractDiv(y0 - y2 - SkMulDiv(x0 - x2, y1, x1), denom);
1370 } else {
1371 SkFixed denom = SkMulDiv(y2, x1, y1) - x2;
1372 if (0 == denom) {
1373 return false;
1374 }
1375 a2 = SkFractDiv(SkMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1376 }
1377
1378 // need to check if SkFixedDiv overflows...
1379 dst->fMat[kMScaleX] = SkFixedDiv(SkFractMul(a2, srcPt[3].fX) +
1380 srcPt[3].fX - srcPt[0].fX, scale.fX);
1381 dst->fMat[kMSkewY] = SkFixedDiv(SkFractMul(a2, srcPt[3].fY) +
1382 srcPt[3].fY - srcPt[0].fY, scale.fX);
1383 dst->fMat[kMPersp0] = SkFixedDiv(a2, scale.fX);
1384 dst->fMat[kMSkewX] = SkFixedDiv(SkFractMul(a1, srcPt[1].fX) +
1385 srcPt[1].fX - srcPt[0].fX, scale.fY);
1386 dst->fMat[kMScaleY] = SkFixedDiv(SkFractMul(a1, srcPt[1].fY) +
1387 srcPt[1].fY - srcPt[0].fY, scale.fY);
1388 dst->fMat[kMPersp1] = SkFixedDiv(a1, scale.fY);
1389 dst->fMat[kMTransX] = srcPt[0].fX;
1390 dst->fMat[kMTransY] = srcPt[0].fY;
1391 dst->fMat[kMPersp2] = SK_Fract1;
1392 dst->setTypeMask(kUnknown_Mask);
1393 return true;
1394}
1395
1396#else /* Scalar is float */
1397
1398static inline bool checkForZero(float x) {
1399 return x*x == 0;
1400}
1401
1402static inline bool poly_to_point(SkPoint* pt, const SkPoint poly[], int count) {
1403 float x = 1, y = 1;
1404 SkPoint pt1, pt2;
1405
1406 if (count > 1) {
1407 pt1.fX = poly[1].fX - poly[0].fX;
1408 pt1.fY = poly[1].fY - poly[0].fY;
1409 y = SkPoint::Length(pt1.fX, pt1.fY);
1410 if (checkForZero(y)) {
1411 return false;
1412 }
1413 switch (count) {
1414 case 2:
1415 break;
1416 case 3:
1417 pt2.fX = poly[0].fY - poly[2].fY;
1418 pt2.fY = poly[2].fX - poly[0].fX;
1419 goto CALC_X;
1420 default:
1421 pt2.fX = poly[0].fY - poly[3].fY;
1422 pt2.fY = poly[3].fX - poly[0].fX;
1423 CALC_X:
1424 x = SkScalarDiv(SkScalarMul(pt1.fX, pt2.fX) +
1425 SkScalarMul(pt1.fY, pt2.fY), y);
1426 break;
1427 }
1428 }
1429 pt->set(x, y);
1430 return true;
1431}
1432
1433bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst,
1434 const SkPoint& scale) {
1435 float invScale = 1 / scale.fY;
1436
1437 dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1438 dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
1439 dst->fMat[kMPersp0] = 0;
1440 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1441 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1442 dst->fMat[kMPersp1] = 0;
1443 dst->fMat[kMTransX] = srcPt[0].fX;
1444 dst->fMat[kMTransY] = srcPt[0].fY;
1445 dst->fMat[kMPersp2] = 1;
1446 dst->setTypeMask(kUnknown_Mask);
1447 return true;
1448}
1449
1450bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst,
1451 const SkPoint& scale) {
1452 float invScale = 1 / scale.fX;
1453 dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
1454 dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
1455 dst->fMat[kMPersp0] = 0;
1456
1457 invScale = 1 / scale.fY;
1458 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1459 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1460 dst->fMat[kMPersp1] = 0;
1461
1462 dst->fMat[kMTransX] = srcPt[0].fX;
1463 dst->fMat[kMTransY] = srcPt[0].fY;
1464 dst->fMat[kMPersp2] = 1;
1465 dst->setTypeMask(kUnknown_Mask);
1466 return true;
1467}
1468
1469bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst,
1470 const SkPoint& scale) {
1471 float a1, a2;
1472 float x0, y0, x1, y1, x2, y2;
1473
1474 x0 = srcPt[2].fX - srcPt[0].fX;
1475 y0 = srcPt[2].fY - srcPt[0].fY;
1476 x1 = srcPt[2].fX - srcPt[1].fX;
1477 y1 = srcPt[2].fY - srcPt[1].fY;
1478 x2 = srcPt[2].fX - srcPt[3].fX;
1479 y2 = srcPt[2].fY - srcPt[3].fY;
1480
1481 /* check if abs(x2) > abs(y2) */
1482 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1483 float denom = SkScalarMulDiv(x1, y2, x2) - y1;
1484 if (checkForZero(denom)) {
1485 return false;
1486 }
1487 a1 = SkScalarDiv(SkScalarMulDiv(x0 - x1, y2, x2) - y0 + y1, denom);
1488 } else {
1489 float denom = x1 - SkScalarMulDiv(y1, x2, y2);
1490 if (checkForZero(denom)) {
1491 return false;
1492 }
1493 a1 = SkScalarDiv(x0 - x1 - SkScalarMulDiv(y0 - y1, x2, y2), denom);
1494 }
1495
1496 /* check if abs(x1) > abs(y1) */
1497 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1498 float denom = y2 - SkScalarMulDiv(x2, y1, x1);
1499 if (checkForZero(denom)) {
1500 return false;
1501 }
1502 a2 = SkScalarDiv(y0 - y2 - SkScalarMulDiv(x0 - x2, y1, x1), denom);
1503 } else {
1504 float denom = SkScalarMulDiv(y2, x1, y1) - x2;
1505 if (checkForZero(denom)) {
1506 return false;
1507 }
1508 a2 = SkScalarDiv(SkScalarMulDiv(y0 - y2, x1, y1) - x0 + x2, denom);
1509 }
1510
1511 float invScale = 1 / scale.fX;
1512 dst->fMat[kMScaleX] = SkScalarMul(SkScalarMul(a2, srcPt[3].fX) +
1513 srcPt[3].fX - srcPt[0].fX, invScale);
1514 dst->fMat[kMSkewY] = SkScalarMul(SkScalarMul(a2, srcPt[3].fY) +
1515 srcPt[3].fY - srcPt[0].fY, invScale);
1516 dst->fMat[kMPersp0] = SkScalarMul(a2, invScale);
1517 invScale = 1 / scale.fY;
1518 dst->fMat[kMSkewX] = SkScalarMul(SkScalarMul(a1, srcPt[1].fX) +
1519 srcPt[1].fX - srcPt[0].fX, invScale);
1520 dst->fMat[kMScaleY] = SkScalarMul(SkScalarMul(a1, srcPt[1].fY) +
1521 srcPt[1].fY - srcPt[0].fY, invScale);
1522 dst->fMat[kMPersp1] = SkScalarMul(a1, invScale);
1523 dst->fMat[kMTransX] = srcPt[0].fX;
1524 dst->fMat[kMTransY] = srcPt[0].fY;
1525 dst->fMat[kMPersp2] = 1;
1526 dst->setTypeMask(kUnknown_Mask);
1527 return true;
1528}
1529
1530#endif
1531
1532typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*, const SkPoint&);
1533
1534/* Taken from Rob Johnson's original sample code in QuickDraw GX
1535*/
1536bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[],
1537 int count) {
1538 if ((unsigned)count > 4) {
1539 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1540 return false;
1541 }
1542
1543 if (0 == count) {
1544 this->reset();
1545 return true;
1546 }
1547 if (1 == count) {
1548 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1549 return true;
1550 }
1551
1552 SkPoint scale;
1553 if (!poly_to_point(&scale, src, count) ||
1554 SkScalarNearlyZero(scale.fX) ||
1555 SkScalarNearlyZero(scale.fY)) {
1556 return false;
1557 }
1558
1559 static const PolyMapProc gPolyMapProcs[] = {
1560 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1561 };
1562 PolyMapProc proc = gPolyMapProcs[count - 2];
1563
1564 SkMatrix tempMap, result;
1565 tempMap.setTypeMask(kUnknown_Mask);
1566
1567 if (!proc(src, &tempMap, scale)) {
1568 return false;
1569 }
1570 if (!tempMap.invert(&result)) {
1571 return false;
1572 }
1573 if (!proc(dst, &tempMap, scale)) {
1574 return false;
1575 }
1576 if (!result.setConcat(tempMap, result)) {
1577 return false;
1578 }
1579 *this = result;
1580 return true;
1581}
1582
1583///////////////////////////////////////////////////////////////////////////////
1584
reed@android.com0ad336f2009-06-29 16:02:20 +00001585uint32_t SkMatrix::flatten(void* buffer) const {
1586 // TODO write less for simple matrices
1587 if (buffer) {
1588 memcpy(buffer, fMat, 9 * sizeof(SkScalar));
1589 }
1590 return 9 * sizeof(SkScalar);
1591}
1592
1593uint32_t SkMatrix::unflatten(const void* buffer) {
1594 memcpy(fMat, buffer, 9 * sizeof(SkScalar));
1595 this->setTypeMask(kUnknown_Mask);
1596 return 9 * sizeof(SkScalar);
1597}
1598
reed@android.com8a1c16f2008-12-17 15:59:43 +00001599void SkMatrix::dump() const {
1600 SkString str;
1601 this->toDumpString(&str);
1602 SkDebugf("%s\n", str.c_str());
1603}
1604
1605void SkMatrix::toDumpString(SkString* str) const {
1606#ifdef SK_CAN_USE_FLOAT
1607 str->printf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
1608#ifdef SK_SCALAR_IS_FLOAT
1609 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1610 fMat[6], fMat[7], fMat[8]);
1611#else
1612 SkFixedToFloat(fMat[0]), SkFixedToFloat(fMat[1]), SkFixedToFloat(fMat[2]),
1613 SkFixedToFloat(fMat[3]), SkFixedToFloat(fMat[4]), SkFixedToFloat(fMat[5]),
1614 SkFractToFloat(fMat[6]), SkFractToFloat(fMat[7]), SkFractToFloat(fMat[8]));
1615#endif
1616#else // can't use float
1617 str->printf("[%x %x %x][%x %x %x][%x %x %x]",
1618 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1619 fMat[6], fMat[7], fMat[8]);
1620#endif
1621}
1622