soui 5.0.0.1
Soui5 Doc
 
Loading...
Searching...
No Matches
SMatrix.cpp
1/*
2 * Copyright 2006 The Android Open Source Project
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7#include <souistd.h>
8#include "matrix/SMatrix.h"
9#include "matrix/SFloatBits.h"
10
11#include <stddef.h>
12
13// In a few places, we performed the following
14// a * b + c * d + e
15// as
16// a * b + (c * d + e)
17//
18// sdot and scross are indended to capture these compound operations into a
19// function, with an eye toward considering upscaling the intermediates to
20// doubles for more precision (as we do in concat and invert).
21//
22// However, these few lines that performed the last add before the "dot", cause
23// tiny image differences, so we guard that change until we see the impact on
24// chrome's layouttests.
25//
26#define SK_LEGACY_MATRIX_MATH_ORDER
27#define SiToU8(x) ((uint8_t)(x))
28
29SNSBEGIN
30static inline float SkDoubleToFloat(double x)
31{
32 return static_cast<float>(x);
33}
34
35SMatrix::SMatrix(const float data[9])
36{
37 memcpy(fMat, data, 9 * sizeof(float));
38 setTypeMask(kUnknown_Mask);
39}
40
41/* [scale-x skew-x trans-x] [X] [X']
42 [skew-y scale-y trans-y] * [Y] = [Y']
43 [persp-0 persp-1 persp-2] [1] [1 ]
44*/
45
47{
48 fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
49 fMat[kMSkewX] = fMat[kMSkewY] = fMat[kMTransX] = fMat[kMTransY] = fMat[kMPersp0] = fMat[kMPersp1] = 0;
50
51 this->setTypeMask(kIdentity_Mask | kRectStaysRect_Mask);
52}
53
54// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
55enum
56{
57 kTranslate_Shift,
58 kScale_Shift,
59 kAffine_Shift,
60 kPerspective_Shift,
61 kRectStaysRect_Shift
62};
63
64static const int32_t kScalar1Int = 0x3f800000;
65
66uint8_t SMatrix::computePerspectiveTypeMask() const
67{
68 // Benchmarking suggests that replacing this set of SFloatAs2sCompliment
69 // is a win, but replacing those below is not. We don't yet understand
70 // that result.
71 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1)
72 {
73 // If this is a perspective transform, we return true for all other
74 // transform flags - this does not disable any optimizations, respects
75 // the rule that the type mask must be conservative, and speeds up
76 // type mask computation.
77 return SiToU8(kORableMasks);
78 }
79
80 return SiToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
81}
82
83uint8_t SMatrix::computeTypeMask() const
84{
85 unsigned mask = 0;
86
87 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1)
88 {
89 // Once it is determined that that this is a perspective transform,
90 // all other flags are moot as far as optimizations are concerned.
91 return SiToU8(kORableMasks);
92 }
93
94 if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0)
95 {
96 mask |= kTranslate_Mask;
97 }
98
99 int m00 = SFloatAs2sCompliment(fMat[kMScaleX]);
100 int m01 = SFloatAs2sCompliment(fMat[kMSkewX]);
101 int m10 = SFloatAs2sCompliment(fMat[kMSkewY]);
102 int m11 = SFloatAs2sCompliment(fMat[kMScaleY]);
103
104 if (m01 | m10)
105 {
106 // The skew components may be scale-inducing, unless we are dealing
107 // with a pure rotation. Testing for a pure rotation is expensive,
108 // so we opt for being conservative by always setting the scale bit.
109 // along with affine.
110 // By doing this, we are also ensuring that matrices have the same
111 // type masks as their inverses.
112 mask |= kAffine_Mask | kScale_Mask;
113
114 // For rectStaysRect, in the affine case, we only need check that
115 // the primary diagonal is all zeros and that the secondary diagonal
116 // is all non-zero.
117
118 // map non-zero to 1
119 m01 = m01 != 0;
120 m10 = m10 != 0;
121
122 int dp0 = 0 == (m00 | m11); // true if both are 0
123 int ds1 = m01 & m10; // true if both are 1
124
125 mask |= (dp0 & ds1) << kRectStaysRect_Shift;
126 }
127 else
128 {
129 // Only test for scale explicitly if not affine, since affine sets the
130 // scale bit.
131 if ((m00 - kScalar1Int) | (m11 - kScalar1Int))
132 {
133 mask |= kScale_Mask;
134 }
135
136 // Not affine, therefore we already know secondary diagonal is
137 // all zeros, so we just need to check that primary diagonal is
138 // all non-zero.
139
140 // map non-zero to 1
141 m00 = m00 != 0;
142 m11 = m11 != 0;
143
144 // record if the (p)rimary diagonal is all non-zero
145 mask |= (m00 & m11) << kRectStaysRect_Shift;
146 }
147
148 return SiToU8(mask);
149}
150
151///////////////////////////////////////////////////////////////////////////////
152
153bool operator==(const SMatrix &a, const SMatrix &b)
154{
155 const float *ma = a.fMat;
156 const float *mb = b.fMat;
157
158 return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] && ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] && ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
159}
160
161///////////////////////////////////////////////////////////////////////////////
162
163// helper function to determine if upper-left 2x2 of matrix is degenerate
164static inline bool is_degenerate_2x2(float scaleX, float skewX, float skewY, float scaleY)
165{
166 float perp_dot = scaleX * scaleY - skewX * skewY;
167 return SFloatNearlyZero(perp_dot, SK_ScalarNearlyZero * SK_ScalarNearlyZero);
168}
169
170///////////////////////////////////////////////////////////////////////////////
171
172bool SMatrix::isSimilarity(float tol) const
173{
174 // if identity or translate matrix
175 TypeMask mask = this->getType();
176 if (mask <= kTranslate_Mask)
177 {
178 return true;
179 }
180 if (mask & kPerspective_Mask)
181 {
182 return false;
183 }
184
185 float mx = fMat[kMScaleX];
186 float my = fMat[kMScaleY];
187 // if no skew, can just compare scale factors
188 if (!(mask & kAffine_Mask))
189 {
190 return !SFloatNearlyZero(mx) && SFloatNearlyEqual(SFloatAbs(mx), SFloatAbs(my));
191 }
192 float sx = fMat[kMSkewX];
193 float sy = fMat[kMSkewY];
194
195 if (is_degenerate_2x2(mx, sx, sy, my))
196 {
197 return false;
198 }
199
200 // upper 2x2 is rotation/reflection + uniform scale if basis vectors
201 // are 90 degree rotations of each other
202 return (SFloatNearlyEqual(mx, my, tol) && SFloatNearlyEqual(sx, -sy, tol)) || (SFloatNearlyEqual(mx, -my, tol) && SFloatNearlyEqual(sx, sy, tol));
203}
204
205bool SMatrix::preservesRightAngles(float tol) const
206{
207 TypeMask mask = this->getType();
208
209 if (mask <= kTranslate_Mask)
210 {
211 // identity, translate and/or scale
212 return true;
213 }
214 if (mask & kPerspective_Mask)
215 {
216 return false;
217 }
218
219 SASSERT(mask & (kAffine_Mask | kScale_Mask));
220
221 float mx = fMat[kMScaleX];
222 float my = fMat[kMScaleY];
223 float sx = fMat[kMSkewX];
224 float sy = fMat[kMSkewY];
225
226 if (is_degenerate_2x2(mx, sx, sy, my))
227 {
228 return false;
229 }
230
231 // upper 2x2 is scale + rotation/reflection if basis vectors are orthogonal
232 SVector2D vec[2];
233 vec[0].set(mx, sy);
234 vec[1].set(sx, my);
235
236 return SFloatNearlyZero(vec[0].dot(vec[1]), SFloatSquare(tol));
237}
238
239///////////////////////////////////////////////////////////////////////////////
240
241static inline float sdot(float a, float b, float c, float d)
242{
243 return a * b + c * d;
244}
245
246static inline float sdot(float a, float b, float c, float d, float e, float f)
247{
248 return a * b + c * d + e * f;
249}
250
251static inline float scross(float a, float b, float c, float d)
252{
253 return a * b - c * d;
254}
255
256void SMatrix::setTranslate(float dx, float dy)
257{
258 if (dx || dy)
259 {
260 fMat[kMTransX] = dx;
261 fMat[kMTransY] = dy;
262
263 fMat[kMScaleX] = fMat[kMScaleY] = fMat[kMPersp2] = 1;
264 fMat[kMSkewX] = fMat[kMSkewY] = fMat[kMPersp0] = fMat[kMPersp1] = 0;
265
266 this->setTypeMask(kTranslate_Mask | kRectStaysRect_Mask);
267 }
268 else
269 {
270 this->reset();
271 }
272}
273
274void SMatrix::preTranslate(float dx, float dy)
275{
276 if (!dx && !dy)
277 {
278 return;
279 }
280
281 if (this->hasPerspective())
282 {
283 SMatrix m;
284 m.setTranslate(dx, dy);
285 this->preConcat(m);
286 }
287 else
288 {
289 fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
290 fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
291 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
292 }
293}
294
295void SMatrix::preTranslate(int dx, int dy)
296{
297 preTranslate((float)dx, (float)dy);
298}
299
300void SMatrix::postTranslate(float dx, float dy)
301{
302 if (!dx && !dy)
303 {
304 return;
305 }
306
307 if (this->hasPerspective())
308 {
309 SMatrix m;
310 m.setTranslate(dx, dy);
311 this->postConcat(m);
312 }
313 else
314 {
315 fMat[kMTransX] += dx;
316 fMat[kMTransY] += dy;
317 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
318 }
319}
320
321///////////////////////////////////////////////////////////////////////////////
322
323void SMatrix::setScale2(float sx, float sy, float px, float py)
324{
325 if (1 == sx && 1 == sy)
326 {
327 this->reset();
328 }
329 else
330 {
331 fMat[kMScaleX] = sx;
332 fMat[kMScaleY] = sy;
333 fMat[kMTransX] = px - sx * px;
334 fMat[kMTransY] = py - sy * py;
335 fMat[kMPersp2] = 1;
336
337 fMat[kMSkewX] = fMat[kMSkewY] = fMat[kMPersp0] = fMat[kMPersp1] = 0;
338
339 this->setTypeMask(kScale_Mask | kTranslate_Mask | kRectStaysRect_Mask);
340 }
341}
342
343void SMatrix::setScale(float sx, float sy)
344{
345 if (1 == sx && 1 == sy)
346 {
347 this->reset();
348 }
349 else
350 {
351 fMat[kMScaleX] = sx;
352 fMat[kMScaleY] = sy;
353 fMat[kMPersp2] = 1;
354
355 fMat[kMTransX] = fMat[kMTransY] = fMat[kMSkewX] = fMat[kMSkewY] = fMat[kMPersp0] = fMat[kMPersp1] = 0;
356
357 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
358 }
359}
360
361bool SMatrix::setIDiv(int divx, int divy)
362{
363 if (!divx || !divy)
364 {
365 return false;
366 }
367 this->setScale(SFloatInvert(divx), SFloatInvert(divy));
368 return true;
369}
370
371void SMatrix::preScale(float sx, float sy, float px, float py)
372{
373 if (1 == sx && 1 == sy)
374 {
375 return;
376 }
377
378 SMatrix m;
379 m.setScale2(sx, sy, px, py);
380 this->preConcat(m);
381}
382
383void SMatrix::preScale(float sx, float sy)
384{
385 if (1 == sx && 1 == sy)
386 {
387 return;
388 }
389
390 // the assumption is that these multiplies are very cheap, and that
391 // a full concat and/or just computing the matrix type is more expensive.
392 // Also, the fixed-point case checks for overflow, but the float doesn't,
393 // so we can get away with these blind multiplies.
394
395 fMat[kMScaleX] *= sx;
396 fMat[kMSkewY] *= sx;
397 fMat[kMPersp0] *= sx;
398
399 fMat[kMSkewX] *= sy;
400 fMat[kMScaleY] *= sy;
401 fMat[kMPersp1] *= sy;
402
403 this->orTypeMask(kScale_Mask);
404}
405
406void SMatrix::postTranslate(int dx, int dy)
407{
408 postTranslate((float)dx, (float)dy);
409}
410
411void SMatrix::postScale(float sx, float sy, float px, float py)
412{
413 if (1 == sx && 1 == sy)
414 {
415 return;
416 }
417 SMatrix m;
418 m.setScale2(sx, sy, px, py);
419 this->postConcat(m);
420}
421
422void SMatrix::postScale(float sx, float sy)
423{
424 if (1 == sx && 1 == sy)
425 {
426 return;
427 }
428 SMatrix m;
429 m.setScale(sx, sy);
430 this->postConcat(m);
431}
432
433// this guy perhaps can go away, if we have a fract/high-precision way to
434// scale matrices
435bool SMatrix::postIDiv(int divx, int divy)
436{
437 if (divx == 0 || divy == 0)
438 {
439 return false;
440 }
441
442 const float invX = 1.f / divx;
443 const float invY = 1.f / divy;
444
445 fMat[kMScaleX] *= invX;
446 fMat[kMSkewX] *= invX;
447 fMat[kMTransX] *= invX;
448
449 fMat[kMScaleY] *= invY;
450 fMat[kMSkewY] *= invY;
451 fMat[kMTransY] *= invY;
452
453 this->setTypeMask(kUnknown_Mask);
454 return true;
455}
456
457////////////////////////////////////////////////////////////////////////////////////
458
459void SMatrix::setSinCos(float sinV, float cosV, float px, float py)
460{
461 const float oneMinusCosV = 1 - cosV;
462
463 fMat[kMScaleX] = cosV;
464 fMat[kMSkewX] = -sinV;
465 fMat[kMTransX] = sdot(sinV, py, oneMinusCosV, px);
466
467 fMat[kMSkewY] = sinV;
468 fMat[kMScaleY] = cosV;
469 fMat[kMTransY] = sdot(-sinV, px, oneMinusCosV, py);
470
471 fMat[kMPersp0] = fMat[kMPersp1] = 0;
472 fMat[kMPersp2] = 1;
473
474 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
475}
476
477float SMatrix::SFloatSinCos(float radians, float *cosValue)
478{
479 float sinValue = sk_float_sin(radians);
480
481 if (cosValue)
482 {
483 *cosValue = sk_float_cos(radians);
484 if (SFloatNearlyZero(*cosValue))
485 {
486 *cosValue = 0;
487 }
488 }
489
490 if (SFloatNearlyZero(sinValue))
491 {
492 sinValue = 0;
493 }
494 return sinValue;
495}
496
497void SMatrix::setSinCos(float sinV, float cosV)
498{
499 fMat[kMScaleX] = cosV;
500 fMat[kMSkewX] = -sinV;
501 fMat[kMTransX] = 0;
502
503 fMat[kMSkewY] = sinV;
504 fMat[kMScaleY] = cosV;
505 fMat[kMTransY] = 0;
506
507 fMat[kMPersp0] = fMat[kMPersp1] = 0;
508 fMat[kMPersp2] = 1;
509
510 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
511}
512
513void SMatrix::setRotate2(float degrees, float px, float py)
514{
515 float sinV, cosV;
516 sinV = SFloatSinCos(SkDegreesToRadians(degrees), &cosV);
517 this->setSinCos(sinV, cosV, px, py);
518}
519
520void SMatrix::setRotate(float degrees)
521{
522 float sinV, cosV;
523 sinV = SFloatSinCos(SkDegreesToRadians(degrees), &cosV);
524 this->setSinCos(sinV, cosV);
525}
526
527void SMatrix::preRotate(float degrees, float px, float py)
528{
529 SMatrix m;
530 m.setRotate2(degrees, px, py);
531 this->preConcat(m);
532}
533
534void SMatrix::preRotate(float degrees)
535{
536 SMatrix m;
537 m.setRotate(degrees);
538 this->preConcat(m);
539}
540
541void SMatrix::postRotate(float degrees, float px, float py)
542{
543 SMatrix m;
544 m.setRotate2(degrees, px, py);
545 this->postConcat(m);
546}
547
548void SMatrix::postRotate(float degrees)
549{
550 SMatrix m;
551 m.setRotate(degrees);
552 this->postConcat(m);
553}
554
555////////////////////////////////////////////////////////////////////////////////////
556
557void SMatrix::setSkew2(float sx, float sy, float px, float py)
558{
559 fMat[kMScaleX] = 1;
560 fMat[kMSkewX] = sx;
561 fMat[kMTransX] = -sx * py;
562
563 fMat[kMSkewY] = sy;
564 fMat[kMScaleY] = 1;
565 fMat[kMTransY] = -sy * px;
566
567 fMat[kMPersp0] = fMat[kMPersp1] = 0;
568 fMat[kMPersp2] = 1;
569
570 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
571}
572
573void SMatrix::setSkew(float sx, float sy)
574{
575 fMat[kMScaleX] = 1;
576 fMat[kMSkewX] = sx;
577 fMat[kMTransX] = 0;
578
579 fMat[kMSkewY] = sy;
580 fMat[kMScaleY] = 1;
581 fMat[kMTransY] = 0;
582
583 fMat[kMPersp0] = fMat[kMPersp1] = 0;
584 fMat[kMPersp2] = 1;
585
586 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
587}
588
589void SMatrix::preSkew(float sx, float sy, float px, float py)
590{
591 SMatrix m;
592 m.setSkew2(sx, sy, px, py);
593 this->preConcat(m);
594}
595
596void SMatrix::preSkew(float sx, float sy)
597{
598 SMatrix m;
599 m.setSkew(sx, sy);
600 this->preConcat(m);
601}
602
603void SMatrix::postSkew(float sx, float sy, float px, float py)
604{
605 SMatrix m;
606 m.setSkew2(sx, sy, px, py);
607 this->postConcat(m);
608}
609
610void SMatrix::postSkew(float sx, float sy)
611{
612 SMatrix m;
613 m.setSkew(sx, sy);
614 this->postConcat(m);
615}
616
617///////////////////////////////////////////////////////////////////////////////
618
619bool SMatrix::setRectToRect(const SRect &src, const SRect &dst, ScaleToFit align)
620{
621 if (src.isEmpty())
622 {
623 this->reset();
624 return false;
625 }
626
627 if (dst.isEmpty())
628 {
629 memset(fMat, 0, 8 * sizeof(float));
630 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
631 }
632 else
633 {
634 float tx, sx = dst.width() / src.width();
635 float ty, sy = dst.height() / src.height();
636 bool xLarger = false;
637
638 if (align != kFill_ScaleToFit)
639 {
640 if (sx > sy)
641 {
642 xLarger = true;
643 sx = sy;
644 }
645 else
646 {
647 sy = sx;
648 }
649 }
650
651 tx = dst.fLeft - src.fLeft * sx;
652 ty = dst.fTop - src.fTop * sy;
653 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit)
654 {
655 float diff;
656
657 if (xLarger)
658 {
659 diff = dst.width() - src.width() * sy;
660 }
661 else
662 {
663 diff = dst.height() - src.height() * sy;
664 }
665
666 if (align == kCenter_ScaleToFit)
667 {
668 diff = SFloatHalf(diff);
669 }
670
671 if (xLarger)
672 {
673 tx += diff;
674 }
675 else
676 {
677 ty += diff;
678 }
679 }
680
681 fMat[kMScaleX] = sx;
682 fMat[kMScaleY] = sy;
683 fMat[kMTransX] = tx;
684 fMat[kMTransY] = ty;
685 fMat[kMSkewX] = fMat[kMSkewY] = fMat[kMPersp0] = fMat[kMPersp1] = 0;
686
687 unsigned mask = kRectStaysRect_Mask;
688 if (sx != 1 || sy != 1)
689 {
690 mask |= kScale_Mask;
691 }
692 if (tx || ty)
693 {
694 mask |= kTranslate_Mask;
695 }
696 this->setTypeMask(mask);
697 }
698 // shared cleanup
699 fMat[kMPersp2] = 1;
700 return true;
701}
702
703///////////////////////////////////////////////////////////////////////////////
704
705static inline float muladdmul(float a, float b, float c, float d)
706{
707 return SkDoubleToFloat((double)a * b + (double)c * d);
708}
709
710static inline float rowcol3(const float row[], const float col[])
711{
712 return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
713}
714
715static void normalize_perspective(float mat[9])
716{
717 if (SFloatAbs(mat[kMPersp2]) > 1)
718 {
719 for (int i = 0; i < 9; i++)
720 mat[i] = SFloatHalf(mat[i]);
721 }
722}
723
724void SMatrix::setConcat(const SMatrix &a, const SMatrix &b)
725{
726 TypeMask aType = a.getPerspectiveTypeMaskOnly();
727 TypeMask bType = b.getPerspectiveTypeMaskOnly();
728
729 if (a.isTriviallyIdentity())
730 {
731 *this = b;
732 }
733 else if (b.isTriviallyIdentity())
734 {
735 *this = a;
736 }
737 else
738 {
739 SMatrix tmp;
740
741 if ((aType | bType) & kPerspective_Mask)
742 {
743 tmp.fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
744 tmp.fMat[kMSkewX] = rowcol3(&a.fMat[0], &b.fMat[1]);
745 tmp.fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
746 tmp.fMat[kMSkewY] = rowcol3(&a.fMat[3], &b.fMat[0]);
747 tmp.fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
748 tmp.fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
749 tmp.fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
750 tmp.fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
751 tmp.fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
752
753 normalize_perspective(tmp.fMat);
754 tmp.setTypeMask(kUnknown_Mask);
755 }
756 else
757 { // not perspective
758 tmp.fMat[kMScaleX] = muladdmul(a.fMat[kMScaleX], b.fMat[kMScaleX], a.fMat[kMSkewX], b.fMat[kMSkewY]);
759
760 tmp.fMat[kMSkewX] = muladdmul(a.fMat[kMScaleX], b.fMat[kMSkewX], a.fMat[kMSkewX], b.fMat[kMScaleY]);
761
762 tmp.fMat[kMTransX] = muladdmul(a.fMat[kMScaleX], b.fMat[kMTransX], a.fMat[kMSkewX], b.fMat[kMTransY]);
763
764 tmp.fMat[kMTransX] += a.fMat[kMTransX];
765
766 tmp.fMat[kMSkewY] = muladdmul(a.fMat[kMSkewY], b.fMat[kMScaleX], a.fMat[kMScaleY], b.fMat[kMSkewY]);
767
768 tmp.fMat[kMScaleY] = muladdmul(a.fMat[kMSkewY], b.fMat[kMSkewX], a.fMat[kMScaleY], b.fMat[kMScaleY]);
769
770 tmp.fMat[kMTransY] = muladdmul(a.fMat[kMSkewY], b.fMat[kMTransX], a.fMat[kMScaleY], b.fMat[kMTransY]);
771
772 tmp.fMat[kMTransY] += a.fMat[kMTransY];
773 tmp.fMat[kMPersp0] = tmp.fMat[kMPersp1] = 0;
774 tmp.fMat[kMPersp2] = 1;
775 // SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
776 // SASSERT(!(tmp.getType() & kPerspective_Mask));
777 tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
778 }
779 *this = tmp;
780 }
781}
782
784{
785 // check for identity first, so we don't do a needless copy of ourselves
786 // to ourselves inside setConcat()
787 if (!mat.isIdentity())
788 {
789 this->setConcat(*this, mat);
790 }
791}
792
794{
795 // check for identity first, so we don't do a needless copy of ourselves
796 // to ourselves inside setConcat()
797 if (!mat.isIdentity())
798 {
799 this->setConcat(mat, *this);
800 }
801}
802
803///////////////////////////////////////////////////////////////////////////////
804
805/* Matrix inversion is very expensive, but also the place where keeping
806 precision may be most important (here and matrix concat). Hence to avoid
807 bitmap blitting artifacts when walking the inverse, we use doubles for
808 the intermediate math, even though we know that is more expensive.
809 */
810
811static inline float scross_dscale(float a, float b, float c, float d, double scale)
812{
813 return SkDoubleToScalar(scross(a, b, c, d) * scale);
814}
815
816static inline double dcross(double a, double b, double c, double d)
817{
818 return a * b - c * d;
819}
820
821static inline float dcross_dscale(double a, double b, double c, double d, double scale)
822{
823 return SkDoubleToScalar(dcross(a, b, c, d) * scale);
824}
825
826static double sk_inv_determinant(const float mat[9], int isPerspective)
827{
828 double det;
829
830 if (isPerspective)
831 {
832 det = mat[kMScaleX] * dcross(mat[kMScaleY], mat[kMPersp2], mat[kMTransY], mat[kMPersp1]) + mat[kMSkewX] * dcross(mat[kMTransY], mat[kMPersp0], mat[kMSkewY], mat[kMPersp2]) + mat[kMTransX] * dcross(mat[kMSkewY], mat[kMPersp1], mat[kMScaleY], mat[kMPersp0]);
833 }
834 else
835 {
836 det = dcross(mat[kMScaleX], mat[kMScaleY], mat[kMSkewX], mat[kMSkewY]);
837 }
838
839 // Since the determinant is on the order of the cube of the matrix members,
840 // compare to the cube of the default nearly-zero constant (although an
841 // estimate of the condition number would be better if it wasn't so expensive).
842 if (SFloatNearlyZero((float)det, SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero))
843 {
844 return 0;
845 }
846 return 1.0 / det;
847}
848
849void SMatrix::SetAffineIdentity(float affine[6])
850{
851 affine[kAScaleX] = 1;
852 affine[kASkewY] = 0;
853 affine[kASkewX] = 0;
854 affine[kAScaleY] = 1;
855 affine[kATransX] = 0;
856 affine[kATransY] = 0;
857}
858
859bool SMatrix::asAffine(float affine[6]) const
860{
861 if (this->hasPerspective())
862 {
863 return false;
864 }
865 if (affine)
866 {
867 affine[kAScaleX] = this->fMat[kMScaleX];
868 affine[kASkewY] = this->fMat[kMSkewY];
869 affine[kASkewX] = this->fMat[kMSkewX];
870 affine[kAScaleY] = this->fMat[kMScaleY];
871 affine[kATransX] = this->fMat[kMTransX];
872 affine[kATransY] = this->fMat[kMTransY];
873 }
874 return true;
875}
876
877bool SMatrix::invertNonIdentity(SMatrix *inv) const
878{
879 SASSERT(!this->isIdentity());
880
881 TypeMask mask = this->getType();
882
883 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask)))
884 {
885 bool invertible = true;
886 if (inv)
887 {
888 if (mask & kScale_Mask)
889 {
890 float invX = fMat[kMScaleX];
891 float invY = fMat[kMScaleY];
892 if (0 == invX || 0 == invY)
893 {
894 return false;
895 }
896 invX = SFloatInvert(invX);
897 invY = SFloatInvert(invY);
898
899 // Must be careful when writing to inv, since it may be the
900 // same memory as this.
901
902 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] = inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
903
904 inv->fMat[kMScaleX] = invX;
905 inv->fMat[kMScaleY] = invY;
906 inv->fMat[kMPersp2] = 1;
907 inv->fMat[kMTransX] = -fMat[kMTransX] * invX;
908 inv->fMat[kMTransY] = -fMat[kMTransY] * invY;
909
910 inv->setTypeMask(mask | kRectStaysRect_Mask);
911 }
912 else
913 {
914 // translate only
915 inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
916 }
917 }
918 else
919 { // inv is NULL, just check if we're invertible
920 if (!fMat[kMScaleX] || !fMat[kMScaleY])
921 {
922 invertible = false;
923 }
924 }
925 return invertible;
926 }
927
928 int isPersp = mask & kPerspective_Mask;
929 double scale = sk_inv_determinant(fMat, isPersp);
930
931 if (scale == 0)
932 { // underflow
933 return false;
934 }
935
936 if (inv)
937 {
938 SMatrix tmp;
939 if (inv == this)
940 {
941 inv = &tmp;
942 }
943
944 if (isPersp)
945 {
946 inv->fMat[kMScaleX] = scross_dscale(fMat[kMScaleY], fMat[kMPersp2], fMat[kMTransY], fMat[kMPersp1], scale);
947 inv->fMat[kMSkewX] = scross_dscale(fMat[kMTransX], fMat[kMPersp1], fMat[kMSkewX], fMat[kMPersp2], scale);
948 inv->fMat[kMTransX] = scross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMTransX], fMat[kMScaleY], scale);
949
950 inv->fMat[kMSkewY] = scross_dscale(fMat[kMTransY], fMat[kMPersp0], fMat[kMSkewY], fMat[kMPersp2], scale);
951 inv->fMat[kMScaleY] = scross_dscale(fMat[kMScaleX], fMat[kMPersp2], fMat[kMTransX], fMat[kMPersp0], scale);
952 inv->fMat[kMTransY] = scross_dscale(fMat[kMTransX], fMat[kMSkewY], fMat[kMScaleX], fMat[kMTransY], scale);
953
954 inv->fMat[kMPersp0] = scross_dscale(fMat[kMSkewY], fMat[kMPersp1], fMat[kMScaleY], fMat[kMPersp0], scale);
955 inv->fMat[kMPersp1] = scross_dscale(fMat[kMSkewX], fMat[kMPersp0], fMat[kMScaleX], fMat[kMPersp1], scale);
956 inv->fMat[kMPersp2] = scross_dscale(fMat[kMScaleX], fMat[kMScaleY], fMat[kMSkewX], fMat[kMSkewY], scale);
957 }
958 else
959 { // not perspective
960 inv->fMat[kMScaleX] = SkDoubleToScalar(fMat[kMScaleY] * scale);
961 inv->fMat[kMSkewX] = SkDoubleToScalar(-fMat[kMSkewX] * scale);
962 inv->fMat[kMTransX] = dcross_dscale(fMat[kMSkewX], fMat[kMTransY], fMat[kMScaleY], fMat[kMTransX], scale);
963
964 inv->fMat[kMSkewY] = SkDoubleToScalar(-fMat[kMSkewY] * scale);
965 inv->fMat[kMScaleY] = SkDoubleToScalar(fMat[kMScaleX] * scale);
966 inv->fMat[kMTransY] = dcross_dscale(fMat[kMSkewY], fMat[kMTransX], fMat[kMScaleX], fMat[kMTransY], scale);
967
968 inv->fMat[kMPersp0] = 0;
969 inv->fMat[kMPersp1] = 0;
970 inv->fMat[kMPersp2] = 1;
971 }
972
973 inv->setTypeMask(fTypeMask);
974
975 if (inv == &tmp)
976 {
977 *(SMatrix *)this = tmp;
978 }
979 }
980 return true;
981}
982
983///////////////////////////////////////////////////////////////////////////////
984
985void SMatrix::Identity_pts(const SMatrix &m, SPoint dst[], const SPoint src[], int count)
986{
987 SASSERT(m.getType() == 0);
988
989 if (dst != src && count > 0)
990 memcpy(dst, src, count * sizeof(SPoint));
991}
992
993void SMatrix::Trans_pts(const SMatrix &m, SPoint dst[], const SPoint src[], int count)
994{
995 SASSERT(m.getType() == kTranslate_Mask);
996
997 if (count > 0)
998 {
999 float tx = m.fMat[kMTransX];
1000 float ty = m.fMat[kMTransY];
1001 do
1002 {
1003 dst->fY = src->fY + ty;
1004 dst->fX = src->fX + tx;
1005 src += 1;
1006 dst += 1;
1007 } while (--count);
1008 }
1009}
1010
1011void SMatrix::Scale_pts(const SMatrix &m, SPoint dst[], const SPoint src[], int count)
1012{
1013 SASSERT(m.getType() == kScale_Mask);
1014
1015 if (count > 0)
1016 {
1017 float mx = m.fMat[kMScaleX];
1018 float my = m.fMat[kMScaleY];
1019 do
1020 {
1021 dst->fY = src->fY * my;
1022 dst->fX = src->fX * mx;
1023 src += 1;
1024 dst += 1;
1025 } while (--count);
1026 }
1027}
1028
1029void SMatrix::ScaleTrans_pts(const SMatrix &m, SPoint dst[], const SPoint src[], int count)
1030{
1031 SASSERT(m.getType() == (kScale_Mask | kTranslate_Mask));
1032
1033 if (count > 0)
1034 {
1035 float mx = m.fMat[kMScaleX];
1036 float my = m.fMat[kMScaleY];
1037 float tx = m.fMat[kMTransX];
1038 float ty = m.fMat[kMTransY];
1039 do
1040 {
1041 dst->fY = src->fY * my + ty;
1042 dst->fX = src->fX * mx + tx;
1043 src += 1;
1044 dst += 1;
1045 } while (--count);
1046 }
1047}
1048
1049void SMatrix::Rot_pts(const SMatrix &m, SPoint dst[], const SPoint src[], int count)
1050{
1051 SASSERT((m.getType() & (kPerspective_Mask | kTranslate_Mask)) == 0);
1052
1053 if (count > 0)
1054 {
1055 float mx = m.fMat[kMScaleX];
1056 float my = m.fMat[kMScaleY];
1057 float kx = m.fMat[kMSkewX];
1058 float ky = m.fMat[kMSkewY];
1059 do
1060 {
1061 float sy = src->fY;
1062 float sx = src->fX;
1063 src += 1;
1064 dst->fY = sdot(sx, ky, sy, my);
1065 dst->fX = sdot(sx, mx, sy, kx);
1066 dst += 1;
1067 } while (--count);
1068 }
1069}
1070
1071void SMatrix::RotTrans_pts(const SMatrix &m, SPoint dst[], const SPoint src[], int count)
1072{
1073 SASSERT(!m.hasPerspective());
1074
1075 if (count > 0)
1076 {
1077 float mx = m.fMat[kMScaleX];
1078 float my = m.fMat[kMScaleY];
1079 float kx = m.fMat[kMSkewX];
1080 float ky = m.fMat[kMSkewY];
1081 float tx = m.fMat[kMTransX];
1082 float ty = m.fMat[kMTransY];
1083 do
1084 {
1085 float sy = src->fY;
1086 float sx = src->fX;
1087 src += 1;
1088#ifdef SK_LEGACY_MATRIX_MATH_ORDER
1089 dst->fY = sx * ky + (sy * my + ty);
1090 dst->fX = sx * mx + (sy * kx + tx);
1091#else
1092 dst->fY = sdot(sx, ky, sy, my) + ty;
1093 dst->fX = sdot(sx, mx, sy, kx) + tx;
1094#endif
1095 dst += 1;
1096 } while (--count);
1097 }
1098}
1099
1100void SMatrix::Persp_pts(const SMatrix &m, SPoint dst[], const SPoint src[], int count)
1101{
1102 SASSERT(m.hasPerspective());
1103
1104 if (count > 0)
1105 {
1106 do
1107 {
1108 float sy = src->fY;
1109 float sx = src->fX;
1110 src += 1;
1111
1112 float x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1113 float y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1114#ifdef SK_LEGACY_MATRIX_MATH_ORDER
1115 float z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]);
1116#else
1117 float z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1118#endif
1119 if (z)
1120 {
1121 z = SFloatFastInvert(z);
1122 }
1123
1124 dst->fY = y * z;
1125 dst->fX = x * z;
1126 dst += 1;
1127 } while (--count);
1128 }
1129}
1130
1131const SMatrix::MapPtsProc SMatrix::gMapPtsProcs[] = { SMatrix::Identity_pts, SMatrix::Trans_pts, SMatrix::Scale_pts, SMatrix::ScaleTrans_pts, SMatrix::Rot_pts, SMatrix::RotTrans_pts, SMatrix::Rot_pts, SMatrix::RotTrans_pts,
1132 // repeat the persp proc 8 times
1133 SMatrix::Persp_pts, SMatrix::Persp_pts, SMatrix::Persp_pts, SMatrix::Persp_pts, SMatrix::Persp_pts, SMatrix::Persp_pts, SMatrix::Persp_pts, SMatrix::Persp_pts };
1134
1135void SMatrix::mapPoints(SPoint dst[], const SPoint src[], int count) const
1136{
1137 SASSERT((dst && src && count > 0) || 0 == count);
1138 // no partial overlap
1139 SASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
1140
1141 this->getMapPtsProc()(*this, dst, src, count);
1142}
1143
1144///////////////////////////////////////////////////////////////////////////////
1145
1146static int32_t SkAbs32(int32_t value)
1147{
1148 if (value < 0)
1149 {
1150 value = -value;
1151 }
1152 return value;
1153}
1154
1155void SMatrix::mapHomogeneousPoints(float dst[], const float src[], int count) const
1156{
1157 SASSERT((dst && src && count > 0) || 0 == count);
1158 // no partial overlap
1159 SASSERT(src == dst || SkAbs32((int32_t)(src - dst)) >= 3 * count);
1160
1161 if (count > 0)
1162 {
1163 if (this->isIdentity())
1164 {
1165 memcpy(dst, src, 3 * count * sizeof(float));
1166 return;
1167 }
1168 do
1169 {
1170 float sx = src[0];
1171 float sy = src[1];
1172 float sw = src[2];
1173 src += 3;
1174
1175 float x = sdot(sx, fMat[kMScaleX], sy, fMat[kMSkewX], sw, fMat[kMTransX]);
1176 float y = sdot(sx, fMat[kMSkewY], sy, fMat[kMScaleY], sw, fMat[kMTransY]);
1177 float w = sdot(sx, fMat[kMPersp0], sy, fMat[kMPersp1], sw, fMat[kMPersp2]);
1178
1179 dst[0] = x;
1180 dst[1] = y;
1181 dst[2] = w;
1182 dst += 3;
1183 } while (--count);
1184 }
1185}
1186
1187///////////////////////////////////////////////////////////////////////////////
1188
1189void SMatrix::mapVectors(SPoint dst[], const SPoint src[], int count) const
1190{
1191 if (this->hasPerspective())
1192 {
1193 SPoint origin;
1194
1195 MapXYProc proc = this->getMapXYProc();
1196 proc(*this, 0, 0, &origin);
1197
1198 for (int i = count - 1; i >= 0; --i)
1199 {
1200 SPoint tmp;
1201
1202 proc(*this, src[i].fX, src[i].fY, &tmp);
1203 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1204 }
1205 }
1206 else
1207 {
1208 SMatrix tmp = *this;
1209
1210 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1211 tmp.clearTypeMask(kTranslate_Mask);
1212 tmp.mapPoints(dst, src, count);
1213 }
1214}
1215
1216bool SMatrix::mapRect(SRect *dst, const SRect &src) const
1217{
1218 SASSERT(dst);
1219
1220 if (this->rectStaysRect())
1221 {
1222 this->mapPoints((SPoint *)dst, (const SPoint *)&src, 2);
1223 dst->sort();
1224 return true;
1225 }
1226 else
1227 {
1228 SPoint quad[4];
1229
1230 src.toQuad(quad);
1231 this->mapPoints(quad, quad, 4);
1232 dst->set(quad, 4);
1233 return false;
1234 }
1235}
1236
1237float SMatrix::mapRadius(float radius) const
1238{
1239 SVector2D vec[2];
1240
1241 vec[0].set(radius, 0);
1242 vec[1].set(0, radius);
1243 this->mapVectors(vec, 2);
1244
1245 float d0 = vec[0].length();
1246 float d1 = vec[1].length();
1247
1248 // return geometric mean
1249 return SFloatSqrt(d0 * d1);
1250}
1251
1252///////////////////////////////////////////////////////////////////////////////
1253
1254void SMatrix::Persp_xy(const SMatrix &m, float sx, float sy, SPoint *pt)
1255{
1256 SASSERT(m.hasPerspective());
1257
1258 float x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1259 float y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1260 float z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1261 if (z)
1262 {
1263 z = SFloatFastInvert(z);
1264 }
1265 pt->fX = x * z;
1266 pt->fY = y * z;
1267}
1268
1269void SMatrix::RotTrans_xy(const SMatrix &m, float sx, float sy, SPoint *pt)
1270{
1271 SASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1272
1273#ifdef SK_LEGACY_MATRIX_MATH_ORDER
1274 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1275 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1276#else
1277 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1278 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1279#endif
1280}
1281
1282void SMatrix::Rot_xy(const SMatrix &m, float sx, float sy, SPoint *pt)
1283{
1284 SASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1285 SASSERT(0 == m.fMat[kMTransX]);
1286 SASSERT(0 == m.fMat[kMTransY]);
1287
1288#ifdef SK_LEGACY_MATRIX_MATH_ORDER
1289 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1290 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1291#else
1292 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1293 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1294#endif
1295}
1296
1297void SMatrix::ScaleTrans_xy(const SMatrix &m, float sx, float sy, SPoint *pt)
1298{
1300
1301 pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
1302 pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
1303}
1304
1305void SMatrix::Scale_xy(const SMatrix &m, float sx, float sy, SPoint *pt)
1306{
1308 SASSERT(0 == m.fMat[kMTransX]);
1309 SASSERT(0 == m.fMat[kMTransY]);
1310
1311 pt->fX = sx * m.fMat[kMScaleX];
1312 pt->fY = sy * m.fMat[kMScaleY];
1313}
1314
1315void SMatrix::Trans_xy(const SMatrix &m, float sx, float sy, SPoint *pt)
1316{
1317 SASSERT(m.getType() == kTranslate_Mask);
1318
1319 pt->fX = sx + m.fMat[kMTransX];
1320 pt->fY = sy + m.fMat[kMTransY];
1321}
1322
1323void SMatrix::Identity_xy(const SMatrix &m, float sx, float sy, SPoint *pt)
1324{
1325 SASSERT(0 == m.getType());
1326
1327 pt->fX = sx;
1328 pt->fY = sy;
1329}
1330
1331const SMatrix::MapXYProc SMatrix::gMapXYProcs[] = { SMatrix::Identity_xy, SMatrix::Trans_xy, SMatrix::Scale_xy, SMatrix::ScaleTrans_xy, SMatrix::Rot_xy, SMatrix::RotTrans_xy, SMatrix::Rot_xy, SMatrix::RotTrans_xy,
1332 // repeat the persp proc 8 times
1333 SMatrix::Persp_xy, SMatrix::Persp_xy, SMatrix::Persp_xy, SMatrix::Persp_xy, SMatrix::Persp_xy, SMatrix::Persp_xy, SMatrix::Persp_xy, SMatrix::Persp_xy };
1334
1335///////////////////////////////////////////////////////////////////////////////
1336
1337// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1338#define PerspNearlyZero(x) SFloatNearlyZero(x, (1.0f / (1 << 26)))
1339
1340///////////////////////////////////////////////////////////////////////////////
1341
1342static inline bool checkForZero(float x)
1343{
1344 return x * x == 0;
1345}
1346
1347static inline bool poly_to_point(SPoint *pt, const SPoint poly[], int count)
1348{
1349 float x = 1, y = 1;
1350 SPoint pt1, pt2;
1351
1352 if (count > 1)
1353 {
1354 pt1.fX = poly[1].fX - poly[0].fX;
1355 pt1.fY = poly[1].fY - poly[0].fY;
1356 y = SPoint::Length(pt1.fX, pt1.fY);
1357 if (checkForZero(y))
1358 {
1359 return false;
1360 }
1361 switch (count)
1362 {
1363 case 2:
1364 break;
1365 case 3:
1366 pt2.fX = poly[0].fY - poly[2].fY;
1367 pt2.fY = poly[2].fX - poly[0].fX;
1368 goto CALC_X;
1369 default:
1370 pt2.fX = poly[0].fY - poly[3].fY;
1371 pt2.fY = poly[3].fX - poly[0].fX;
1372 CALC_X:
1373 x = sdot(pt1.fX, pt2.fX, pt1.fY, pt2.fY) / y;
1374 break;
1375 }
1376 }
1377 pt->set(x, y);
1378 return true;
1379}
1380
1381bool SMatrix::Poly2Proc(const SPoint srcPt[], SMatrix *dst, const SPoint &scale)
1382{
1383 float invScale = 1 / scale.fY;
1384
1385 dst->fMat[kMScaleX] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1386 dst->fMat[kMSkewY] = (srcPt[0].fX - srcPt[1].fX) * invScale;
1387 dst->fMat[kMPersp0] = 0;
1388 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1389 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1390 dst->fMat[kMPersp1] = 0;
1391 dst->fMat[kMTransX] = srcPt[0].fX;
1392 dst->fMat[kMTransY] = srcPt[0].fY;
1393 dst->fMat[kMPersp2] = 1;
1394 dst->setTypeMask(kUnknown_Mask);
1395 return true;
1396}
1397
1398bool SMatrix::Poly3Proc(const SPoint srcPt[], SMatrix *dst, const SPoint &scale)
1399{
1400 float invScale = 1 / scale.fX;
1401 dst->fMat[kMScaleX] = (srcPt[2].fX - srcPt[0].fX) * invScale;
1402 dst->fMat[kMSkewY] = (srcPt[2].fY - srcPt[0].fY) * invScale;
1403 dst->fMat[kMPersp0] = 0;
1404
1405 invScale = 1 / scale.fY;
1406 dst->fMat[kMSkewX] = (srcPt[1].fX - srcPt[0].fX) * invScale;
1407 dst->fMat[kMScaleY] = (srcPt[1].fY - srcPt[0].fY) * invScale;
1408 dst->fMat[kMPersp1] = 0;
1409
1410 dst->fMat[kMTransX] = srcPt[0].fX;
1411 dst->fMat[kMTransY] = srcPt[0].fY;
1412 dst->fMat[kMPersp2] = 1;
1413 dst->setTypeMask(kUnknown_Mask);
1414 return true;
1415}
1416
1417bool SMatrix::Poly4Proc(const SPoint srcPt[], SMatrix *dst, const SPoint &scale)
1418{
1419 float a1, a2;
1420 float x0, y0, x1, y1, x2, y2;
1421
1422 x0 = srcPt[2].fX - srcPt[0].fX;
1423 y0 = srcPt[2].fY - srcPt[0].fY;
1424 x1 = srcPt[2].fX - srcPt[1].fX;
1425 y1 = srcPt[2].fY - srcPt[1].fY;
1426 x2 = srcPt[2].fX - srcPt[3].fX;
1427 y2 = srcPt[2].fY - srcPt[3].fY;
1428
1429 /* check if abs(x2) > abs(y2) */
1430 if (x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2)
1431 {
1432 float denom = SFloatMulDiv(x1, y2, x2) - y1;
1433 if (checkForZero(denom))
1434 {
1435 return false;
1436 }
1437 a1 = (SFloatMulDiv(x0 - x1, y2, x2) - y0 + y1) / denom;
1438 }
1439 else
1440 {
1441 float denom = x1 - SFloatMulDiv(y1, x2, y2);
1442 if (checkForZero(denom))
1443 {
1444 return false;
1445 }
1446 a1 = (x0 - x1 - SFloatMulDiv(y0 - y1, x2, y2)) / denom;
1447 }
1448
1449 /* check if abs(x1) > abs(y1) */
1450 if (x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1)
1451 {
1452 float denom = y2 - SFloatMulDiv(x2, y1, x1);
1453 if (checkForZero(denom))
1454 {
1455 return false;
1456 }
1457 a2 = (y0 - y2 - SFloatMulDiv(x0 - x2, y1, x1)) / denom;
1458 }
1459 else
1460 {
1461 float denom = SFloatMulDiv(y2, x1, y1) - x2;
1462 if (checkForZero(denom))
1463 {
1464 return false;
1465 }
1466 a2 = (SFloatMulDiv(y0 - y2, x1, y1) - x0 + x2) / denom;
1467 }
1468
1469 float invScale = SFloatInvert(scale.fX);
1470 dst->fMat[kMScaleX] = (a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX) * invScale;
1471 dst->fMat[kMSkewY] = (a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY) * invScale;
1472 dst->fMat[kMPersp0] = a2 * invScale;
1473
1474 invScale = SFloatInvert(scale.fY);
1475 dst->fMat[kMSkewX] = (a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX) * invScale;
1476 dst->fMat[kMScaleY] = (a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY) * invScale;
1477 dst->fMat[kMPersp1] = a1 * invScale;
1478
1479 dst->fMat[kMTransX] = srcPt[0].fX;
1480 dst->fMat[kMTransY] = srcPt[0].fY;
1481 dst->fMat[kMPersp2] = 1;
1482 dst->setTypeMask(kUnknown_Mask);
1483 return true;
1484}
1485
1486typedef bool (*PolyMapProc)(const SPoint[], SMatrix *, const SPoint &);
1487
1488/* Taken from Rob Johnson's original sample code in QuickDraw GX
1489 */
1490bool SMatrix::setPolyToPoly(const SPoint src[], const SPoint dst[], int count)
1491{
1492 if ((unsigned)count > 4)
1493 {
1494 // SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1495 return false;
1496 }
1497
1498 if (0 == count)
1499 {
1500 this->reset();
1501 return true;
1502 }
1503 if (1 == count)
1504 {
1505 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1506 return true;
1507 }
1508
1509 SPoint scale;
1510 if (!poly_to_point(&scale, src, count) || SFloatNearlyZero(scale.fX) || SFloatNearlyZero(scale.fY))
1511 {
1512 return false;
1513 }
1514
1515 static const PolyMapProc gPolyMapProcs[] = { SMatrix::Poly2Proc, SMatrix::Poly3Proc, SMatrix::Poly4Proc };
1516 PolyMapProc proc = gPolyMapProcs[count - 2];
1517
1518 SMatrix tempMap, result;
1519 tempMap.setTypeMask(kUnknown_Mask);
1520
1521 if (!proc(src, &tempMap, scale))
1522 {
1523 return false;
1524 }
1525 if (!tempMap.invert(&result))
1526 {
1527 return false;
1528 }
1529 if (!proc(dst, &tempMap, scale))
1530 {
1531 return false;
1532 }
1533 this->setConcat(tempMap, result);
1534 return true;
1535}
1536
1537///////////////////////////////////////////////////////////////////////////////
1538
1539enum MinMaxOrBoth
1540{
1541 kMin_MinMaxOrBoth,
1542 kMax_MinMaxOrBoth,
1543 kBoth_MinMaxOrBoth
1544};
1545
1546template <MinMaxOrBoth MIN_MAX_OR_BOTH>
1547bool get_scale_factor(SMatrix::TypeMask typeMask, const float m[9], float results[/*1 or 2*/])
1548{
1549 if (typeMask & SMatrix::kPerspective_Mask)
1550 {
1551 return false;
1552 }
1553 if (SMatrix::kIdentity_Mask == typeMask)
1554 {
1555 results[0] = SK_Scalar1;
1556 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1557 {
1558 results[1] = SK_Scalar1;
1559 }
1560 return true;
1561 }
1562 if (!(typeMask & SMatrix::kAffine_Mask))
1563 {
1564 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1565 {
1566 results[0] = SkMinScalar(SFloatAbs(m[kMScaleX]), SFloatAbs(m[kMScaleY]));
1567 }
1568 else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1569 {
1570 results[0] = SkMaxScalar(SFloatAbs(m[kMScaleX]), SFloatAbs(m[kMScaleY]));
1571 }
1572 else
1573 {
1574 results[0] = SFloatAbs(m[kMScaleX]);
1575 results[1] = SFloatAbs(m[kMScaleY]);
1576 if (results[0] > results[1])
1577 {
1578 STSwap(results[0], results[1]);
1579 }
1580 }
1581 return true;
1582 }
1583 // ignore the translation part of the matrix, just look at 2x2 portion.
1584 // compute singular values, take largest or smallest abs value.
1585 // [a b; b c] = A^T*A
1586 float a = sdot(m[kMScaleX], m[kMScaleX], m[kMSkewY], m[kMSkewY]);
1587 float b = sdot(m[kMScaleX], m[kMSkewX], m[kMScaleY], m[kMSkewY]);
1588 float c = sdot(m[kMSkewX], m[kMSkewX], m[kMScaleY], m[kMScaleY]);
1589 // eigenvalues of A^T*A are the squared singular values of A.
1590 // characteristic equation is det((A^T*A) - l*I) = 0
1591 // l^2 - (a + c)l + (ac-b^2)
1592 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1593 // and roots are guaranteed to be pos and real).
1594 float bSqd = b * b;
1595 // if upper left 2x2 is orthogonal save some math
1596 if (bSqd <= SK_ScalarNearlyZero * SK_ScalarNearlyZero)
1597 {
1598 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1599 {
1600 results[0] = SkMinScalar(a, c);
1601 }
1602 else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1603 {
1604 results[0] = SkMaxScalar(a, c);
1605 }
1606 else
1607 {
1608 results[0] = a;
1609 results[1] = c;
1610 if (results[0] > results[1])
1611 {
1612 STSwap(results[0], results[1]);
1613 }
1614 }
1615 }
1616 else
1617 {
1618 float aminusc = a - c;
1619 float apluscdiv2 = SFloatHalf(a + c);
1620 float x = SFloatHalf(SFloatSqrt(aminusc * aminusc + 4 * bSqd));
1621 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1622 {
1623 results[0] = apluscdiv2 - x;
1624 }
1625 else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1626 {
1627 results[0] = apluscdiv2 + x;
1628 }
1629 else
1630 {
1631 results[0] = apluscdiv2 - x;
1632 results[1] = apluscdiv2 + x;
1633 }
1634 }
1635 SASSERT(results[0] >= 0);
1636 results[0] = SFloatSqrt(results[0]);
1637 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH)
1638 {
1639 SASSERT(results[1] >= 0);
1640 results[1] = SFloatSqrt(results[1]);
1641 }
1642 return true;
1643}
1644
1646{
1647 float factor;
1648 if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor))
1649 {
1650 return factor;
1651 }
1652 else
1653 {
1654 return -1;
1655 }
1656}
1657
1659{
1660 float factor;
1661 if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor))
1662 {
1663 return factor;
1664 }
1665 else
1666 {
1667 return -1;
1668 }
1669}
1670
1671bool SMatrix::getMinMaxScales(float scaleFactors[2]) const
1672{
1673 return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1674}
1675
1676namespace
1677{
1678
1679struct PODMatrix
1680{
1681 float matrix[9];
1682 uint32_t typemask;
1683
1684 const SMatrix &asSkMatrix() const
1685 {
1686 return *reinterpret_cast<const SMatrix *>(this);
1687 }
1688};
1689} // namespace
1690
1692{
1693 static const PODMatrix identity = { { SK_Scalar1, 0, 0, 0, SK_Scalar1, 0, 0, 0, SK_Scalar1 }, kIdentity_Mask | kRectStaysRect_Mask };
1694 SASSERT(identity.asSkMatrix().isIdentity());
1695 return identity.asSkMatrix();
1696}
1697
1699{
1700
1701 static const PODMatrix invalid = { { SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax }, kTranslate_Mask | kScale_Mask | kAffine_Mask | kPerspective_Mask };
1702 return invalid.asSkMatrix();
1703}
1704
1705///////////////////////////////////////////////////////////////////////////////
1706
1707/*!
1708\fn SMatrix &SMatrix::operator *=(const SMatrix &matrix)
1709\overload
1710
1711Returns the result of multiplying this matrix by the given \a
1712matrix.
1713*/
1714
1716{
1717 postConcat(src);
1718 return *this;
1719}
1720
1721/*!
1722\fn SMatrix SMatrix::operator *(const SMatrix &matrix) const
1723
1724Returns the result of multiplying this matrix by the given \a
1725matrix.
1726
1727Note that matrix multiplication is not commutative, i.e. a*b !=
1728b*a.
1729*/
1730
1732{
1733 SMatrix ret(*this);
1734 ret.postConcat(m);
1735 return ret;
1736}
1737
1738/*!
1739Assigns the given \a matrix's values to this matrix.
1740*/
1742{
1743 memcpy(fMat, src.fMat, sizeof(fMat));
1744 fTypeMask = src.fTypeMask;
1745 return *this;
1746}
1747
1748void SMatrix::setTypeMask(int mask)
1749{
1750 // allow kUnknown or a valid mask
1751 SASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask || ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask) == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
1752 fTypeMask = SiToU8(mask);
1753}
1754
1755void SMatrix::orTypeMask(int mask)
1756{
1757 SASSERT((mask & kORableMasks) == mask);
1758 fTypeMask = SiToU8(fTypeMask | mask);
1759}
1760
1761void SMatrix::setMatrix(const float fMat[9], int matType)
1762{
1763 memcpy(this->fMat, fMat, sizeof(this->fMat));
1764 this->setTypeMask(matType);
1765}
1766
1768{
1769 this->reset();
1770}
1771
1772IxForm *SMatrix::Data() const
1773{
1774 return (IxForm *)this;
1775}
1776
1778{
1779 return this->getType() == 0;
1780}
1781
1782SNSEND
The SMatrix class holds a 3x3 matrix for transforming coordinates. SMatrix does not have a constructo...
Definition SMatrix.h:22
bool getMinMaxScales(float scaleFactors[2]) const
Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max is scale...
Definition SMatrix.cpp:1671
float getMinScale() const
Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper left 2x2....
Definition SMatrix.cpp:1645
void postRotate(float degrees, float px, float py)
Post-concats the matrix with the specified rotation.
Definition SMatrix.cpp:541
bool invert(SMatrix *inverse) const
If this matrix can be inverted, return true and if inverse is not null, set inverse to be the inverse...
Definition SMatrix.h:600
void postTranslate(float dx, float dy)
Post-concats the matrix with the specified translation.
Definition SMatrix.cpp:300
float mapRadius(float radius) const
Return the mean radius of a circle after it has been mapped by this matrix. NOTE: in perspective this...
Definition SMatrix.cpp:1237
bool asAffine(float affine[6]) const
Fills the passed array with the affine values in column major order. If the matrix is a perspective t...
Definition SMatrix.cpp:859
SMatrix operator*(const SMatrix &src) const
Multiplies the matrix by another matrix.
Definition SMatrix.cpp:1731
static void SetAffineIdentity(float affine[6])
Fills the passed array with affine identity values in column major order.
Definition SMatrix.cpp:849
bool setIDiv(int divx, int divy)
Sets the matrix to scale by 1/divx and 1/divy.
Definition SMatrix.cpp:361
SMatrix & operator*=(const SMatrix &src)
Multiplies the matrix by another matrix.
Definition SMatrix.cpp:1715
static const SMatrix & InvalidMatrix()
Return a reference to a const matrix that is "invalid", one that could never be used.
Definition SMatrix.cpp:1698
void setSkew(float kx, float ky) OVERRIDE
Sets the matrix to a skew.
Definition SMatrix.cpp:573
void mapPoints(SPoint dst[], const SPoint src[], int count) const
Apply this matrix to the array of points specified by src, and write the transformed points into the ...
Definition SMatrix.cpp:1135
void preScale(float sx, float sy, float px, float py)
Pre-concats the matrix with the specified scale.
Definition SMatrix.cpp:371
bool preservesRightAngles(float tol=((1.0f)/(1<< 12))) const
Checks if the matrix contains only translation, rotation/reflection, or scale (non-uniform scale is a...
Definition SMatrix.cpp:205
bool hasPerspective() const
Checks if the matrix contains perspective elements.
Definition SMatrix.h:271
void preTranslate(float dx, float dy)
Pre-concats the matrix with the specified translation.
Definition SMatrix.cpp:274
float getMaxScale() const
Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper left 2x2....
Definition SMatrix.cpp:1658
void setRotate2(float degrees, float px, float py) OVERRIDE
Sets the matrix to a rotation with pivot point.
Definition SMatrix.cpp:513
IxForm * Data() SCONST OVERRIDE
Returns a pointer to the matrix data.
Definition SMatrix.cpp:1772
void setMatrix(const float data[9], int matType=kUnknown_Mask)
Sets the matrix to the specified data array.
Definition SMatrix.cpp:1761
static const SMatrix & I()
Return a reference to a const identity matrix.
Definition SMatrix.cpp:1691
void preConcat(const SMatrix &other)
Pre-concats the matrix with the specified matrix.
Definition SMatrix.cpp:783
bool mapRect(SRect *dst, const SRect &src) const
Apply this matrix to the src rectangle, and write the transformed rectangle into dst....
Definition SMatrix.cpp:1216
void setSkew2(float kx, float ky, float px, float py) OVERRIDE
Sets the matrix to a skew with pivot point.
Definition SMatrix.cpp:557
bool setPolyToPoly(const SPoint src[], const SPoint dst[], int count)
Set the matrix such that the specified src points would map to the specified dst points....
Definition SMatrix.cpp:1490
void reset() OVERRIDE
Resets the matrix to the identity matrix.
Definition SMatrix.cpp:46
TypeMask getType() const
Returns a bitfield describing the transformations the matrix may perform. The bitfield is computed co...
Definition SMatrix.h:225
void preRotate(float degrees, float px, float py)
Pre-concats the matrix with the specified rotation.
Definition SMatrix.cpp:527
MapPtsProc getMapPtsProc() const
Get the appropriate MapPtsProc for this matrix.
Definition SMatrix.h:825
void setConcat(const SMatrix &a, const SMatrix &b)
Sets the matrix to the concatenation of the two specified matrices.
Definition SMatrix.cpp:724
bool rectStaysRect() const
Returns true if the matrix will map a rectangle to another rectangle. This can be true if the matrix ...
Definition SMatrix.h:249
ScaleToFit
Enum for scale-to-fit options.
Definition SMatrix.h:544
@ kEnd_ScaleToFit
Definition SMatrix.h:569
@ kFill_ScaleToFit
Definition SMatrix.h:549
@ kCenter_ScaleToFit
Definition SMatrix.h:562
bool postIDiv(int divx, int divy)
Post-concats the matrix by dividing it by the specified integers.
Definition SMatrix.cpp:435
void preSkew(float kx, float ky, float px, float py)
Pre-concats the matrix with the specified skew.
Definition SMatrix.cpp:589
SMatrix & scale(float sx, float sy)
Post-concats the matrix with a scale.
Definition SMatrix.h:98
BOOL isIdentity() SCONST OVERRIDE
Checks if the matrix is the identity matrix.
Definition SMatrix.cpp:1777
SMatrix & operator=(const SMatrix &src)
Assignment operator.
Definition SMatrix.cpp:1741
void postSkew(float kx, float ky, float px, float py)
Post-concats the matrix with the specified skew.
Definition SMatrix.cpp:603
void setSinCos(float sinValue, float cosValue, float px, float py)
Sets the matrix to rotate by the specified sine and cosine values, with a pivot point at (px,...
Definition SMatrix.cpp:459
void postConcat(const SMatrix &other)
Post-concats the matrix with the specified matrix.
Definition SMatrix.cpp:793
void setRotate(float degrees) OVERRIDE
Sets the matrix to a rotation.
Definition SMatrix.cpp:520
bool isSimilarity(float tol=((1.0f)/(1<< 12))) const
Checks if the matrix contains only translation, rotation/reflection, or uniform scale....
Definition SMatrix.cpp:172
void setTranslate(float dx, float dy) OVERRIDE
Sets the matrix to a translation.
Definition SMatrix.cpp:256
bool setRectToRect(const SRect &src, const SRect &dst, ScaleToFit stf)
Set the matrix to the scale and translate values that map the source rectangle to the destination rec...
Definition SMatrix.cpp:619
MapXYProc getMapXYProc() const
Get the appropriate MapXYProc for this matrix.
Definition SMatrix.h:799
void mapHomogeneousPoints(float dst[], const float src[], int count) const
Apply this matrix to the array of homogeneous points, specified by src, where a homogeneous point is ...
Definition SMatrix.cpp:1155
void postScale(float sx, float sy, float px, float py)
Post-concats the matrix with the specified scale.
Definition SMatrix.cpp:411
TypeMask
Enum of bit fields for the mask returned by getType(). Use this to identify the complexity of the mat...
Definition SMatrix.h:210
@ kAffine_Mask
Set if the matrix skews or rotates.
Definition SMatrix.h:214
@ kPerspective_Mask
Set if the matrix is in perspective.
Definition SMatrix.h:215
@ kScale_Mask
Set if the matrix has X or Y scale.
Definition SMatrix.h:213
@ kIdentity_Mask
Set if the matrix is identity.
Definition SMatrix.h:211
@ kTranslate_Mask
Set if the matrix has translation.
Definition SMatrix.h:212
void(* MapXYProc)(const SMatrix &mat, float x, float y, SPoint *result)
Function pointer type for mapping a single point (x, y) to a transformed point.
Definition SMatrix.h:782
void setScale(float sx, float sy) OVERRIDE
Sets the matrix to a scale.
Definition SMatrix.cpp:343
void setIdentity() OVERRIDE
Sets the matrix to the identity matrix.
Definition SMatrix.cpp:1767
friend bool operator==(const SMatrix &a, const SMatrix &b)
Equality operator.
Definition SMatrix.cpp:153
void mapVectors(SVector2D dst[], const SVector2D src[], int count) const
Apply this matrix to the array of vectors specified by src, and write the transformed vectors into th...
Definition SMatrix.cpp:1189
void(* MapPtsProc)(const SMatrix &mat, SPoint dst[], const SPoint src[], int count)
Function pointer type for mapping an array of points.
Definition SMatrix.h:808
SMatrix()
Default constructor, initializes the matrix to identity.
Definition SMatrix.h:27
void setScale2(float sx, float sy, float px, float py) OVERRIDE
Sets the matrix to a scale with pivot point.
Definition SMatrix.cpp:323
float fMat[kMCount]
Array of floats representing the matrix elements.
Definition SRender-i.h:975