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 guy aligns with the masks, so we can compute a mask from a varaible 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 guy 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 SkASSERT(results[0] >= -SK_ScalarNearlyZero);
1523 if (results[0] < 0) {
1524 results[0] = 0;
1525 }
1526 results[0] = SkScalarSqrt(results[0]);
1527 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1528 if (!SkScalarIsFinite(results[1])) {
1529 return false;
1530 }
1531 SkASSERT(results[1] >= -SK_ScalarNearlyZero);
1532 if (results[1] < 0) {
1533 results[1] = 0;
1534 }
1535 results[1] = SkScalarSqrt(results[1]);
1536 }
1537 return true;
1538}
1539
1540SkScalar SkMatrix::getMinScale() const {
1541 SkScalar factor;
1542 if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1543 return factor;
1544 } else {
1545 return -1;
1546 }
1547}
1548
1549SkScalar SkMatrix::getMaxScale() const {
1550 SkScalar factor;
1551 if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1552 return factor;
1553 } else {
1554 return -1;
1555 }
1556}
1557
1558bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1559 return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1560}
1561
1562const SkMatrix& SkMatrix::I() {
1563 static constexpr SkMatrix identity;
1564 SkASSERT(identity.isIdentity());
1565 return identity;
1566}
1567
1568const SkMatrix& SkMatrix::InvalidMatrix() {
1569 static constexpr SkMatrix invalid(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1570 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1571 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1572 kTranslate_Mask | kScale_Mask |
1573 kAffine_Mask | kPerspective_Mask);
1574 return invalid;
1575}
1576
1577bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const {
1578 if (this->hasPerspective()) {
1579 return false;
1580 }
1581
1582 const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY());
1583 const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY());
1584 if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) ||
1585 SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) {
1586 return false;
1587 }
1588
1589 if (scale) {
1590 scale->set(sx, sy);
1591 }
1592 if (remaining) {
1593 *remaining = *this;
1594 remaining->preScale(SkScalarInvert(sx), SkScalarInvert(sy));
1595 }
1596 return true;
1597}
1598
1599///////////////////////////////////////////////////////////////////////////////
1600
1601size_t SkMatrix::writeToMemory(void* buffer) const {
1602 // TODO write less for simple matrices
1603 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1604 if (buffer) {
1605 memcpy(buffer, fMat, sizeInMemory);
1606 }
1607 return sizeInMemory;
1608}
1609
1610size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
1611 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1612 if (length < sizeInMemory) {
1613 return 0;
1614 }
1615 memcpy(fMat, buffer, sizeInMemory);
1616 this->setTypeMask(kUnknown_Mask);
1617 return sizeInMemory;
1618}
1619
1620void SkMatrix::dump() const {
1621 SkString str;
1622 str.appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
1623 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1624 fMat[6], fMat[7], fMat[8]);
1625 SkDebugf("%s\n", str.c_str());
1626}
1627
1628///////////////////////////////////////////////////////////////////////////////
1629
1630#include "src/core/SkMatrixUtils.h"
1631
1632bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkPaint& paint) {
1633 // Our path aa is 2-bits, and our rect aa is 8, so we could use 8,
1634 // but in practice 4 seems enough (still looks smooth) and allows
1635 // more slightly fractional cases to fall into the fast (sprite) case.
1636 static const unsigned kAntiAliasSubpixelBits = 4;
1637
1638 const unsigned subpixelBits = paint.isAntiAlias() ? kAntiAliasSubpixelBits : 0;
1639
1640 // quick reject on affine or perspective
1641 if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
1642 return false;
1643 }
1644
1645 // quick success check
1646 if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1647 return true;
1648 }
1649
1650 // mapRect supports negative scales, so we eliminate those first
1651 if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1652 return false;
1653 }
1654
1655 SkRect dst;
1656 SkIRect isrc = SkIRect::MakeSize(size);
1657
1658 {
1659 SkRect src;
1660 src.set(isrc);
1661 mat.mapRect(&dst, src);
1662 }
1663
1664 // just apply the translate to isrc
1665 isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1666 SkScalarRoundToInt(mat.getTranslateY()));
1667
1668 if (subpixelBits) {
1669 isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits);
1670 isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits);
1671 isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits);
1672 isrc.fBottom = SkLeftShift(isrc.fBottom, subpixelBits);
1673
1674 const float scale = 1 << subpixelBits;
1675 dst.fLeft *= scale;
1676 dst.fTop *= scale;
1677 dst.fRight *= scale;
1678 dst.fBottom *= scale;
1679 }
1680
1681 SkIRect idst;
1682 dst.round(&idst);
1683 return isrc == idst;
1684}
1685
1686// A square matrix M can be decomposed (via polar decomposition) into two matrices --
1687// an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
1688// where U is another orthogonal matrix and W is a scale matrix. These can be recombined
1689// to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
1690//
1691// The one wrinkle is that traditionally Q may contain a reflection -- the
1692// calculation has been rejiggered to put that reflection into W.
1693bool SkDecomposeUpper2x2(const SkMatrix& matrix,
1694 SkPoint* rotation1,
1695 SkPoint* scale,
1696 SkPoint* rotation2) {
1697
1698 SkScalar A = matrix[SkMatrix::kMScaleX];
1699 SkScalar B = matrix[SkMatrix::kMSkewX];
1700 SkScalar C = matrix[SkMatrix::kMSkewY];
1701 SkScalar D = matrix[SkMatrix::kMScaleY];
1702
1703 if (is_degenerate_2x2(A, B, C, D)) {
1704 return false;
1705 }
1706
1707 double w1, w2;
1708 SkScalar cos1, sin1;
1709 SkScalar cos2, sin2;
1710
1711 // do polar decomposition (M = Q*S)
1712 SkScalar cosQ, sinQ;
1713 double Sa, Sb, Sd;
1714 // if M is already symmetric (i.e., M = I*S)
1715 if (SkScalarNearlyEqual(B, C)) {
1716 cosQ = 1;
1717 sinQ = 0;
1718
1719 Sa = A;
1720 Sb = B;
1721 Sd = D;
1722 } else {
1723 cosQ = A + D;
1724 sinQ = C - B;
1725 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
1726 cosQ *= reciplen;
1727 sinQ *= reciplen;
1728
1729 // S = Q^-1*M
1730 // we don't calc Sc since it's symmetric
1731 Sa = A*cosQ + C*sinQ;
1732 Sb = B*cosQ + D*sinQ;
1733 Sd = -B*sinQ + D*cosQ;
1734 }
1735
1736 // Now we need to compute eigenvalues of S (our scale factors)
1737 // and eigenvectors (bases for our rotation)
1738 // From this, should be able to reconstruct S as U*W*U^T
1739 if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
1740 // already diagonalized
1741 cos1 = 1;
1742 sin1 = 0;
1743 w1 = Sa;
1744 w2 = Sd;
1745 cos2 = cosQ;
1746 sin2 = sinQ;
1747 } else {
1748 double diff = Sa - Sd;
1749 double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
1750 double trace = Sa + Sd;
1751 if (diff > 0) {
1752 w1 = 0.5*(trace + discriminant);
1753 w2 = 0.5*(trace - discriminant);
1754 } else {
1755 w1 = 0.5*(trace - discriminant);
1756 w2 = 0.5*(trace + discriminant);
1757 }
1758
1759 cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
1760 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
1761 cos1 *= reciplen;
1762 sin1 *= reciplen;
1763
1764 // rotation 2 is composition of Q and U
1765 cos2 = cos1*cosQ - sin1*sinQ;
1766 sin2 = sin1*cosQ + cos1*sinQ;
1767
1768 // rotation 1 is U^T
1769 sin1 = -sin1;
1770 }
1771
1772 if (scale) {
1773 scale->fX = SkDoubleToScalar(w1);
1774 scale->fY = SkDoubleToScalar(w2);
1775 }
1776 if (rotation1) {
1777 rotation1->fX = cos1;
1778 rotation1->fY = sin1;
1779 }
1780 if (rotation2) {
1781 rotation2->fX = cos2;
1782 rotation2->fY = sin2;
1783 }
1784
1785 return true;
1786}
1787
1788//////////////////////////////////////////////////////////////////////////////////////////////////
1789
1790void SkRSXform::toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const {
1791#if 0
1792 // This is the slow way, but it documents what we're doing
1793 quad[0].set(0, 0);
1794 quad[1].set(width, 0);
1795 quad[2].set(width, height);
1796 quad[3].set(0, height);
1797 SkMatrix m;
1798 m.setRSXform(*this).mapPoints(quad, quad, 4);
1799#else
1800 const SkScalar m00 = fSCos;
1801 const SkScalar m01 = -fSSin;
1802 const SkScalar m02 = fTx;
1803 const SkScalar m10 = -m01;
1804 const SkScalar m11 = m00;
1805 const SkScalar m12 = fTy;
1806
1807 quad[0].set(m02, m12);
1808 quad[1].set(m00 * width + m02, m10 * width + m12);
1809 quad[2].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
1810 quad[3].set(m01 * height + m02, m11 * height + m12);
1811#endif
1812}
1813
1814void SkRSXform::toTriStrip(SkScalar width, SkScalar height, SkPoint strip[4]) const {
1815 const SkScalar m00 = fSCos;
1816 const SkScalar m01 = -fSSin;
1817 const SkScalar m02 = fTx;
1818 const SkScalar m10 = -m01;
1819 const SkScalar m11 = m00;
1820 const SkScalar m12 = fTy;
1821
1822 strip[0].set(m02, m12);
1823 strip[1].set(m01 * height + m02, m11 * height + m12);
1824 strip[2].set(m00 * width + m02, m10 * width + m12);
1825 strip[3].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
1826}
1827
1828///////////////////////////////////////////////////////////////////////////////////////////////////
1829
1830SkFilterQuality SkMatrixPriv::AdjustHighQualityFilterLevel(const SkMatrix& matrix,
1831 bool matrixIsInverse) {
1832 if (matrix.isIdentity()) {
1833 return kNone_SkFilterQuality;
1834 }
1835
1836 auto is_minimizing = [&](SkScalar scale) {
1837 return matrixIsInverse ? scale > 1 : scale < 1;
1838 };
1839
1840 SkScalar scales[2];
1841 if (!matrix.getMinMaxScales(scales) || is_minimizing(scales[0])) {
1842 // Bicubic doesn't handle arbitrary minimization well, as src texels can be skipped
1843 // entirely,
1844 return kMedium_SkFilterQuality;
1845 }
1846
1847 // At this point if scales[1] == SK_Scalar1 then the matrix doesn't do any scaling.
1848 if (scales[1] == SK_Scalar1) {
1849 if (matrix.rectStaysRect() && SkScalarIsInt(matrix.getTranslateX()) &&
1850 SkScalarIsInt(matrix.getTranslateY())) {
1851 return kNone_SkFilterQuality;
1852 } else {
1853 // Use bilerp to handle rotation or fractional translation.
1854 return kLow_SkFilterQuality;
1855 }
1856 }
1857
1858 return kHigh_SkFilterQuality;
1859}
1860