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