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