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