blob: 034f22fa668e79337fb007f54a9aa9263b66326a [file] [log] [blame]
David Ghandehari9e5b5872016-07-28 09:50:04 -07001/*
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
Xiaoming Shi73dfa202020-03-12 11:31:35 -07008#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
20#include <cstddef>
21#include <utility>
David Ghandehari9e5b5872016-07-28 09:50:04 -070022
Mike Fleming3933d922018-04-02 10:53:08 -070023#if defined(COBALT)
Chad Duffinac9ac062019-07-23 10:06:45 -070024#include "starboard/common/log.h"
Mike Fleming3933d922018-04-02 10:53:08 -070025#endif
26
Andrew Top200ce4b2018-01-29 13:43:50 -080027static void normalize_perspective(SkScalar mat[9]) {
28 // If it was interesting to never store the last element, we could divide all 8 other
29 // elements here by the 9th, making it 1.0...
30 //
31 // When SkScalar was SkFixed, we would sometimes rescale the entire matrix to keep its
32 // component values from getting too large. This is not a concern when using floats/doubles,
33 // so we do nothing now.
34
35 // Disable this for now, but it could be enabled.
36#if 0
37 if (0 == mat[SkMatrix::kMPersp0] && 0 == mat[SkMatrix::kMPersp1]) {
38 SkScalar p2 = mat[SkMatrix::kMPersp2];
39 if (p2 != 0 && p2 != 1) {
40 double inv = 1.0 / p2;
41 for (int i = 0; i < 6; ++i) {
42 mat[i] = SkDoubleToScalar(mat[i] * inv);
43 }
44 mat[SkMatrix::kMPersp2] = 1;
45 }
46 }
47#endif
48}
49
David Ghandehari9e5b5872016-07-28 09:50:04 -070050// In a few places, we performed the following
51// a * b + c * d + e
52// as
53// a * b + (c * d + e)
54//
55// sdot and scross are indended to capture these compound operations into a
56// function, with an eye toward considering upscaling the intermediates to
57// doubles for more precision (as we do in concat and invert).
58//
59// However, these few lines that performed the last add before the "dot", cause
60// tiny image differences, so we guard that change until we see the impact on
61// chrome's layouttests.
62//
63#define SK_LEGACY_MATRIX_MATH_ORDER
64
David Ghandehari9e5b5872016-07-28 09:50:04 -070065/* [scale-x skew-x trans-x] [X] [X']
66 [skew-y scale-y trans-y] * [Y] = [Y']
67 [persp-0 persp-1 persp-2] [1] [1 ]
68*/
69
Xiaoming Shi73dfa202020-03-12 11:31:35 -070070SkMatrix& SkMatrix::reset() { *this = SkMatrix(); return *this; }
David Ghandehari9e5b5872016-07-28 09:50:04 -070071
Xiaoming Shi73dfa202020-03-12 11:31:35 -070072SkMatrix& SkMatrix::set9(const SkScalar buffer[]) {
Andrew Top200ce4b2018-01-29 13:43:50 -080073 memcpy(fMat, buffer, 9 * sizeof(SkScalar));
74 normalize_perspective(fMat);
75 this->setTypeMask(kUnknown_Mask);
Xiaoming Shi73dfa202020-03-12 11:31:35 -070076 return *this;
Andrew Top200ce4b2018-01-29 13:43:50 -080077}
78
Xiaoming Shi73dfa202020-03-12 11:31:35 -070079SkMatrix& SkMatrix::setAffine(const SkScalar buffer[]) {
Andrew Top200ce4b2018-01-29 13:43:50 -080080 fMat[kMScaleX] = buffer[kAScaleX];
81 fMat[kMSkewX] = buffer[kASkewX];
82 fMat[kMTransX] = buffer[kATransX];
83 fMat[kMSkewY] = buffer[kASkewY];
84 fMat[kMScaleY] = buffer[kAScaleY];
85 fMat[kMTransY] = buffer[kATransY];
86 fMat[kMPersp0] = 0;
87 fMat[kMPersp1] = 0;
88 fMat[kMPersp2] = 1;
89 this->setTypeMask(kUnknown_Mask);
Xiaoming Shi73dfa202020-03-12 11:31:35 -070090 return *this;
Andrew Top200ce4b2018-01-29 13:43:50 -080091}
92
David Ghandehari9e5b5872016-07-28 09:50:04 -070093// this guy aligns with the masks, so we can compute a mask from a varaible 0/1
94enum {
95 kTranslate_Shift,
96 kScale_Shift,
97 kAffine_Shift,
98 kPerspective_Shift,
99 kRectStaysRect_Shift
100};
101
102static const int32_t kScalar1Int = 0x3f800000;
103
104uint8_t SkMatrix::computePerspectiveTypeMask() const {
105 // Benchmarking suggests that replacing this set of SkScalarAs2sCompliment
106 // is a win, but replacing those below is not. We don't yet understand
107 // that result.
108 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
109 // If this is a perspective transform, we return true for all other
110 // transform flags - this does not disable any optimizations, respects
111 // the rule that the type mask must be conservative, and speeds up
112 // type mask computation.
113 return SkToU8(kORableMasks);
114 }
115
116 return SkToU8(kOnlyPerspectiveValid_Mask | kUnknown_Mask);
117}
118
119uint8_t SkMatrix::computeTypeMask() const {
120 unsigned mask = 0;
121
122 if (fMat[kMPersp0] != 0 || fMat[kMPersp1] != 0 || fMat[kMPersp2] != 1) {
123 // Once it is determined that that this is a perspective transform,
124 // all other flags are moot as far as optimizations are concerned.
125 return SkToU8(kORableMasks);
126 }
127
128 if (fMat[kMTransX] != 0 || fMat[kMTransY] != 0) {
129 mask |= kTranslate_Mask;
130 }
131
132 int m00 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleX]);
133 int m01 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewX]);
134 int m10 = SkScalarAs2sCompliment(fMat[SkMatrix::kMSkewY]);
135 int m11 = SkScalarAs2sCompliment(fMat[SkMatrix::kMScaleY]);
136
137 if (m01 | m10) {
138 // The skew components may be scale-inducing, unless we are dealing
139 // with a pure rotation. Testing for a pure rotation is expensive,
140 // so we opt for being conservative by always setting the scale bit.
141 // along with affine.
142 // By doing this, we are also ensuring that matrices have the same
143 // type masks as their inverses.
144 mask |= kAffine_Mask | kScale_Mask;
145
146 // For rectStaysRect, in the affine case, we only need check that
147 // the primary diagonal is all zeros and that the secondary diagonal
148 // is all non-zero.
149
150 // map non-zero to 1
151 m01 = m01 != 0;
152 m10 = m10 != 0;
153
154 int dp0 = 0 == (m00 | m11) ; // true if both are 0
155 int ds1 = m01 & m10; // true if both are 1
156
157 mask |= (dp0 & ds1) << kRectStaysRect_Shift;
158 } else {
159 // Only test for scale explicitly if not affine, since affine sets the
160 // scale bit.
Andrew Top200ce4b2018-01-29 13:43:50 -0800161 if ((m00 ^ kScalar1Int) | (m11 ^ kScalar1Int)) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700162 mask |= kScale_Mask;
163 }
164
165 // Not affine, therefore we already know secondary diagonal is
166 // all zeros, so we just need to check that primary diagonal is
167 // all non-zero.
168
169 // map non-zero to 1
170 m00 = m00 != 0;
171 m11 = m11 != 0;
172
173 // record if the (p)rimary diagonal is all non-zero
174 mask |= (m00 & m11) << kRectStaysRect_Shift;
175 }
176
177 return SkToU8(mask);
178}
179
180///////////////////////////////////////////////////////////////////////////////
181
182bool operator==(const SkMatrix& a, const SkMatrix& b) {
183 const SkScalar* SK_RESTRICT ma = a.fMat;
184 const SkScalar* SK_RESTRICT mb = b.fMat;
185
186 return ma[0] == mb[0] && ma[1] == mb[1] && ma[2] == mb[2] &&
187 ma[3] == mb[3] && ma[4] == mb[4] && ma[5] == mb[5] &&
188 ma[6] == mb[6] && ma[7] == mb[7] && ma[8] == mb[8];
189}
190
191///////////////////////////////////////////////////////////////////////////////
192
193// helper function to determine if upper-left 2x2 of matrix is degenerate
194static inline bool is_degenerate_2x2(SkScalar scaleX, SkScalar skewX,
195 SkScalar skewY, SkScalar scaleY) {
196 SkScalar perp_dot = scaleX*scaleY - skewX*skewY;
197 return SkScalarNearlyZero(perp_dot, SK_ScalarNearlyZero*SK_ScalarNearlyZero);
198}
199
200///////////////////////////////////////////////////////////////////////////////
201
202bool SkMatrix::isSimilarity(SkScalar tol) const {
203 // if identity or translate matrix
204 TypeMask mask = this->getType();
205 if (mask <= kTranslate_Mask) {
206 return true;
207 }
208 if (mask & kPerspective_Mask) {
209 return false;
210 }
211
212 SkScalar mx = fMat[kMScaleX];
213 SkScalar my = fMat[kMScaleY];
214 // if no skew, can just compare scale factors
215 if (!(mask & kAffine_Mask)) {
216 return !SkScalarNearlyZero(mx) && SkScalarNearlyEqual(SkScalarAbs(mx), SkScalarAbs(my));
217 }
218 SkScalar sx = fMat[kMSkewX];
219 SkScalar sy = fMat[kMSkewY];
220
221 if (is_degenerate_2x2(mx, sx, sy, my)) {
222 return false;
223 }
224
225 // upper 2x2 is rotation/reflection + uniform scale if basis vectors
226 // are 90 degree rotations of each other
227 return (SkScalarNearlyEqual(mx, my, tol) && SkScalarNearlyEqual(sx, -sy, tol))
228 || (SkScalarNearlyEqual(mx, -my, tol) && SkScalarNearlyEqual(sx, sy, tol));
229}
230
231bool SkMatrix::preservesRightAngles(SkScalar tol) const {
232 TypeMask mask = this->getType();
233
234 if (mask <= kTranslate_Mask) {
235 // identity, translate and/or scale
236 return true;
237 }
238 if (mask & kPerspective_Mask) {
239 return false;
240 }
241
242 SkASSERT(mask & (kAffine_Mask | kScale_Mask));
243
244 SkScalar mx = fMat[kMScaleX];
245 SkScalar my = fMat[kMScaleY];
246 SkScalar sx = fMat[kMSkewX];
247 SkScalar sy = fMat[kMSkewY];
248
249 if (is_degenerate_2x2(mx, sx, sy, my)) {
250 return false;
251 }
252
253 // upper 2x2 is scale + rotation/reflection if basis vectors are orthogonal
254 SkVector vec[2];
255 vec[0].set(mx, sy);
256 vec[1].set(sx, my);
257
258 return SkScalarNearlyZero(vec[0].dot(vec[1]), SkScalarSquare(tol));
259}
260
261///////////////////////////////////////////////////////////////////////////////
262
263static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
264 return a * b + c * d;
265}
266
267static inline SkScalar sdot(SkScalar a, SkScalar b, SkScalar c, SkScalar d,
268 SkScalar e, SkScalar f) {
269 return a * b + c * d + e * f;
270}
271
272static inline SkScalar scross(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
273 return a * b - c * d;
274}
275
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700276SkMatrix& SkMatrix::setTranslate(SkScalar dx, SkScalar dy) {
277 *this = SkMatrix(1, 0, dx,
278 0, 1, dy,
279 0, 0, 1,
280 (dx != 0 || dy != 0) ? kTranslate_Mask | kRectStaysRect_Mask
281 : kIdentity_Mask | kRectStaysRect_Mask);
282 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700283}
284
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700285SkMatrix& SkMatrix::preTranslate(SkScalar dx, SkScalar dy) {
Andrew Top200ce4b2018-01-29 13:43:50 -0800286 const unsigned mask = this->getType();
David Ghandehari9e5b5872016-07-28 09:50:04 -0700287
Andrew Top200ce4b2018-01-29 13:43:50 -0800288 if (mask <= kTranslate_Mask) {
289 fMat[kMTransX] += dx;
290 fMat[kMTransY] += dy;
291 } else if (mask & kPerspective_Mask) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700292 SkMatrix m;
293 m.setTranslate(dx, dy);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700294 return this->preConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700295 } else {
296 fMat[kMTransX] += sdot(fMat[kMScaleX], dx, fMat[kMSkewX], dy);
297 fMat[kMTransY] += sdot(fMat[kMSkewY], dx, fMat[kMScaleY], dy);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700298 }
Andrew Top200ce4b2018-01-29 13:43:50 -0800299 this->updateTranslateMask();
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700300 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700301}
302
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700303SkMatrix& SkMatrix::postTranslate(SkScalar dx, SkScalar dy) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700304 if (this->hasPerspective()) {
305 SkMatrix m;
306 m.setTranslate(dx, dy);
307 this->postConcat(m);
308 } else {
309 fMat[kMTransX] += dx;
310 fMat[kMTransY] += dy;
Andrew Top200ce4b2018-01-29 13:43:50 -0800311 this->updateTranslateMask();
David Ghandehari9e5b5872016-07-28 09:50:04 -0700312 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700313 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700314}
315
316///////////////////////////////////////////////////////////////////////////////
317
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700318SkMatrix& SkMatrix::setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700319 if (1 == sx && 1 == sy) {
320 this->reset();
321 } else {
Andrew Top200ce4b2018-01-29 13:43:50 -0800322 this->setScaleTranslate(sx, sy, px - sx * px, py - sy * py);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700323 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700324 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700325}
326
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700327SkMatrix& SkMatrix::setScale(SkScalar sx, SkScalar sy) {
328 *this = SkMatrix(sx, 0, 0,
329 0, sy, 0,
330 0, 0, 1,
331 (sx == 1 && sy == 1) ? kIdentity_Mask | kRectStaysRect_Mask
332 : kScale_Mask | kRectStaysRect_Mask);
333 return *this;
334}
335
336SkMatrix& SkMatrix::preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700337 if (1 == sx && 1 == sy) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700338 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700339 }
340
341 SkMatrix m;
342 m.setScale(sx, sy, px, py);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700343 return this->preConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700344}
345
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700346SkMatrix& SkMatrix::preScale(SkScalar sx, SkScalar sy) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700347 if (1 == sx && 1 == sy) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700348 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700349 }
350
351 // the assumption is that these multiplies are very cheap, and that
352 // a full concat and/or just computing the matrix type is more expensive.
353 // Also, the fixed-point case checks for overflow, but the float doesn't,
354 // so we can get away with these blind multiplies.
355
356 fMat[kMScaleX] *= sx;
357 fMat[kMSkewY] *= sx;
358 fMat[kMPersp0] *= sx;
359
360 fMat[kMSkewX] *= sy;
361 fMat[kMScaleY] *= sy;
362 fMat[kMPersp1] *= sy;
363
Andrew Top200ce4b2018-01-29 13:43:50 -0800364 // Attempt to simplify our type when applying an inverse scale.
365 // TODO: The persp/affine preconditions are in place to keep the mask consistent with
366 // what computeTypeMask() would produce (persp/skew always implies kScale).
367 // We should investigate whether these flag dependencies are truly needed.
368 if (fMat[kMScaleX] == 1 && fMat[kMScaleY] == 1
369 && !(fTypeMask & (kPerspective_Mask | kAffine_Mask))) {
370 this->clearTypeMask(kScale_Mask);
371 } else {
372 this->orTypeMask(kScale_Mask);
373 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700374 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700375}
376
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700377SkMatrix& SkMatrix::postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700378 if (1 == sx && 1 == sy) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700379 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700380 }
381 SkMatrix m;
382 m.setScale(sx, sy, px, py);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700383 return this->postConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700384}
385
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700386SkMatrix& SkMatrix::postScale(SkScalar sx, SkScalar sy) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700387 if (1 == sx && 1 == sy) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700388 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700389 }
390 SkMatrix m;
391 m.setScale(sx, sy);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700392 return this->postConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700393}
394
395// this guy perhaps can go away, if we have a fract/high-precision way to
396// scale matrices
397bool SkMatrix::postIDiv(int divx, int divy) {
398 if (divx == 0 || divy == 0) {
399 return false;
400 }
401
402 const float invX = 1.f / divx;
403 const float invY = 1.f / divy;
404
405 fMat[kMScaleX] *= invX;
406 fMat[kMSkewX] *= invX;
407 fMat[kMTransX] *= invX;
408
409 fMat[kMScaleY] *= invY;
410 fMat[kMSkewY] *= invY;
411 fMat[kMTransY] *= invY;
412
413 this->setTypeMask(kUnknown_Mask);
414 return true;
415}
416
417////////////////////////////////////////////////////////////////////////////////////
418
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700419SkMatrix& SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700420 const SkScalar oneMinusCosV = 1 - cosV;
421
422 fMat[kMScaleX] = cosV;
423 fMat[kMSkewX] = -sinV;
424 fMat[kMTransX] = sdot(sinV, py, oneMinusCosV, px);
425
426 fMat[kMSkewY] = sinV;
427 fMat[kMScaleY] = cosV;
428 fMat[kMTransY] = sdot(-sinV, px, oneMinusCosV, py);
429
430 fMat[kMPersp0] = fMat[kMPersp1] = 0;
431 fMat[kMPersp2] = 1;
432
433 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700434 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700435}
436
Andrew Top200ce4b2018-01-29 13:43:50 -0800437SkMatrix& SkMatrix::setRSXform(const SkRSXform& xform) {
438 fMat[kMScaleX] = xform.fSCos;
439 fMat[kMSkewX] = -xform.fSSin;
440 fMat[kMTransX] = xform.fTx;
441
442 fMat[kMSkewY] = xform.fSSin;
443 fMat[kMScaleY] = xform.fSCos;
444 fMat[kMTransY] = xform.fTy;
445
446 fMat[kMPersp0] = fMat[kMPersp1] = 0;
447 fMat[kMPersp2] = 1;
448
449 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
450 return *this;
451}
452
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700453SkMatrix& SkMatrix::setSinCos(SkScalar sinV, SkScalar cosV) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700454 fMat[kMScaleX] = cosV;
455 fMat[kMSkewX] = -sinV;
456 fMat[kMTransX] = 0;
457
458 fMat[kMSkewY] = sinV;
459 fMat[kMScaleY] = cosV;
460 fMat[kMTransY] = 0;
461
462 fMat[kMPersp0] = fMat[kMPersp1] = 0;
463 fMat[kMPersp2] = 1;
464
465 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700466 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700467}
468
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700469SkMatrix& SkMatrix::setRotate(SkScalar degrees, SkScalar px, SkScalar py) {
470 SkScalar rad = SkDegreesToRadians(degrees);
471 return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad), px, py);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700472}
473
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700474SkMatrix& SkMatrix::setRotate(SkScalar degrees) {
475 SkScalar rad = SkDegreesToRadians(degrees);
476 return this->setSinCos(SkScalarSinSnapToZero(rad), SkScalarCosSnapToZero(rad));
David Ghandehari9e5b5872016-07-28 09:50:04 -0700477}
478
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700479SkMatrix& SkMatrix::preRotate(SkScalar degrees, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700480 SkMatrix m;
481 m.setRotate(degrees, px, py);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700482 return this->preConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700483}
484
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700485SkMatrix& SkMatrix::preRotate(SkScalar degrees) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700486 SkMatrix m;
487 m.setRotate(degrees);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700488 return this->preConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700489}
490
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700491SkMatrix& SkMatrix::postRotate(SkScalar degrees, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700492 SkMatrix m;
493 m.setRotate(degrees, px, py);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700494 return this->postConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700495}
496
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700497SkMatrix& SkMatrix::postRotate(SkScalar degrees) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700498 SkMatrix m;
499 m.setRotate(degrees);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700500 return this->postConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700501}
502
503////////////////////////////////////////////////////////////////////////////////////
504
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700505SkMatrix& SkMatrix::setSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
506 *this = SkMatrix(1, sx, -sx * py,
507 sy, 1, -sy * px,
508 0, 0, 1,
509 kUnknown_Mask | kOnlyPerspectiveValid_Mask);
510 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700511}
512
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700513SkMatrix& SkMatrix::setSkew(SkScalar sx, SkScalar sy) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700514 fMat[kMScaleX] = 1;
515 fMat[kMSkewX] = sx;
516 fMat[kMTransX] = 0;
517
518 fMat[kMSkewY] = sy;
519 fMat[kMScaleY] = 1;
520 fMat[kMTransY] = 0;
521
522 fMat[kMPersp0] = fMat[kMPersp1] = 0;
523 fMat[kMPersp2] = 1;
524
525 this->setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700526 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700527}
528
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700529SkMatrix& SkMatrix::preSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700530 SkMatrix m;
531 m.setSkew(sx, sy, px, py);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700532 return this->preConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700533}
534
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700535SkMatrix& SkMatrix::preSkew(SkScalar sx, SkScalar sy) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700536 SkMatrix m;
537 m.setSkew(sx, sy);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700538 return this->preConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700539}
540
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700541SkMatrix& SkMatrix::postSkew(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700542 SkMatrix m;
543 m.setSkew(sx, sy, px, py);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700544 return this->postConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700545}
546
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700547SkMatrix& SkMatrix::postSkew(SkScalar sx, SkScalar sy) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700548 SkMatrix m;
549 m.setSkew(sx, sy);
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700550 return this->postConcat(m);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700551}
552
553///////////////////////////////////////////////////////////////////////////////
554
Andrew Top200ce4b2018-01-29 13:43:50 -0800555bool SkMatrix::setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit align) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700556 if (src.isEmpty()) {
557 this->reset();
558 return false;
559 }
560
561 if (dst.isEmpty()) {
562 sk_bzero(fMat, 8 * sizeof(SkScalar));
Andrew Top200ce4b2018-01-29 13:43:50 -0800563 fMat[kMPersp2] = 1;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700564 this->setTypeMask(kScale_Mask | kRectStaysRect_Mask);
565 } else {
566 SkScalar tx, sx = dst.width() / src.width();
567 SkScalar ty, sy = dst.height() / src.height();
568 bool xLarger = false;
569
570 if (align != kFill_ScaleToFit) {
571 if (sx > sy) {
572 xLarger = true;
573 sx = sy;
574 } else {
575 sy = sx;
576 }
577 }
578
579 tx = dst.fLeft - src.fLeft * sx;
580 ty = dst.fTop - src.fTop * sy;
581 if (align == kCenter_ScaleToFit || align == kEnd_ScaleToFit) {
582 SkScalar diff;
583
584 if (xLarger) {
585 diff = dst.width() - src.width() * sy;
586 } else {
587 diff = dst.height() - src.height() * sy;
588 }
589
590 if (align == kCenter_ScaleToFit) {
591 diff = SkScalarHalf(diff);
592 }
593
594 if (xLarger) {
595 tx += diff;
596 } else {
597 ty += diff;
598 }
599 }
600
Andrew Top200ce4b2018-01-29 13:43:50 -0800601 this->setScaleTranslate(sx, sy, tx, ty);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700602 }
David Ghandehari9e5b5872016-07-28 09:50:04 -0700603 return true;
604}
605
606///////////////////////////////////////////////////////////////////////////////
607
608static inline float muladdmul(float a, float b, float c, float d) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700609 return sk_double_to_float((double)a * b + (double)c * d);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700610}
611
612static inline float rowcol3(const float row[], const float col[]) {
613 return row[0] * col[0] + row[1] * col[3] + row[2] * col[6];
614}
615
Andrew Top200ce4b2018-01-29 13:43:50 -0800616static bool only_scale_and_translate(unsigned mask) {
617 return 0 == (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask));
David Ghandehari9e5b5872016-07-28 09:50:04 -0700618}
619
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700620SkMatrix& SkMatrix::setConcat(const SkMatrix& a, const SkMatrix& b) {
Andrew Top200ce4b2018-01-29 13:43:50 -0800621 TypeMask aType = a.getType();
622 TypeMask bType = b.getType();
David Ghandehari9e5b5872016-07-28 09:50:04 -0700623
624 if (a.isTriviallyIdentity()) {
625 *this = b;
626 } else if (b.isTriviallyIdentity()) {
627 *this = a;
Andrew Top200ce4b2018-01-29 13:43:50 -0800628 } else if (only_scale_and_translate(aType | bType)) {
629 this->setScaleTranslate(a.fMat[kMScaleX] * b.fMat[kMScaleX],
630 a.fMat[kMScaleY] * b.fMat[kMScaleY],
631 a.fMat[kMScaleX] * b.fMat[kMTransX] + a.fMat[kMTransX],
632 a.fMat[kMScaleY] * b.fMat[kMTransY] + a.fMat[kMTransY]);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700633 } else {
634 SkMatrix tmp;
635
636 if ((aType | bType) & kPerspective_Mask) {
637 tmp.fMat[kMScaleX] = rowcol3(&a.fMat[0], &b.fMat[0]);
638 tmp.fMat[kMSkewX] = rowcol3(&a.fMat[0], &b.fMat[1]);
639 tmp.fMat[kMTransX] = rowcol3(&a.fMat[0], &b.fMat[2]);
640 tmp.fMat[kMSkewY] = rowcol3(&a.fMat[3], &b.fMat[0]);
641 tmp.fMat[kMScaleY] = rowcol3(&a.fMat[3], &b.fMat[1]);
642 tmp.fMat[kMTransY] = rowcol3(&a.fMat[3], &b.fMat[2]);
643 tmp.fMat[kMPersp0] = rowcol3(&a.fMat[6], &b.fMat[0]);
644 tmp.fMat[kMPersp1] = rowcol3(&a.fMat[6], &b.fMat[1]);
645 tmp.fMat[kMPersp2] = rowcol3(&a.fMat[6], &b.fMat[2]);
646
647 normalize_perspective(tmp.fMat);
648 tmp.setTypeMask(kUnknown_Mask);
Andrew Top200ce4b2018-01-29 13:43:50 -0800649 } else {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700650 tmp.fMat[kMScaleX] = muladdmul(a.fMat[kMScaleX],
651 b.fMat[kMScaleX],
652 a.fMat[kMSkewX],
653 b.fMat[kMSkewY]);
654
655 tmp.fMat[kMSkewX] = muladdmul(a.fMat[kMScaleX],
656 b.fMat[kMSkewX],
657 a.fMat[kMSkewX],
658 b.fMat[kMScaleY]);
659
660 tmp.fMat[kMTransX] = muladdmul(a.fMat[kMScaleX],
661 b.fMat[kMTransX],
662 a.fMat[kMSkewX],
Andrew Top200ce4b2018-01-29 13:43:50 -0800663 b.fMat[kMTransY]) + a.fMat[kMTransX];
David Ghandehari9e5b5872016-07-28 09:50:04 -0700664
665 tmp.fMat[kMSkewY] = muladdmul(a.fMat[kMSkewY],
666 b.fMat[kMScaleX],
667 a.fMat[kMScaleY],
668 b.fMat[kMSkewY]);
669
670 tmp.fMat[kMScaleY] = muladdmul(a.fMat[kMSkewY],
671 b.fMat[kMSkewX],
672 a.fMat[kMScaleY],
673 b.fMat[kMScaleY]);
674
675 tmp.fMat[kMTransY] = muladdmul(a.fMat[kMSkewY],
676 b.fMat[kMTransX],
677 a.fMat[kMScaleY],
Andrew Top200ce4b2018-01-29 13:43:50 -0800678 b.fMat[kMTransY]) + a.fMat[kMTransY];
David Ghandehari9e5b5872016-07-28 09:50:04 -0700679
Andrew Top200ce4b2018-01-29 13:43:50 -0800680 tmp.fMat[kMPersp0] = 0;
681 tmp.fMat[kMPersp1] = 0;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700682 tmp.fMat[kMPersp2] = 1;
683 //SkDebugf("Concat mat non-persp type: %d\n", tmp.getType());
684 //SkASSERT(!(tmp.getType() & kPerspective_Mask));
685 tmp.setTypeMask(kUnknown_Mask | kOnlyPerspectiveValid_Mask);
686 }
687 *this = tmp;
688 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700689 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700690}
691
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700692SkMatrix& SkMatrix::preConcat(const SkMatrix& mat) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700693 // 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(*this, mat);
697 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700698 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700699}
700
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700701SkMatrix& SkMatrix::postConcat(const SkMatrix& mat) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700702 // check for identity first, so we don't do a needless copy of ourselves
703 // to ourselves inside setConcat()
704 if (!mat.isIdentity()) {
705 this->setConcat(mat, *this);
706 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700707 return *this;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700708}
709
710///////////////////////////////////////////////////////////////////////////////
711
712/* Matrix inversion is very expensive, but also the place where keeping
713 precision may be most important (here and matrix concat). Hence to avoid
714 bitmap blitting artifacts when walking the inverse, we use doubles for
715 the intermediate math, even though we know that is more expensive.
716 */
717
718static inline SkScalar scross_dscale(SkScalar a, SkScalar b,
719 SkScalar c, SkScalar d, double scale) {
720 return SkDoubleToScalar(scross(a, b, c, d) * scale);
721}
722
723static inline double dcross(double a, double b, double c, double d) {
724 return a * b - c * d;
725}
726
727static inline SkScalar dcross_dscale(double a, double b,
728 double c, double d, double scale) {
729 return SkDoubleToScalar(dcross(a, b, c, d) * scale);
730}
731
732static double sk_inv_determinant(const float mat[9], int isPerspective) {
733 double det;
734
735 if (isPerspective) {
736 det = mat[SkMatrix::kMScaleX] *
737 dcross(mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp2],
738 mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp1])
739 +
740 mat[SkMatrix::kMSkewX] *
741 dcross(mat[SkMatrix::kMTransY], mat[SkMatrix::kMPersp0],
742 mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp2])
743 +
744 mat[SkMatrix::kMTransX] *
745 dcross(mat[SkMatrix::kMSkewY], mat[SkMatrix::kMPersp1],
746 mat[SkMatrix::kMScaleY], mat[SkMatrix::kMPersp0]);
747 } else {
748 det = dcross(mat[SkMatrix::kMScaleX], mat[SkMatrix::kMScaleY],
749 mat[SkMatrix::kMSkewX], mat[SkMatrix::kMSkewY]);
750 }
751
752 // Since the determinant is on the order of the cube of the matrix members,
753 // compare to the cube of the default nearly-zero constant (although an
754 // estimate of the condition number would be better if it wasn't so expensive).
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700755 if (SkScalarNearlyZero(sk_double_to_float(det),
756 SK_ScalarNearlyZero * SK_ScalarNearlyZero * SK_ScalarNearlyZero)) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700757 return 0;
758 }
759 return 1.0 / det;
760}
761
762void SkMatrix::SetAffineIdentity(SkScalar affine[6]) {
763 affine[kAScaleX] = 1;
764 affine[kASkewY] = 0;
765 affine[kASkewX] = 0;
766 affine[kAScaleY] = 1;
767 affine[kATransX] = 0;
768 affine[kATransY] = 0;
769}
770
771bool SkMatrix::asAffine(SkScalar affine[6]) const {
772 if (this->hasPerspective()) {
773 return false;
774 }
775 if (affine) {
776 affine[kAScaleX] = this->fMat[kMScaleX];
777 affine[kASkewY] = this->fMat[kMSkewY];
778 affine[kASkewX] = this->fMat[kMSkewX];
779 affine[kAScaleY] = this->fMat[kMScaleY];
780 affine[kATransX] = this->fMat[kMTransX];
781 affine[kATransY] = this->fMat[kMTransY];
782 }
783 return true;
784}
785
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700786void SkMatrix::mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
787 SkASSERT((dst && src && count > 0) || 0 == count);
788 // no partial overlap
789 SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
790 this->getMapPtsProc()(*this, dst, src, count);
791}
792
793void SkMatrix::mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
794 SkASSERT(result);
795 this->getMapXYProc()(*this, x, y, result);
796}
797
Andrew Top200ce4b2018-01-29 13:43:50 -0800798void SkMatrix::ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp) {
799 SkASSERT(src != dst);
800 SkASSERT(src && dst);
801
802 if (isPersp) {
803 dst[kMScaleX] = scross_dscale(src[kMScaleY], src[kMPersp2], src[kMTransY], src[kMPersp1], invDet);
804 dst[kMSkewX] = scross_dscale(src[kMTransX], src[kMPersp1], src[kMSkewX], src[kMPersp2], invDet);
805 dst[kMTransX] = scross_dscale(src[kMSkewX], src[kMTransY], src[kMTransX], src[kMScaleY], invDet);
806
807 dst[kMSkewY] = scross_dscale(src[kMTransY], src[kMPersp0], src[kMSkewY], src[kMPersp2], invDet);
808 dst[kMScaleY] = scross_dscale(src[kMScaleX], src[kMPersp2], src[kMTransX], src[kMPersp0], invDet);
809 dst[kMTransY] = scross_dscale(src[kMTransX], src[kMSkewY], src[kMScaleX], src[kMTransY], invDet);
810
811 dst[kMPersp0] = scross_dscale(src[kMSkewY], src[kMPersp1], src[kMScaleY], src[kMPersp0], invDet);
812 dst[kMPersp1] = scross_dscale(src[kMSkewX], src[kMPersp0], src[kMScaleX], src[kMPersp1], invDet);
813 dst[kMPersp2] = scross_dscale(src[kMScaleX], src[kMScaleY], src[kMSkewX], src[kMSkewY], invDet);
814 } else { // not perspective
815 dst[kMScaleX] = SkDoubleToScalar(src[kMScaleY] * invDet);
816 dst[kMSkewX] = SkDoubleToScalar(-src[kMSkewX] * invDet);
817 dst[kMTransX] = dcross_dscale(src[kMSkewX], src[kMTransY], src[kMScaleY], src[kMTransX], invDet);
818
819 dst[kMSkewY] = SkDoubleToScalar(-src[kMSkewY] * invDet);
820 dst[kMScaleY] = SkDoubleToScalar(src[kMScaleX] * invDet);
821 dst[kMTransY] = dcross_dscale(src[kMSkewY], src[kMTransX], src[kMScaleX], src[kMTransY], invDet);
822
823 dst[kMPersp0] = 0;
824 dst[kMPersp1] = 0;
825 dst[kMPersp2] = 1;
826 }
827}
828
David Ghandehari9e5b5872016-07-28 09:50:04 -0700829bool SkMatrix::invertNonIdentity(SkMatrix* inv) const {
830 SkASSERT(!this->isIdentity());
831
832 TypeMask mask = this->getType();
833
834 if (0 == (mask & ~(kScale_Mask | kTranslate_Mask))) {
835 bool invertible = true;
836 if (inv) {
837 if (mask & kScale_Mask) {
838 SkScalar invX = fMat[kMScaleX];
839 SkScalar invY = fMat[kMScaleY];
840 if (0 == invX || 0 == invY) {
841 return false;
842 }
843 invX = SkScalarInvert(invX);
844 invY = SkScalarInvert(invY);
845
846 // Must be careful when writing to inv, since it may be the
847 // same memory as this.
848
849 inv->fMat[kMSkewX] = inv->fMat[kMSkewY] =
850 inv->fMat[kMPersp0] = inv->fMat[kMPersp1] = 0;
851
852 inv->fMat[kMScaleX] = invX;
853 inv->fMat[kMScaleY] = invY;
854 inv->fMat[kMPersp2] = 1;
855 inv->fMat[kMTransX] = -fMat[kMTransX] * invX;
856 inv->fMat[kMTransY] = -fMat[kMTransY] * invY;
857
858 inv->setTypeMask(mask | kRectStaysRect_Mask);
859 } else {
860 // translate only
861 inv->setTranslate(-fMat[kMTransX], -fMat[kMTransY]);
862 }
Andrew Top200ce4b2018-01-29 13:43:50 -0800863 } else { // inv is nullptr, just check if we're invertible
David Ghandehari9e5b5872016-07-28 09:50:04 -0700864 if (!fMat[kMScaleX] || !fMat[kMScaleY]) {
865 invertible = false;
866 }
867 }
868 return invertible;
869 }
870
871 int isPersp = mask & kPerspective_Mask;
Andrew Top200ce4b2018-01-29 13:43:50 -0800872 double invDet = sk_inv_determinant(fMat, isPersp);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700873
Andrew Top200ce4b2018-01-29 13:43:50 -0800874 if (invDet == 0) { // underflow
David Ghandehari9e5b5872016-07-28 09:50:04 -0700875 return false;
876 }
877
Andrew Top200ce4b2018-01-29 13:43:50 -0800878 bool applyingInPlace = (inv == this);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700879
Andrew Top200ce4b2018-01-29 13:43:50 -0800880 SkMatrix* tmp = inv;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700881
Andrew Top200ce4b2018-01-29 13:43:50 -0800882 SkMatrix storage;
883 if (applyingInPlace || nullptr == tmp) {
884 tmp = &storage; // we either need to avoid trampling memory or have no memory
David Ghandehari9e5b5872016-07-28 09:50:04 -0700885 }
Andrew Top200ce4b2018-01-29 13:43:50 -0800886
887 ComputeInv(tmp->fMat, fMat, invDet, isPersp);
888 if (!tmp->isFinite()) {
889 return false;
890 }
891
892 tmp->setTypeMask(fTypeMask);
893
894 if (applyingInPlace) {
895 *inv = storage; // need to copy answer back
896 }
897
David Ghandehari9e5b5872016-07-28 09:50:04 -0700898 return true;
899}
900
901///////////////////////////////////////////////////////////////////////////////
902
Andrew Top200ce4b2018-01-29 13:43:50 -0800903void SkMatrix::Identity_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700904 SkASSERT(m.getType() == 0);
905
Andrew Top200ce4b2018-01-29 13:43:50 -0800906 if (dst != src && count > 0) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700907 memcpy(dst, src, count * sizeof(SkPoint));
Andrew Top200ce4b2018-01-29 13:43:50 -0800908 }
David Ghandehari9e5b5872016-07-28 09:50:04 -0700909}
910
Andrew Top200ce4b2018-01-29 13:43:50 -0800911void SkMatrix::Trans_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
912 SkASSERT(m.getType() <= SkMatrix::kTranslate_Mask);
David Ghandehari9e5b5872016-07-28 09:50:04 -0700913 if (count > 0) {
Andrew Top200ce4b2018-01-29 13:43:50 -0800914 SkScalar tx = m.getTranslateX();
915 SkScalar ty = m.getTranslateY();
916 if (count & 1) {
David Ghandehari9e5b5872016-07-28 09:50:04 -0700917 dst->fX = src->fX + tx;
Andrew Top200ce4b2018-01-29 13:43:50 -0800918 dst->fY = src->fY + ty;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700919 src += 1;
920 dst += 1;
Andrew Top200ce4b2018-01-29 13:43:50 -0800921 }
922 Sk4s trans4(tx, ty, tx, ty);
923 count >>= 1;
924 if (count & 1) {
925 (Sk4s::Load(src) + trans4).store(dst);
926 src += 2;
927 dst += 2;
928 }
929 count >>= 1;
930 for (int i = 0; i < count; ++i) {
931 (Sk4s::Load(src+0) + trans4).store(dst+0);
932 (Sk4s::Load(src+2) + trans4).store(dst+2);
933 src += 4;
934 dst += 4;
935 }
David Ghandehari9e5b5872016-07-28 09:50:04 -0700936 }
937}
938
Andrew Top200ce4b2018-01-29 13:43:50 -0800939void SkMatrix::Scale_pts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
940 SkASSERT(m.getType() <= (SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask));
David Ghandehari9e5b5872016-07-28 09:50:04 -0700941 if (count > 0) {
Andrew Top200ce4b2018-01-29 13:43:50 -0800942 SkScalar tx = m.getTranslateX();
943 SkScalar ty = m.getTranslateY();
944 SkScalar sx = m.getScaleX();
945 SkScalar sy = m.getScaleY();
946 if (count & 1) {
947 dst->fX = src->fX * sx + tx;
948 dst->fY = src->fY * sy + ty;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700949 src += 1;
950 dst += 1;
Andrew Top200ce4b2018-01-29 13:43:50 -0800951 }
952 Sk4s trans4(tx, ty, tx, ty);
953 Sk4s scale4(sx, sy, sx, sy);
954 count >>= 1;
955 if (count & 1) {
956 (Sk4s::Load(src) * scale4 + trans4).store(dst);
957 src += 2;
958 dst += 2;
959 }
960 count >>= 1;
961 for (int i = 0; i < count; ++i) {
962 (Sk4s::Load(src+0) * scale4 + trans4).store(dst+0);
963 (Sk4s::Load(src+2) * scale4 + trans4).store(dst+2);
964 src += 4;
965 dst += 4;
966 }
David Ghandehari9e5b5872016-07-28 09:50:04 -0700967 }
968}
969
970void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
971 const SkPoint src[], int count) {
972 SkASSERT(m.hasPerspective());
973
974 if (count > 0) {
975 do {
976 SkScalar sy = src->fY;
977 SkScalar sx = src->fX;
978 src += 1;
979
980 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
981 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
982#ifdef SK_LEGACY_MATRIX_MATH_ORDER
983 SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]);
984#else
985 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
986#endif
987 if (z) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -0700988 z = 1 / z;
David Ghandehari9e5b5872016-07-28 09:50:04 -0700989 }
990
991 dst->fY = y * z;
992 dst->fX = x * z;
993 dst += 1;
994 } while (--count);
995 }
996}
997
Andrew Top200ce4b2018-01-29 13:43:50 -0800998void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
999 SkASSERT(m.getType() != SkMatrix::kPerspective_Mask);
1000 if (count > 0) {
1001 SkScalar tx = m.getTranslateX();
1002 SkScalar ty = m.getTranslateY();
1003 SkScalar sx = m.getScaleX();
1004 SkScalar sy = m.getScaleY();
1005 SkScalar kx = m.getSkewX();
1006 SkScalar ky = m.getSkewY();
1007 if (count & 1) {
1008 dst->set(src->fX * sx + src->fY * kx + tx,
1009 src->fX * ky + src->fY * sy + ty);
1010 src += 1;
1011 dst += 1;
1012 }
1013 Sk4s trans4(tx, ty, tx, ty);
1014 Sk4s scale4(sx, sy, sx, sy);
1015 Sk4s skew4(kx, ky, kx, ky); // applied to swizzle of src4
1016 count >>= 1;
1017 for (int i = 0; i < count; ++i) {
1018 Sk4s src4 = Sk4s::Load(src);
1019 Sk4s swz4 = SkNx_shuffle<1,0,3,2>(src4); // y0 x0, y1 x1
1020 (src4 * scale4 + swz4 * skew4 + trans4).store(dst);
1021 src += 2;
1022 dst += 2;
1023 }
1024 }
1025}
1026
David Ghandehari9e5b5872016-07-28 09:50:04 -07001027const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
1028 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
Andrew Top200ce4b2018-01-29 13:43:50 -08001029 SkMatrix::Scale_pts, SkMatrix::Scale_pts,
1030 SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
1031 SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
David Ghandehari9e5b5872016-07-28 09:50:04 -07001032 // repeat the persp proc 8 times
1033 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1034 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1035 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1036 SkMatrix::Persp_pts, SkMatrix::Persp_pts
1037};
1038
David Ghandehari9e5b5872016-07-28 09:50:04 -07001039///////////////////////////////////////////////////////////////////////////////
1040
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001041void SkMatrixPriv::MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[],
1042 size_t dstStride, const SkPoint3 src[],
1043 size_t srcStride, int count) {
David Ghandehari9e5b5872016-07-28 09:50:04 -07001044 SkASSERT((dst && src && count > 0) || 0 == count);
1045 // no partial overlap
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001046 SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001047
1048 if (count > 0) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001049 if (mx.isIdentity()) {
1050 if (src != dst) {
1051 if (srcStride == sizeof(SkPoint3) && dstStride == sizeof(SkPoint3)) {
1052 memcpy(dst, src, count * sizeof(SkPoint3));
1053 } else {
1054 for (int i = 0; i < count; ++i) {
1055 *dst = *src;
1056 dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
1057 src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) +
1058 srcStride);
1059 }
1060 }
1061 }
David Ghandehari9e5b5872016-07-28 09:50:04 -07001062 return;
1063 }
1064 do {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001065 SkScalar sx = src->fX;
1066 SkScalar sy = src->fY;
1067 SkScalar sw = src->fZ;
1068 src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) + srcStride);
1069 const SkScalar* mat = mx.fMat;
1070 typedef SkMatrix M;
1071 SkScalar x = sdot(sx, mat[M::kMScaleX], sy, mat[M::kMSkewX], sw, mat[M::kMTransX]);
1072 SkScalar y = sdot(sx, mat[M::kMSkewY], sy, mat[M::kMScaleY], sw, mat[M::kMTransY]);
1073 SkScalar w = sdot(sx, mat[M::kMPersp0], sy, mat[M::kMPersp1], sw, mat[M::kMPersp2]);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001074
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001075 dst->set(x, y, w);
1076 dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001077 } while (--count);
1078 }
1079}
1080
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001081void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const {
1082 SkMatrixPriv::MapHomogeneousPointsWithStride(*this, dst, sizeof(SkPoint3), src,
1083 sizeof(SkPoint3), count);
1084}
1085
David Ghandehari9e5b5872016-07-28 09:50:04 -07001086///////////////////////////////////////////////////////////////////////////////
1087
1088void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
1089 if (this->hasPerspective()) {
1090 SkPoint origin;
1091
1092 MapXYProc proc = this->getMapXYProc();
1093 proc(*this, 0, 0, &origin);
1094
1095 for (int i = count - 1; i >= 0; --i) {
1096 SkPoint tmp;
1097
1098 proc(*this, src[i].fX, src[i].fY, &tmp);
1099 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1100 }
1101 } else {
1102 SkMatrix tmp = *this;
1103
1104 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1105 tmp.clearTypeMask(kTranslate_Mask);
1106 tmp.mapPoints(dst, src, count);
1107 }
1108}
1109
Andrew Top200ce4b2018-01-29 13:43:50 -08001110static Sk4f sort_as_rect(const Sk4f& ltrb) {
1111 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1112 Sk4f min = Sk4f::Min(ltrb, rblt);
1113 Sk4f max = Sk4f::Max(ltrb, rblt);
1114 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1115 // ARM this sequence generates the fastest (a single instruction).
1116 return Sk4f(min[2], min[3], max[0], max[1]);
1117}
1118
1119void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
1120 SkASSERT(dst);
1121 SkASSERT(this->isScaleTranslate());
1122
1123 SkScalar sx = fMat[kMScaleX];
1124 SkScalar sy = fMat[kMScaleY];
1125 SkScalar tx = fMat[kMTransX];
1126 SkScalar ty = fMat[kMTransY];
1127 Sk4f scale(sx, sy, sx, sy);
1128 Sk4f trans(tx, ty, tx, ty);
1129 sort_as_rect(Sk4f::Load(&src.fLeft) * scale + trans).store(&dst->fLeft);
1130}
1131
David Ghandehari9e5b5872016-07-28 09:50:04 -07001132bool SkMatrix::mapRect(SkRect* dst, const SkRect& src) const {
1133 SkASSERT(dst);
1134
Andrew Top200ce4b2018-01-29 13:43:50 -08001135 if (this->getType() <= kTranslate_Mask) {
1136 SkScalar tx = fMat[kMTransX];
1137 SkScalar ty = fMat[kMTransY];
1138 Sk4f trans(tx, ty, tx, ty);
1139 sort_as_rect(Sk4f::Load(&src.fLeft) + trans).store(&dst->fLeft);
1140 return true;
1141 }
1142 if (this->isScaleTranslate()) {
1143 this->mapRectScaleTranslate(dst, src);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001144 return true;
1145 } else {
1146 SkPoint quad[4];
1147
1148 src.toQuad(quad);
1149 this->mapPoints(quad, quad, 4);
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001150 dst->setBoundsNoCheck(quad, 4);
1151 return this->rectStaysRect(); // might still return true if rotated by 90, etc.
David Ghandehari9e5b5872016-07-28 09:50:04 -07001152 }
1153}
1154
1155SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1156 SkVector vec[2];
1157
1158 vec[0].set(radius, 0);
1159 vec[1].set(0, radius);
1160 this->mapVectors(vec, 2);
1161
1162 SkScalar d0 = vec[0].length();
1163 SkScalar d1 = vec[1].length();
1164
1165 // return geometric mean
1166 return SkScalarSqrt(d0 * d1);
1167}
1168
1169///////////////////////////////////////////////////////////////////////////////
1170
1171void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1172 SkPoint* pt) {
1173 SkASSERT(m.hasPerspective());
1174
1175 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1176 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1177 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1178 if (z) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001179 z = 1 / z;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001180 }
1181 pt->fX = x * z;
1182 pt->fY = y * z;
1183}
1184
1185void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1186 SkPoint* pt) {
1187 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1188
1189#ifdef SK_LEGACY_MATRIX_MATH_ORDER
1190 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1191 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1192#else
1193 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1194 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1195#endif
1196}
1197
1198void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1199 SkPoint* pt) {
1200 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1201 SkASSERT(0 == m.fMat[kMTransX]);
1202 SkASSERT(0 == m.fMat[kMTransY]);
1203
1204#ifdef SK_LEGACY_MATRIX_MATH_ORDER
1205 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1206 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1207#else
1208 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1209 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1210#endif
1211}
1212
1213void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1214 SkPoint* pt) {
1215 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1216 == kScale_Mask);
1217
1218 pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
1219 pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
1220}
1221
1222void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1223 SkPoint* pt) {
1224 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1225 == kScale_Mask);
1226 SkASSERT(0 == m.fMat[kMTransX]);
1227 SkASSERT(0 == m.fMat[kMTransY]);
1228
1229 pt->fX = sx * m.fMat[kMScaleX];
1230 pt->fY = sy * m.fMat[kMScaleY];
1231}
1232
1233void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1234 SkPoint* pt) {
1235 SkASSERT(m.getType() == kTranslate_Mask);
1236
1237 pt->fX = sx + m.fMat[kMTransX];
1238 pt->fY = sy + m.fMat[kMTransY];
1239}
1240
1241void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1242 SkPoint* pt) {
1243 SkASSERT(0 == m.getType());
1244
1245 pt->fX = sx;
1246 pt->fY = sy;
1247}
1248
1249const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1250 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1251 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1252 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1253 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1254 // repeat the persp proc 8 times
1255 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1256 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1257 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1258 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1259};
1260
1261///////////////////////////////////////////////////////////////////////////////
1262
1263// if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1264#define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1265
Andrew Top200ce4b2018-01-29 13:43:50 -08001266bool SkMatrix::isFixedStepInX() const {
1267 return PerspNearlyZero(fMat[kMPersp0]);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001268}
1269
Andrew Top200ce4b2018-01-29 13:43:50 -08001270SkVector SkMatrix::fixedStepInX(SkScalar y) const {
1271 SkASSERT(PerspNearlyZero(fMat[kMPersp0]));
1272 if (PerspNearlyZero(fMat[kMPersp1]) &&
1273 PerspNearlyZero(fMat[kMPersp2] - 1)) {
1274 return SkVector::Make(fMat[kMScaleX], fMat[kMSkewY]);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001275 } else {
Andrew Top200ce4b2018-01-29 13:43:50 -08001276 SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
1277 return SkVector::Make(fMat[kMScaleX] / z, fMat[kMSkewY] / z);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001278 }
David Ghandehari9e5b5872016-07-28 09:50:04 -07001279}
1280
1281///////////////////////////////////////////////////////////////////////////////
1282
1283static inline bool checkForZero(float x) {
1284 return x*x == 0;
1285}
1286
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001287bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst) {
1288 dst->fMat[kMScaleX] = srcPt[1].fY - srcPt[0].fY;
1289 dst->fMat[kMSkewY] = srcPt[0].fX - srcPt[1].fX;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001290 dst->fMat[kMPersp0] = 0;
1291
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001292 dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
1293 dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001294 dst->fMat[kMPersp1] = 0;
1295
1296 dst->fMat[kMTransX] = srcPt[0].fX;
1297 dst->fMat[kMTransY] = srcPt[0].fY;
1298 dst->fMat[kMPersp2] = 1;
1299 dst->setTypeMask(kUnknown_Mask);
1300 return true;
1301}
1302
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001303bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst) {
1304 dst->fMat[kMScaleX] = srcPt[2].fX - srcPt[0].fX;
1305 dst->fMat[kMSkewY] = srcPt[2].fY - srcPt[0].fY;
1306 dst->fMat[kMPersp0] = 0;
1307
1308 dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
1309 dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
1310 dst->fMat[kMPersp1] = 0;
1311
1312 dst->fMat[kMTransX] = srcPt[0].fX;
1313 dst->fMat[kMTransY] = srcPt[0].fY;
1314 dst->fMat[kMPersp2] = 1;
1315 dst->setTypeMask(kUnknown_Mask);
1316 return true;
1317}
1318
1319bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst) {
David Ghandehari9e5b5872016-07-28 09:50:04 -07001320 float a1, a2;
1321 float x0, y0, x1, y1, x2, y2;
1322
1323 x0 = srcPt[2].fX - srcPt[0].fX;
1324 y0 = srcPt[2].fY - srcPt[0].fY;
1325 x1 = srcPt[2].fX - srcPt[1].fX;
1326 y1 = srcPt[2].fY - srcPt[1].fY;
1327 x2 = srcPt[2].fX - srcPt[3].fX;
1328 y2 = srcPt[2].fY - srcPt[3].fY;
1329
1330 /* check if abs(x2) > abs(y2) */
1331 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001332 float denom = sk_ieee_float_divide(x1 * y2, x2) - y1;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001333 if (checkForZero(denom)) {
1334 return false;
1335 }
Andrew Top200ce4b2018-01-29 13:43:50 -08001336 a1 = (((x0 - x1) * y2 / x2) - y0 + y1) / denom;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001337 } else {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001338 float denom = x1 - sk_ieee_float_divide(y1 * x2, y2);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001339 if (checkForZero(denom)) {
1340 return false;
1341 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001342 a1 = (x0 - x1 - sk_ieee_float_divide((y0 - y1) * x2, y2)) / denom;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001343 }
1344
1345 /* check if abs(x1) > abs(y1) */
1346 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001347 float denom = y2 - sk_ieee_float_divide(x2 * y1, x1);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001348 if (checkForZero(denom)) {
1349 return false;
1350 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001351 a2 = (y0 - y2 - sk_ieee_float_divide((x0 - x2) * y1, x1)) / denom;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001352 } else {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001353 float denom = sk_ieee_float_divide(y2 * x1, y1) - x2;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001354 if (checkForZero(denom)) {
1355 return false;
1356 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001357 a2 = (sk_ieee_float_divide((y0 - y2) * x1, y1) - x0 + x2) / denom;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001358 }
1359
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001360 dst->fMat[kMScaleX] = a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX;
1361 dst->fMat[kMSkewY] = a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY;
1362 dst->fMat[kMPersp0] = a2;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001363
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001364 dst->fMat[kMSkewX] = a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX;
1365 dst->fMat[kMScaleY] = a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY;
1366 dst->fMat[kMPersp1] = a1;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001367
1368 dst->fMat[kMTransX] = srcPt[0].fX;
1369 dst->fMat[kMTransY] = srcPt[0].fY;
1370 dst->fMat[kMPersp2] = 1;
1371 dst->setTypeMask(kUnknown_Mask);
1372 return true;
1373}
1374
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001375typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001376
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001377/* Adapted from Rob Johnson's original sample code in QuickDraw GX
David Ghandehari9e5b5872016-07-28 09:50:04 -07001378*/
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001379bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count) {
David Ghandehari9e5b5872016-07-28 09:50:04 -07001380 if ((unsigned)count > 4) {
1381 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1382 return false;
1383 }
1384
1385 if (0 == count) {
1386 this->reset();
1387 return true;
1388 }
1389 if (1 == count) {
1390 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1391 return true;
1392 }
1393
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001394 const PolyMapProc gPolyMapProcs[] = {
David Ghandehari9e5b5872016-07-28 09:50:04 -07001395 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1396 };
1397 PolyMapProc proc = gPolyMapProcs[count - 2];
1398
1399 SkMatrix tempMap, result;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001400
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001401 if (!proc(src, &tempMap)) {
David Ghandehari9e5b5872016-07-28 09:50:04 -07001402 return false;
1403 }
1404 if (!tempMap.invert(&result)) {
1405 return false;
1406 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001407 if (!proc(dst, &tempMap)) {
David Ghandehari9e5b5872016-07-28 09:50:04 -07001408 return false;
1409 }
1410 this->setConcat(tempMap, result);
1411 return true;
1412}
1413
1414///////////////////////////////////////////////////////////////////////////////
1415
1416enum MinMaxOrBoth {
1417 kMin_MinMaxOrBoth,
1418 kMax_MinMaxOrBoth,
1419 kBoth_MinMaxOrBoth
1420};
1421
1422template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
1423 const SkScalar m[9],
1424 SkScalar results[/*1 or 2*/]) {
1425 if (typeMask & SkMatrix::kPerspective_Mask) {
1426 return false;
1427 }
1428 if (SkMatrix::kIdentity_Mask == typeMask) {
1429 results[0] = SK_Scalar1;
1430 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1431 results[1] = SK_Scalar1;
1432 }
1433 return true;
1434 }
1435 if (!(typeMask & SkMatrix::kAffine_Mask)) {
1436 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1437 results[0] = SkMinScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1438 SkScalarAbs(m[SkMatrix::kMScaleY]));
1439 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1440 results[0] = SkMaxScalar(SkScalarAbs(m[SkMatrix::kMScaleX]),
1441 SkScalarAbs(m[SkMatrix::kMScaleY]));
1442 } else {
1443 results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
1444 results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
1445 if (results[0] > results[1]) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001446 using std::swap;
1447 swap(results[0], results[1]);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001448 }
1449 }
1450 return true;
1451 }
1452 // ignore the translation part of the matrix, just look at 2x2 portion.
1453 // compute singular values, take largest or smallest abs value.
1454 // [a b; b c] = A^T*A
1455 SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
1456 m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
1457 SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
1458 m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
1459 SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX],
1460 m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
1461 // eigenvalues of A^T*A are the squared singular values of A.
1462 // characteristic equation is det((A^T*A) - l*I) = 0
1463 // l^2 - (a + c)l + (ac-b^2)
1464 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1465 // and roots are guaranteed to be pos and real).
1466 SkScalar bSqd = b * b;
1467 // if upper left 2x2 is orthogonal save some math
1468 if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
1469 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1470 results[0] = SkMinScalar(a, c);
1471 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1472 results[0] = SkMaxScalar(a, c);
1473 } else {
1474 results[0] = a;
1475 results[1] = c;
1476 if (results[0] > results[1]) {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001477 using std::swap;
1478 swap(results[0], results[1]);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001479 }
1480 }
1481 } else {
1482 SkScalar aminusc = a - c;
1483 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1484 SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
1485 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1486 results[0] = apluscdiv2 - x;
1487 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1488 results[0] = apluscdiv2 + x;
1489 } else {
1490 results[0] = apluscdiv2 - x;
1491 results[1] = apluscdiv2 + x;
1492 }
Mike Fleming3933d922018-04-02 10:53:08 -07001493
1494#if defined(COBALT)
1495 // If |x| and |apluscdiv2| are very large floating point numbers
1496 // that are close to each other, there might be floating point
1497 // inaccuracies in calculating the eigenvalues.
1498 const SkScalar kLargeNumber = 1E12;
1499 if ((SkScalarAbs(x) > kLargeNumber) &&
1500 (SkScalarAbs(apluscdiv2) > kLargeNumber) &&
1501 SkScalarNearlyZero(x/apluscdiv2 - 1)) {
1502 results[0] = 0;
1503 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1504 results[1] = 0;
1505 }
1506 SB_DLOG(WARNING) << "Unable to calculate scale factor of a matrix.";
1507 return false;
1508 }
1509#endif
David Ghandehari9e5b5872016-07-28 09:50:04 -07001510 }
Andrew Top200ce4b2018-01-29 13:43:50 -08001511 if (!SkScalarIsFinite(results[0])) {
1512 return false;
1513 }
1514 // Due to the floating point inaccuracy, there might be an error in a, b, c
1515 // calculated by sdot, further deepened by subsequent arithmetic operations
1516 // on them. Therefore, we allow and cap the nearly-zero negative values.
1517 SkASSERT(results[0] >= -SK_ScalarNearlyZero);
1518 if (results[0] < 0) {
1519 results[0] = 0;
1520 }
David Ghandehari9e5b5872016-07-28 09:50:04 -07001521 results[0] = SkScalarSqrt(results[0]);
1522 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
Andrew Top200ce4b2018-01-29 13:43:50 -08001523 if (!SkScalarIsFinite(results[1])) {
1524 return false;
1525 }
1526 SkASSERT(results[1] >= -SK_ScalarNearlyZero);
1527 if (results[1] < 0) {
1528 results[1] = 0;
1529 }
David Ghandehari9e5b5872016-07-28 09:50:04 -07001530 results[1] = SkScalarSqrt(results[1]);
1531 }
1532 return true;
1533}
1534
1535SkScalar SkMatrix::getMinScale() const {
1536 SkScalar factor;
1537 if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1538 return factor;
1539 } else {
1540 return -1;
1541 }
1542}
1543
1544SkScalar SkMatrix::getMaxScale() const {
1545 SkScalar factor;
1546 if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1547 return factor;
1548 } else {
1549 return -1;
1550 }
1551}
1552
1553bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1554 return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1555}
1556
David Ghandehari9e5b5872016-07-28 09:50:04 -07001557const SkMatrix& SkMatrix::I() {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001558 static constexpr SkMatrix identity;
1559 SkASSERT(identity.isIdentity());
1560 return identity;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001561}
1562
1563const SkMatrix& SkMatrix::InvalidMatrix() {
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001564 static constexpr SkMatrix invalid(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1565 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1566 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1567 kTranslate_Mask | kScale_Mask |
1568 kAffine_Mask | kPerspective_Mask);
1569 return invalid;
David Ghandehari9e5b5872016-07-28 09:50:04 -07001570}
1571
Andrew Top200ce4b2018-01-29 13:43:50 -08001572bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const {
1573 if (this->hasPerspective()) {
1574 return false;
1575 }
1576
1577 const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY());
1578 const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY());
1579 if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) ||
1580 SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) {
1581 return false;
1582 }
1583
1584 if (scale) {
1585 scale->set(sx, sy);
1586 }
1587 if (remaining) {
1588 *remaining = *this;
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001589 remaining->preScale(SkScalarInvert(sx), SkScalarInvert(sy));
Andrew Top200ce4b2018-01-29 13:43:50 -08001590 }
1591 return true;
1592}
1593
David Ghandehari9e5b5872016-07-28 09:50:04 -07001594///////////////////////////////////////////////////////////////////////////////
1595
1596size_t SkMatrix::writeToMemory(void* buffer) const {
1597 // TODO write less for simple matrices
1598 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1599 if (buffer) {
1600 memcpy(buffer, fMat, sizeInMemory);
1601 }
1602 return sizeInMemory;
1603}
1604
1605size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
1606 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1607 if (length < sizeInMemory) {
1608 return 0;
1609 }
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001610 memcpy(fMat, buffer, sizeInMemory);
1611 this->setTypeMask(kUnknown_Mask);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001612 return sizeInMemory;
1613}
1614
David Ghandehari9e5b5872016-07-28 09:50:04 -07001615void SkMatrix::dump() const {
1616 SkString str;
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001617 str.appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
David Ghandehari9e5b5872016-07-28 09:50:04 -07001618 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1619 fMat[6], fMat[7], fMat[8]);
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001620 SkDebugf("%s\n", str.c_str());
David Ghandehari9e5b5872016-07-28 09:50:04 -07001621}
David Ghandehari9e5b5872016-07-28 09:50:04 -07001622
1623///////////////////////////////////////////////////////////////////////////////
1624
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001625#include "src/core/SkMatrixUtils.h"
David Ghandehari9e5b5872016-07-28 09:50:04 -07001626
Andrew Top200ce4b2018-01-29 13:43:50 -08001627bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkPaint& paint) {
1628 // Our path aa is 2-bits, and our rect aa is 8, so we could use 8,
1629 // but in practice 4 seems enough (still looks smooth) and allows
1630 // more slightly fractional cases to fall into the fast (sprite) case.
1631 static const unsigned kAntiAliasSubpixelBits = 4;
1632
1633 const unsigned subpixelBits = paint.isAntiAlias() ? kAntiAliasSubpixelBits : 0;
1634
David Ghandehari9e5b5872016-07-28 09:50:04 -07001635 // quick reject on affine or perspective
1636 if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
1637 return false;
1638 }
1639
1640 // quick success check
1641 if (!subpixelBits && !(mat.getType() & ~SkMatrix::kTranslate_Mask)) {
1642 return true;
1643 }
1644
1645 // mapRect supports negative scales, so we eliminate those first
1646 if (mat.getScaleX() < 0 || mat.getScaleY() < 0) {
1647 return false;
1648 }
1649
1650 SkRect dst;
Andrew Top200ce4b2018-01-29 13:43:50 -08001651 SkIRect isrc = SkIRect::MakeSize(size);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001652
1653 {
1654 SkRect src;
1655 src.set(isrc);
1656 mat.mapRect(&dst, src);
1657 }
1658
1659 // just apply the translate to isrc
1660 isrc.offset(SkScalarRoundToInt(mat.getTranslateX()),
1661 SkScalarRoundToInt(mat.getTranslateY()));
1662
1663 if (subpixelBits) {
Andrew Top200ce4b2018-01-29 13:43:50 -08001664 isrc.fLeft = SkLeftShift(isrc.fLeft, subpixelBits);
1665 isrc.fTop = SkLeftShift(isrc.fTop, subpixelBits);
1666 isrc.fRight = SkLeftShift(isrc.fRight, subpixelBits);
1667 isrc.fBottom = SkLeftShift(isrc.fBottom, subpixelBits);
David Ghandehari9e5b5872016-07-28 09:50:04 -07001668
1669 const float scale = 1 << subpixelBits;
1670 dst.fLeft *= scale;
1671 dst.fTop *= scale;
1672 dst.fRight *= scale;
1673 dst.fBottom *= scale;
1674 }
1675
1676 SkIRect idst;
1677 dst.round(&idst);
1678 return isrc == idst;
1679}
1680
1681// A square matrix M can be decomposed (via polar decomposition) into two matrices --
1682// an orthogonal matrix Q and a symmetric matrix S. In turn we can decompose S into U*W*U^T,
1683// where U is another orthogonal matrix and W is a scale matrix. These can be recombined
1684// to give M = (Q*U)*W*U^T, i.e., the product of two orthogonal matrices and a scale matrix.
1685//
1686// The one wrinkle is that traditionally Q may contain a reflection -- the
1687// calculation has been rejiggered to put that reflection into W.
1688bool SkDecomposeUpper2x2(const SkMatrix& matrix,
1689 SkPoint* rotation1,
1690 SkPoint* scale,
1691 SkPoint* rotation2) {
1692
1693 SkScalar A = matrix[SkMatrix::kMScaleX];
1694 SkScalar B = matrix[SkMatrix::kMSkewX];
1695 SkScalar C = matrix[SkMatrix::kMSkewY];
1696 SkScalar D = matrix[SkMatrix::kMScaleY];
1697
1698 if (is_degenerate_2x2(A, B, C, D)) {
1699 return false;
1700 }
1701
1702 double w1, w2;
1703 SkScalar cos1, sin1;
1704 SkScalar cos2, sin2;
1705
1706 // do polar decomposition (M = Q*S)
1707 SkScalar cosQ, sinQ;
1708 double Sa, Sb, Sd;
1709 // if M is already symmetric (i.e., M = I*S)
1710 if (SkScalarNearlyEqual(B, C)) {
1711 cosQ = 1;
1712 sinQ = 0;
1713
1714 Sa = A;
1715 Sb = B;
1716 Sd = D;
1717 } else {
1718 cosQ = A + D;
1719 sinQ = C - B;
1720 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cosQ*cosQ + sinQ*sinQ));
1721 cosQ *= reciplen;
1722 sinQ *= reciplen;
1723
1724 // S = Q^-1*M
1725 // we don't calc Sc since it's symmetric
1726 Sa = A*cosQ + C*sinQ;
1727 Sb = B*cosQ + D*sinQ;
1728 Sd = -B*sinQ + D*cosQ;
1729 }
1730
1731 // Now we need to compute eigenvalues of S (our scale factors)
1732 // and eigenvectors (bases for our rotation)
1733 // From this, should be able to reconstruct S as U*W*U^T
1734 if (SkScalarNearlyZero(SkDoubleToScalar(Sb))) {
1735 // already diagonalized
1736 cos1 = 1;
1737 sin1 = 0;
1738 w1 = Sa;
1739 w2 = Sd;
1740 cos2 = cosQ;
1741 sin2 = sinQ;
1742 } else {
1743 double diff = Sa - Sd;
1744 double discriminant = sqrt(diff*diff + 4.0*Sb*Sb);
1745 double trace = Sa + Sd;
1746 if (diff > 0) {
1747 w1 = 0.5*(trace + discriminant);
1748 w2 = 0.5*(trace - discriminant);
1749 } else {
1750 w1 = 0.5*(trace - discriminant);
1751 w2 = 0.5*(trace + discriminant);
1752 }
1753
1754 cos1 = SkDoubleToScalar(Sb); sin1 = SkDoubleToScalar(w1 - Sa);
1755 SkScalar reciplen = SkScalarInvert(SkScalarSqrt(cos1*cos1 + sin1*sin1));
1756 cos1 *= reciplen;
1757 sin1 *= reciplen;
1758
1759 // rotation 2 is composition of Q and U
1760 cos2 = cos1*cosQ - sin1*sinQ;
1761 sin2 = sin1*cosQ + cos1*sinQ;
1762
1763 // rotation 1 is U^T
1764 sin1 = -sin1;
1765 }
1766
1767 if (scale) {
1768 scale->fX = SkDoubleToScalar(w1);
1769 scale->fY = SkDoubleToScalar(w2);
1770 }
1771 if (rotation1) {
1772 rotation1->fX = cos1;
1773 rotation1->fY = sin1;
1774 }
1775 if (rotation2) {
1776 rotation2->fX = cos2;
1777 rotation2->fY = sin2;
1778 }
1779
1780 return true;
1781}
Andrew Top200ce4b2018-01-29 13:43:50 -08001782
1783//////////////////////////////////////////////////////////////////////////////////////////////////
1784
1785void SkRSXform::toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const {
1786#if 0
1787 // This is the slow way, but it documents what we're doing
1788 quad[0].set(0, 0);
1789 quad[1].set(width, 0);
1790 quad[2].set(width, height);
1791 quad[3].set(0, height);
1792 SkMatrix m;
1793 m.setRSXform(*this).mapPoints(quad, quad, 4);
1794#else
1795 const SkScalar m00 = fSCos;
1796 const SkScalar m01 = -fSSin;
1797 const SkScalar m02 = fTx;
1798 const SkScalar m10 = -m01;
1799 const SkScalar m11 = m00;
1800 const SkScalar m12 = fTy;
1801
1802 quad[0].set(m02, m12);
1803 quad[1].set(m00 * width + m02, m10 * width + m12);
1804 quad[2].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
1805 quad[3].set(m01 * height + m02, m11 * height + m12);
1806#endif
1807}
Xiaoming Shi73dfa202020-03-12 11:31:35 -07001808
1809void SkRSXform::toTriStrip(SkScalar width, SkScalar height, SkPoint strip[4]) const {
1810 const SkScalar m00 = fSCos;
1811 const SkScalar m01 = -fSSin;
1812 const SkScalar m02 = fTx;
1813 const SkScalar m10 = -m01;
1814 const SkScalar m11 = m00;
1815 const SkScalar m12 = fTy;
1816
1817 strip[0].set(m02, m12);
1818 strip[1].set(m01 * height + m02, m11 * height + m12);
1819 strip[2].set(m00 * width + m02, m10 * width + m12);
1820 strip[3].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
1821}
1822
1823///////////////////////////////////////////////////////////////////////////////////////////////////
1824
1825SkFilterQuality SkMatrixPriv::AdjustHighQualityFilterLevel(const SkMatrix& matrix,
1826 bool matrixIsInverse) {
1827 if (matrix.isIdentity()) {
1828 return kNone_SkFilterQuality;
1829 }
1830
1831 auto is_minimizing = [&](SkScalar scale) {
1832 return matrixIsInverse ? scale > 1 : scale < 1;
1833 };
1834
1835 SkScalar scales[2];
1836 if (!matrix.getMinMaxScales(scales) || is_minimizing(scales[0])) {
1837 // Bicubic doesn't handle arbitrary minimization well, as src texels can be skipped
1838 // entirely,
1839 return kMedium_SkFilterQuality;
1840 }
1841
1842 // At this point if scales[1] == SK_Scalar1 then the matrix doesn't do any scaling.
1843 if (scales[1] == SK_Scalar1) {
1844 if (matrix.rectStaysRect() && SkScalarIsInt(matrix.getTranslateX()) &&
1845 SkScalarIsInt(matrix.getTranslateY())) {
1846 return kNone_SkFilterQuality;
1847 } else {
1848 // Use bilerp to handle rotation or fractional translation.
1849 return kLow_SkFilterQuality;
1850 }
1851 }
1852
1853 return kHigh_SkFilterQuality;
1854}