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