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 if (count & 1) {
940 dst->fX = src->fX * sx + tx;
941 dst->fY = src->fY * sy + ty;
942 src += 1;
943 dst += 1;
944 }
945 Sk4s trans4(tx, ty, tx, ty);
946 Sk4s scale4(sx, sy, sx, sy);
947 count >>= 1;
948 if (count & 1) {
949 (Sk4s::Load(src) * scale4 + trans4).store(dst);
950 src += 2;
951 dst += 2;
952 }
953 count >>= 1;
954 for (int i = 0; i < count; ++i) {
955 (Sk4s::Load(src+0) * scale4 + trans4).store(dst+0);
956 (Sk4s::Load(src+2) * scale4 + trans4).store(dst+2);
957 src += 4;
958 dst += 4;
959 }
960 }
961 }
962
Persp_pts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)963 void SkMatrix::Persp_pts(const SkMatrix& m, SkPoint dst[],
964 const SkPoint src[], int count) {
965 SkASSERT(m.hasPerspective());
966
967 if (count > 0) {
968 do {
969 SkScalar sy = src->fY;
970 SkScalar sx = src->fX;
971 src += 1;
972
973 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
974 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
975 #ifdef SK_LEGACY_MATRIX_MATH_ORDER
976 SkScalar z = sx * m.fMat[kMPersp0] + (sy * m.fMat[kMPersp1] + m.fMat[kMPersp2]);
977 #else
978 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
979 #endif
980 if (z) {
981 z = 1 / z;
982 }
983
984 dst->fY = y * z;
985 dst->fX = x * z;
986 dst += 1;
987 } while (--count);
988 }
989 }
990
Affine_vpts(const SkMatrix & m,SkPoint dst[],const SkPoint src[],int count)991 void SkMatrix::Affine_vpts(const SkMatrix& m, SkPoint dst[], const SkPoint src[], int count) {
992 SkASSERT(m.getType() != SkMatrix::kPerspective_Mask);
993 if (count > 0) {
994 SkScalar tx = m.getTranslateX();
995 SkScalar ty = m.getTranslateY();
996 SkScalar sx = m.getScaleX();
997 SkScalar sy = m.getScaleY();
998 SkScalar kx = m.getSkewX();
999 SkScalar ky = m.getSkewY();
1000 if (count & 1) {
1001 dst->set(src->fX * sx + src->fY * kx + tx,
1002 src->fX * ky + src->fY * sy + ty);
1003 src += 1;
1004 dst += 1;
1005 }
1006 Sk4s trans4(tx, ty, tx, ty);
1007 Sk4s scale4(sx, sy, sx, sy);
1008 Sk4s skew4(kx, ky, kx, ky); // applied to swizzle of src4
1009 count >>= 1;
1010 for (int i = 0; i < count; ++i) {
1011 Sk4s src4 = Sk4s::Load(src);
1012 Sk4s swz4 = SkNx_shuffle<1,0,3,2>(src4); // y0 x0, y1 x1
1013 (src4 * scale4 + swz4 * skew4 + trans4).store(dst);
1014 src += 2;
1015 dst += 2;
1016 }
1017 }
1018 }
1019
1020 const SkMatrix::MapPtsProc SkMatrix::gMapPtsProcs[] = {
1021 SkMatrix::Identity_pts, SkMatrix::Trans_pts,
1022 SkMatrix::Scale_pts, SkMatrix::Scale_pts,
1023 SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
1024 SkMatrix::Affine_vpts, SkMatrix::Affine_vpts,
1025 // repeat the persp proc 8 times
1026 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1027 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1028 SkMatrix::Persp_pts, SkMatrix::Persp_pts,
1029 SkMatrix::Persp_pts, SkMatrix::Persp_pts
1030 };
1031
1032 ///////////////////////////////////////////////////////////////////////////////
1033
MapHomogeneousPointsWithStride(const SkMatrix & mx,SkPoint3 dst[],size_t dstStride,const SkPoint3 src[],size_t srcStride,int count)1034 void SkMatrixPriv::MapHomogeneousPointsWithStride(const SkMatrix& mx, SkPoint3 dst[],
1035 size_t dstStride, const SkPoint3 src[],
1036 size_t srcStride, int count) {
1037 SkASSERT((dst && src && count > 0) || 0 == count);
1038 // no partial overlap
1039 SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
1040
1041 if (count > 0) {
1042 if (mx.isIdentity()) {
1043 if (src != dst) {
1044 if (srcStride == sizeof(SkPoint3) && dstStride == sizeof(SkPoint3)) {
1045 memcpy(dst, src, count * sizeof(SkPoint3));
1046 } else {
1047 for (int i = 0; i < count; ++i) {
1048 *dst = *src;
1049 dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
1050 src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) +
1051 srcStride);
1052 }
1053 }
1054 }
1055 return;
1056 }
1057 do {
1058 SkScalar sx = src->fX;
1059 SkScalar sy = src->fY;
1060 SkScalar sw = src->fZ;
1061 src = reinterpret_cast<const SkPoint3*>(reinterpret_cast<const char*>(src) + srcStride);
1062 const SkScalar* mat = mx.fMat;
1063 typedef SkMatrix M;
1064 SkScalar x = sdot(sx, mat[M::kMScaleX], sy, mat[M::kMSkewX], sw, mat[M::kMTransX]);
1065 SkScalar y = sdot(sx, mat[M::kMSkewY], sy, mat[M::kMScaleY], sw, mat[M::kMTransY]);
1066 SkScalar w = sdot(sx, mat[M::kMPersp0], sy, mat[M::kMPersp1], sw, mat[M::kMPersp2]);
1067
1068 dst->set(x, y, w);
1069 dst = reinterpret_cast<SkPoint3*>(reinterpret_cast<char*>(dst) + dstStride);
1070 } while (--count);
1071 }
1072 }
1073
mapHomogeneousPoints(SkPoint3 dst[],const SkPoint3 src[],int count) const1074 void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint3 src[], int count) const {
1075 SkMatrixPriv::MapHomogeneousPointsWithStride(*this, dst, sizeof(SkPoint3), src,
1076 sizeof(SkPoint3), count);
1077 }
1078
mapHomogeneousPoints(SkPoint3 dst[],const SkPoint src[],int count) const1079 void SkMatrix::mapHomogeneousPoints(SkPoint3 dst[], const SkPoint src[], int count) const {
1080 if (this->isIdentity()) {
1081 for (int i = 0; i < count; ++i) {
1082 dst[i] = { src[i].fX, src[i].fY, 1 };
1083 }
1084 } else if (this->hasPerspective()) {
1085 for (int i = 0; i < count; ++i) {
1086 dst[i] = {
1087 fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
1088 fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
1089 fMat[6] * src[i].fX + fMat[7] * src[i].fY + fMat[8],
1090 };
1091 }
1092 } else { // affine
1093 for (int i = 0; i < count; ++i) {
1094 dst[i] = {
1095 fMat[0] * src[i].fX + fMat[1] * src[i].fY + fMat[2],
1096 fMat[3] * src[i].fX + fMat[4] * src[i].fY + fMat[5],
1097 1,
1098 };
1099 }
1100 }
1101 }
1102
1103 ///////////////////////////////////////////////////////////////////////////////
1104
mapVectors(SkPoint dst[],const SkPoint src[],int count) const1105 void SkMatrix::mapVectors(SkPoint dst[], const SkPoint src[], int count) const {
1106 if (this->hasPerspective()) {
1107 SkPoint origin;
1108
1109 MapXYProc proc = this->getMapXYProc();
1110 proc(*this, 0, 0, &origin);
1111
1112 for (int i = count - 1; i >= 0; --i) {
1113 SkPoint tmp;
1114
1115 proc(*this, src[i].fX, src[i].fY, &tmp);
1116 dst[i].set(tmp.fX - origin.fX, tmp.fY - origin.fY);
1117 }
1118 } else {
1119 SkMatrix tmp = *this;
1120
1121 tmp.fMat[kMTransX] = tmp.fMat[kMTransY] = 0;
1122 tmp.clearTypeMask(kTranslate_Mask);
1123 tmp.mapPoints(dst, src, count);
1124 }
1125 }
1126
sort_as_rect(const Sk4f & ltrb)1127 static Sk4f sort_as_rect(const Sk4f& ltrb) {
1128 Sk4f rblt(ltrb[2], ltrb[3], ltrb[0], ltrb[1]);
1129 Sk4f min = Sk4f::Min(ltrb, rblt);
1130 Sk4f max = Sk4f::Max(ltrb, rblt);
1131 // We can extract either pair [0,1] or [2,3] from min and max and be correct, but on
1132 // ARM this sequence generates the fastest (a single instruction).
1133 return Sk4f(min[2], min[3], max[0], max[1]);
1134 }
1135
mapRectScaleTranslate(SkRect * dst,const SkRect & src) const1136 void SkMatrix::mapRectScaleTranslate(SkRect* dst, const SkRect& src) const {
1137 SkASSERT(dst);
1138 SkASSERT(this->isScaleTranslate());
1139
1140 SkScalar sx = fMat[kMScaleX];
1141 SkScalar sy = fMat[kMScaleY];
1142 SkScalar tx = fMat[kMTransX];
1143 SkScalar ty = fMat[kMTransY];
1144 Sk4f scale(sx, sy, sx, sy);
1145 Sk4f trans(tx, ty, tx, ty);
1146 sort_as_rect(Sk4f::Load(&src.fLeft) * scale + trans).store(&dst->fLeft);
1147 }
1148
mapRect(SkRect * dst,const SkRect & src,SkApplyPerspectiveClip pc) const1149 bool SkMatrix::mapRect(SkRect* dst, const SkRect& src, SkApplyPerspectiveClip pc) const {
1150 SkASSERT(dst);
1151
1152 if (this->getType() <= kTranslate_Mask) {
1153 SkScalar tx = fMat[kMTransX];
1154 SkScalar ty = fMat[kMTransY];
1155 Sk4f trans(tx, ty, tx, ty);
1156 sort_as_rect(Sk4f::Load(&src.fLeft) + trans).store(&dst->fLeft);
1157 return true;
1158 }
1159 if (this->isScaleTranslate()) {
1160 this->mapRectScaleTranslate(dst, src);
1161 return true;
1162 } else if (pc == SkApplyPerspectiveClip::kYes && this->hasPerspective()) {
1163 SkPath path;
1164 path.addRect(src);
1165 path.transform(*this);
1166 *dst = path.getBounds();
1167 return false;
1168 } else {
1169 SkPoint quad[4];
1170
1171 src.toQuad(quad);
1172 this->mapPoints(quad, quad, 4);
1173 dst->setBoundsNoCheck(quad, 4);
1174 return this->rectStaysRect(); // might still return true if rotated by 90, etc.
1175 }
1176 }
1177
mapRadius(SkScalar radius) const1178 SkScalar SkMatrix::mapRadius(SkScalar radius) const {
1179 SkVector vec[2];
1180
1181 vec[0].set(radius, 0);
1182 vec[1].set(0, radius);
1183 this->mapVectors(vec, 2);
1184
1185 SkScalar d0 = vec[0].length();
1186 SkScalar d1 = vec[1].length();
1187
1188 // return geometric mean
1189 return SkScalarSqrt(d0 * d1);
1190 }
1191
1192 ///////////////////////////////////////////////////////////////////////////////
1193
Persp_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1194 void SkMatrix::Persp_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1195 SkPoint* pt) {
1196 SkASSERT(m.hasPerspective());
1197
1198 SkScalar x = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1199 SkScalar y = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1200 SkScalar z = sdot(sx, m.fMat[kMPersp0], sy, m.fMat[kMPersp1]) + m.fMat[kMPersp2];
1201 if (z) {
1202 z = 1 / z;
1203 }
1204 pt->fX = x * z;
1205 pt->fY = y * z;
1206 }
1207
RotTrans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1208 void SkMatrix::RotTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1209 SkPoint* pt) {
1210 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask)) == kAffine_Mask);
1211
1212 #ifdef SK_LEGACY_MATRIX_MATH_ORDER
1213 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1214 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1215 #else
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 #endif
1219 }
1220
Rot_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1221 void SkMatrix::Rot_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1222 SkPoint* pt) {
1223 SkASSERT((m.getType() & (kAffine_Mask | kPerspective_Mask))== kAffine_Mask);
1224 SkASSERT(0 == m.fMat[kMTransX]);
1225 SkASSERT(0 == m.fMat[kMTransY]);
1226
1227 #ifdef SK_LEGACY_MATRIX_MATH_ORDER
1228 pt->fX = sx * m.fMat[kMScaleX] + (sy * m.fMat[kMSkewX] + m.fMat[kMTransX]);
1229 pt->fY = sx * m.fMat[kMSkewY] + (sy * m.fMat[kMScaleY] + m.fMat[kMTransY]);
1230 #else
1231 pt->fX = sdot(sx, m.fMat[kMScaleX], sy, m.fMat[kMSkewX]) + m.fMat[kMTransX];
1232 pt->fY = sdot(sx, m.fMat[kMSkewY], sy, m.fMat[kMScaleY]) + m.fMat[kMTransY];
1233 #endif
1234 }
1235
ScaleTrans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1236 void SkMatrix::ScaleTrans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1237 SkPoint* pt) {
1238 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1239 == kScale_Mask);
1240
1241 pt->fX = sx * m.fMat[kMScaleX] + m.fMat[kMTransX];
1242 pt->fY = sy * m.fMat[kMScaleY] + m.fMat[kMTransY];
1243 }
1244
Scale_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1245 void SkMatrix::Scale_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1246 SkPoint* pt) {
1247 SkASSERT((m.getType() & (kScale_Mask | kAffine_Mask | kPerspective_Mask))
1248 == kScale_Mask);
1249 SkASSERT(0 == m.fMat[kMTransX]);
1250 SkASSERT(0 == m.fMat[kMTransY]);
1251
1252 pt->fX = sx * m.fMat[kMScaleX];
1253 pt->fY = sy * m.fMat[kMScaleY];
1254 }
1255
Trans_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1256 void SkMatrix::Trans_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1257 SkPoint* pt) {
1258 SkASSERT(m.getType() == kTranslate_Mask);
1259
1260 pt->fX = sx + m.fMat[kMTransX];
1261 pt->fY = sy + m.fMat[kMTransY];
1262 }
1263
Identity_xy(const SkMatrix & m,SkScalar sx,SkScalar sy,SkPoint * pt)1264 void SkMatrix::Identity_xy(const SkMatrix& m, SkScalar sx, SkScalar sy,
1265 SkPoint* pt) {
1266 SkASSERT(0 == m.getType());
1267
1268 pt->fX = sx;
1269 pt->fY = sy;
1270 }
1271
1272 const SkMatrix::MapXYProc SkMatrix::gMapXYProcs[] = {
1273 SkMatrix::Identity_xy, SkMatrix::Trans_xy,
1274 SkMatrix::Scale_xy, SkMatrix::ScaleTrans_xy,
1275 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1276 SkMatrix::Rot_xy, SkMatrix::RotTrans_xy,
1277 // repeat the persp proc 8 times
1278 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1279 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1280 SkMatrix::Persp_xy, SkMatrix::Persp_xy,
1281 SkMatrix::Persp_xy, SkMatrix::Persp_xy
1282 };
1283
1284 ///////////////////////////////////////////////////////////////////////////////
1285 #if 0
1286 // if its nearly zero (just made up 26, perhaps it should be bigger or smaller)
1287 #define PerspNearlyZero(x) SkScalarNearlyZero(x, (1.0f / (1 << 26)))
1288
1289 bool SkMatrix::isFixedStepInX() const {
1290 return PerspNearlyZero(fMat[kMPersp0]);
1291 }
1292
1293 SkVector SkMatrix::fixedStepInX(SkScalar y) const {
1294 SkASSERT(PerspNearlyZero(fMat[kMPersp0]));
1295 if (PerspNearlyZero(fMat[kMPersp1]) &&
1296 PerspNearlyZero(fMat[kMPersp2] - 1)) {
1297 return SkVector::Make(fMat[kMScaleX], fMat[kMSkewY]);
1298 } else {
1299 SkScalar z = y * fMat[kMPersp1] + fMat[kMPersp2];
1300 return SkVector::Make(fMat[kMScaleX] / z, fMat[kMSkewY] / z);
1301 }
1302 }
1303 #endif
1304
1305 ///////////////////////////////////////////////////////////////////////////////
1306
checkForZero(float x)1307 static inline bool checkForZero(float x) {
1308 return x*x == 0;
1309 }
1310
Poly2Proc(const SkPoint srcPt[],SkMatrix * dst)1311 bool SkMatrix::Poly2Proc(const SkPoint srcPt[], SkMatrix* dst) {
1312 dst->fMat[kMScaleX] = srcPt[1].fY - srcPt[0].fY;
1313 dst->fMat[kMSkewY] = srcPt[0].fX - srcPt[1].fX;
1314 dst->fMat[kMPersp0] = 0;
1315
1316 dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
1317 dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
1318 dst->fMat[kMPersp1] = 0;
1319
1320 dst->fMat[kMTransX] = srcPt[0].fX;
1321 dst->fMat[kMTransY] = srcPt[0].fY;
1322 dst->fMat[kMPersp2] = 1;
1323 dst->setTypeMask(kUnknown_Mask);
1324 return true;
1325 }
1326
Poly3Proc(const SkPoint srcPt[],SkMatrix * dst)1327 bool SkMatrix::Poly3Proc(const SkPoint srcPt[], SkMatrix* dst) {
1328 dst->fMat[kMScaleX] = srcPt[2].fX - srcPt[0].fX;
1329 dst->fMat[kMSkewY] = srcPt[2].fY - srcPt[0].fY;
1330 dst->fMat[kMPersp0] = 0;
1331
1332 dst->fMat[kMSkewX] = srcPt[1].fX - srcPt[0].fX;
1333 dst->fMat[kMScaleY] = srcPt[1].fY - srcPt[0].fY;
1334 dst->fMat[kMPersp1] = 0;
1335
1336 dst->fMat[kMTransX] = srcPt[0].fX;
1337 dst->fMat[kMTransY] = srcPt[0].fY;
1338 dst->fMat[kMPersp2] = 1;
1339 dst->setTypeMask(kUnknown_Mask);
1340 return true;
1341 }
1342
Poly4Proc(const SkPoint srcPt[],SkMatrix * dst)1343 bool SkMatrix::Poly4Proc(const SkPoint srcPt[], SkMatrix* dst) {
1344 float a1, a2;
1345 float x0, y0, x1, y1, x2, y2;
1346
1347 x0 = srcPt[2].fX - srcPt[0].fX;
1348 y0 = srcPt[2].fY - srcPt[0].fY;
1349 x1 = srcPt[2].fX - srcPt[1].fX;
1350 y1 = srcPt[2].fY - srcPt[1].fY;
1351 x2 = srcPt[2].fX - srcPt[3].fX;
1352 y2 = srcPt[2].fY - srcPt[3].fY;
1353
1354 /* check if abs(x2) > abs(y2) */
1355 if ( x2 > 0 ? y2 > 0 ? x2 > y2 : x2 > -y2 : y2 > 0 ? -x2 > y2 : x2 < y2) {
1356 float denom = sk_ieee_float_divide(x1 * y2, x2) - y1;
1357 if (checkForZero(denom)) {
1358 return false;
1359 }
1360 a1 = (((x0 - x1) * y2 / x2) - y0 + y1) / denom;
1361 } else {
1362 float denom = x1 - sk_ieee_float_divide(y1 * x2, y2);
1363 if (checkForZero(denom)) {
1364 return false;
1365 }
1366 a1 = (x0 - x1 - sk_ieee_float_divide((y0 - y1) * x2, y2)) / denom;
1367 }
1368
1369 /* check if abs(x1) > abs(y1) */
1370 if ( x1 > 0 ? y1 > 0 ? x1 > y1 : x1 > -y1 : y1 > 0 ? -x1 > y1 : x1 < y1) {
1371 float denom = y2 - sk_ieee_float_divide(x2 * y1, x1);
1372 if (checkForZero(denom)) {
1373 return false;
1374 }
1375 a2 = (y0 - y2 - sk_ieee_float_divide((x0 - x2) * y1, x1)) / denom;
1376 } else {
1377 float denom = sk_ieee_float_divide(y2 * x1, y1) - x2;
1378 if (checkForZero(denom)) {
1379 return false;
1380 }
1381 a2 = (sk_ieee_float_divide((y0 - y2) * x1, y1) - x0 + x2) / denom;
1382 }
1383
1384 dst->fMat[kMScaleX] = a2 * srcPt[3].fX + srcPt[3].fX - srcPt[0].fX;
1385 dst->fMat[kMSkewY] = a2 * srcPt[3].fY + srcPt[3].fY - srcPt[0].fY;
1386 dst->fMat[kMPersp0] = a2;
1387
1388 dst->fMat[kMSkewX] = a1 * srcPt[1].fX + srcPt[1].fX - srcPt[0].fX;
1389 dst->fMat[kMScaleY] = a1 * srcPt[1].fY + srcPt[1].fY - srcPt[0].fY;
1390 dst->fMat[kMPersp1] = a1;
1391
1392 dst->fMat[kMTransX] = srcPt[0].fX;
1393 dst->fMat[kMTransY] = srcPt[0].fY;
1394 dst->fMat[kMPersp2] = 1;
1395 dst->setTypeMask(kUnknown_Mask);
1396 return true;
1397 }
1398
1399 typedef bool (*PolyMapProc)(const SkPoint[], SkMatrix*);
1400
1401 /* Adapted from Rob Johnson's original sample code in QuickDraw GX
1402 */
setPolyToPoly(const SkPoint src[],const SkPoint dst[],int count)1403 bool SkMatrix::setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count) {
1404 if ((unsigned)count > 4) {
1405 SkDebugf("--- SkMatrix::setPolyToPoly count out of range %d\n", count);
1406 return false;
1407 }
1408
1409 if (0 == count) {
1410 this->reset();
1411 return true;
1412 }
1413 if (1 == count) {
1414 this->setTranslate(dst[0].fX - src[0].fX, dst[0].fY - src[0].fY);
1415 return true;
1416 }
1417
1418 const PolyMapProc gPolyMapProcs[] = {
1419 SkMatrix::Poly2Proc, SkMatrix::Poly3Proc, SkMatrix::Poly4Proc
1420 };
1421 PolyMapProc proc = gPolyMapProcs[count - 2];
1422
1423 SkMatrix tempMap, result;
1424
1425 if (!proc(src, &tempMap)) {
1426 return false;
1427 }
1428 if (!tempMap.invert(&result)) {
1429 return false;
1430 }
1431 if (!proc(dst, &tempMap)) {
1432 return false;
1433 }
1434 this->setConcat(tempMap, result);
1435 return true;
1436 }
1437
1438 ///////////////////////////////////////////////////////////////////////////////
1439
1440 enum MinMaxOrBoth {
1441 kMin_MinMaxOrBoth,
1442 kMax_MinMaxOrBoth,
1443 kBoth_MinMaxOrBoth
1444 };
1445
get_scale_factor(SkMatrix::TypeMask typeMask,const SkScalar m[9],SkScalar results[])1446 template <MinMaxOrBoth MIN_MAX_OR_BOTH> bool get_scale_factor(SkMatrix::TypeMask typeMask,
1447 const SkScalar m[9],
1448 SkScalar results[/*1 or 2*/]) {
1449 if (typeMask & SkMatrix::kPerspective_Mask) {
1450 return false;
1451 }
1452 if (SkMatrix::kIdentity_Mask == typeMask) {
1453 results[0] = SK_Scalar1;
1454 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1455 results[1] = SK_Scalar1;
1456 }
1457 return true;
1458 }
1459 if (!(typeMask & SkMatrix::kAffine_Mask)) {
1460 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1461 results[0] = std::min(SkScalarAbs(m[SkMatrix::kMScaleX]),
1462 SkScalarAbs(m[SkMatrix::kMScaleY]));
1463 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1464 results[0] = std::max(SkScalarAbs(m[SkMatrix::kMScaleX]),
1465 SkScalarAbs(m[SkMatrix::kMScaleY]));
1466 } else {
1467 results[0] = SkScalarAbs(m[SkMatrix::kMScaleX]);
1468 results[1] = SkScalarAbs(m[SkMatrix::kMScaleY]);
1469 if (results[0] > results[1]) {
1470 using std::swap;
1471 swap(results[0], results[1]);
1472 }
1473 }
1474 return true;
1475 }
1476 // ignore the translation part of the matrix, just look at 2x2 portion.
1477 // compute singular values, take largest or smallest abs value.
1478 // [a b; b c] = A^T*A
1479 SkScalar a = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMScaleX],
1480 m[SkMatrix::kMSkewY], m[SkMatrix::kMSkewY]);
1481 SkScalar b = sdot(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewX],
1482 m[SkMatrix::kMScaleY], m[SkMatrix::kMSkewY]);
1483 SkScalar c = sdot(m[SkMatrix::kMSkewX], m[SkMatrix::kMSkewX],
1484 m[SkMatrix::kMScaleY], m[SkMatrix::kMScaleY]);
1485 // eigenvalues of A^T*A are the squared singular values of A.
1486 // characteristic equation is det((A^T*A) - l*I) = 0
1487 // l^2 - (a + c)l + (ac-b^2)
1488 // solve using quadratic equation (divisor is non-zero since l^2 has 1 coeff
1489 // and roots are guaranteed to be pos and real).
1490 SkScalar bSqd = b * b;
1491 // if upper left 2x2 is orthogonal save some math
1492 if (bSqd <= SK_ScalarNearlyZero*SK_ScalarNearlyZero) {
1493 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1494 results[0] = std::min(a, c);
1495 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1496 results[0] = std::max(a, c);
1497 } else {
1498 results[0] = a;
1499 results[1] = c;
1500 if (results[0] > results[1]) {
1501 using std::swap;
1502 swap(results[0], results[1]);
1503 }
1504 }
1505 } else {
1506 SkScalar aminusc = a - c;
1507 SkScalar apluscdiv2 = SkScalarHalf(a + c);
1508 SkScalar x = SkScalarHalf(SkScalarSqrt(aminusc * aminusc + 4 * bSqd));
1509 if (kMin_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1510 results[0] = apluscdiv2 - x;
1511 } else if (kMax_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1512 results[0] = apluscdiv2 + x;
1513 } else {
1514 results[0] = apluscdiv2 - x;
1515 results[1] = apluscdiv2 + x;
1516 }
1517 }
1518 if (!SkScalarIsFinite(results[0])) {
1519 return false;
1520 }
1521 // Due to the floating point inaccuracy, there might be an error in a, b, c
1522 // calculated by sdot, further deepened by subsequent arithmetic operations
1523 // on them. Therefore, we allow and cap the nearly-zero negative values.
1524 if (results[0] < 0) {
1525 results[0] = 0;
1526 }
1527 results[0] = SkScalarSqrt(results[0]);
1528 if (kBoth_MinMaxOrBoth == MIN_MAX_OR_BOTH) {
1529 if (!SkScalarIsFinite(results[1])) {
1530 return false;
1531 }
1532 if (results[1] < 0) {
1533 results[1] = 0;
1534 }
1535 results[1] = SkScalarSqrt(results[1]);
1536 }
1537 return true;
1538 }
1539
getMinScale() const1540 SkScalar SkMatrix::getMinScale() const {
1541 SkScalar factor;
1542 if (get_scale_factor<kMin_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1543 return factor;
1544 } else {
1545 return -1;
1546 }
1547 }
1548
getMaxScale() const1549 SkScalar SkMatrix::getMaxScale() const {
1550 SkScalar factor;
1551 if (get_scale_factor<kMax_MinMaxOrBoth>(this->getType(), fMat, &factor)) {
1552 return factor;
1553 } else {
1554 return -1;
1555 }
1556 }
1557
getMinMaxScales(SkScalar scaleFactors[2]) const1558 bool SkMatrix::getMinMaxScales(SkScalar scaleFactors[2]) const {
1559 return get_scale_factor<kBoth_MinMaxOrBoth>(this->getType(), fMat, scaleFactors);
1560 }
1561
I()1562 const SkMatrix& SkMatrix::I() {
1563 static constexpr SkMatrix identity;
1564 SkASSERT(identity.isIdentity());
1565 return identity;
1566 }
1567
InvalidMatrix()1568 const SkMatrix& SkMatrix::InvalidMatrix() {
1569 static constexpr SkMatrix invalid(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1570 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1571 SK_ScalarMax, SK_ScalarMax, SK_ScalarMax,
1572 kTranslate_Mask | kScale_Mask |
1573 kAffine_Mask | kPerspective_Mask);
1574 return invalid;
1575 }
1576
decomposeScale(SkSize * scale,SkMatrix * remaining) const1577 bool SkMatrix::decomposeScale(SkSize* scale, SkMatrix* remaining) const {
1578 if (this->hasPerspective()) {
1579 return false;
1580 }
1581
1582 const SkScalar sx = SkVector::Length(this->getScaleX(), this->getSkewY());
1583 const SkScalar sy = SkVector::Length(this->getSkewX(), this->getScaleY());
1584 if (!SkScalarIsFinite(sx) || !SkScalarIsFinite(sy) ||
1585 SkScalarNearlyZero(sx) || SkScalarNearlyZero(sy)) {
1586 return false;
1587 }
1588
1589 if (scale) {
1590 scale->set(sx, sy);
1591 }
1592 if (remaining) {
1593 *remaining = *this;
1594 remaining->preScale(SkScalarInvert(sx), SkScalarInvert(sy));
1595 }
1596 return true;
1597 }
1598
1599 ///////////////////////////////////////////////////////////////////////////////
1600
writeToMemory(void * buffer) const1601 size_t SkMatrix::writeToMemory(void* buffer) const {
1602 // TODO write less for simple matrices
1603 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1604 if (buffer) {
1605 memcpy(buffer, fMat, sizeInMemory);
1606 }
1607 return sizeInMemory;
1608 }
1609
readFromMemory(const void * buffer,size_t length)1610 size_t SkMatrix::readFromMemory(const void* buffer, size_t length) {
1611 static const size_t sizeInMemory = 9 * sizeof(SkScalar);
1612 if (length < sizeInMemory) {
1613 return 0;
1614 }
1615 memcpy(fMat, buffer, sizeInMemory);
1616 this->setTypeMask(kUnknown_Mask);
1617 // Figure out the type now so that we're thread-safe
1618 (void)this->getType();
1619 return sizeInMemory;
1620 }
1621
dump() const1622 void SkMatrix::dump() const {
1623 SkString str;
1624 str.appendf("[%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f][%8.4f %8.4f %8.4f]",
1625 fMat[0], fMat[1], fMat[2], fMat[3], fMat[4], fMat[5],
1626 fMat[6], fMat[7], fMat[8]);
1627 SkDebugf("%s\n", str.c_str());
1628 }
1629
1630 ///////////////////////////////////////////////////////////////////////////////
1631
1632 #include "src/core/SkMatrixUtils.h"
1633 #include "src/core/SkSamplingPriv.h"
1634
SkTreatAsSprite(const SkMatrix & mat,const SkISize & size,const SkSamplingOptions & sampling,const SkPaint & paint)1635 bool SkTreatAsSprite(const SkMatrix& mat, const SkISize& size, const SkSamplingOptions& sampling,
1636 const SkPaint& paint) {
1637 if (!SkSamplingPriv::NoChangeWithIdentityMatrix(sampling)) {
1638 return false;
1639 }
1640
1641 // Our path aa is 2-bits, and our rect aa is 8, so we could use 8,
1642 // but in practice 4 seems enough (still looks smooth) and allows
1643 // more slightly fractional cases to fall into the fast (sprite) case.
1644 static const unsigned kAntiAliasSubpixelBits = 4;
1645
1646 const unsigned subpixelBits = paint.isAntiAlias() ? kAntiAliasSubpixelBits : 0;
1647
1648 // quick reject on affine or perspective
1649 if (mat.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask)) {
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
toQuad(SkScalar width,SkScalar height,SkPoint quad[4]) const1798 void SkRSXform::toQuad(SkScalar width, SkScalar height, SkPoint quad[4]) const {
1799 #if 0
1800 // This is the slow way, but it documents what we're doing
1801 quad[0].set(0, 0);
1802 quad[1].set(width, 0);
1803 quad[2].set(width, height);
1804 quad[3].set(0, height);
1805 SkMatrix m;
1806 m.setRSXform(*this).mapPoints(quad, quad, 4);
1807 #else
1808 const SkScalar m00 = fSCos;
1809 const SkScalar m01 = -fSSin;
1810 const SkScalar m02 = fTx;
1811 const SkScalar m10 = -m01;
1812 const SkScalar m11 = m00;
1813 const SkScalar m12 = fTy;
1814
1815 quad[0].set(m02, m12);
1816 quad[1].set(m00 * width + m02, m10 * width + m12);
1817 quad[2].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
1818 quad[3].set(m01 * height + m02, m11 * height + m12);
1819 #endif
1820 }
1821
toTriStrip(SkScalar width,SkScalar height,SkPoint strip[4]) const1822 void SkRSXform::toTriStrip(SkScalar width, SkScalar height, SkPoint strip[4]) const {
1823 const SkScalar m00 = fSCos;
1824 const SkScalar m01 = -fSSin;
1825 const SkScalar m02 = fTx;
1826 const SkScalar m10 = -m01;
1827 const SkScalar m11 = m00;
1828 const SkScalar m12 = fTy;
1829
1830 strip[0].set(m02, m12);
1831 strip[1].set(m01 * height + m02, m11 * height + m12);
1832 strip[2].set(m00 * width + m02, m10 * width + m12);
1833 strip[3].set(m00 * width + m01 * height + m02, m10 * width + m11 * height + m12);
1834 }
1835
1836 ///////////////////////////////////////////////////////////////////////////////////////////////////
1837
DifferentialAreaScale(const SkMatrix & m,const SkPoint & p)1838 SkScalar SkMatrixPriv::DifferentialAreaScale(const SkMatrix& m, const SkPoint& p) {
1839 // [m00 m01 m02] [f(u,v)]
1840 // Assuming M = [m10 m11 m12], define the projected p'(u,v) = [g(u,v)] where
1841 // [m20 m12 m22]
1842 // [x] [u]
1843 // f(u,v) = x(u,v) / w(u,v), g(u,v) = y(u,v) / w(u,v) and [y] = M*[v]
1844 // [w] [1]
1845 //
1846 // Then the differential scale factor between p = (u,v) and p' is |det J|,
1847 // where J is the Jacobian for p': [df/du dg/du]
1848 // [df/dv dg/dv]
1849 // and df/du = (w*dx/du - x*dw/du)/w^2, dg/du = (w*dy/du - y*dw/du)/w^2
1850 // df/dv = (w*dx/dv - x*dw/dv)/w^2, dg/dv = (w*dy/dv - y*dw/dv)/w^2
1851 //
1852 // From here, |det J| can be rewritten as |det J'/w^3|, where
1853 // [x y w ] [x y w ]
1854 // J' = [dx/du dy/du dw/du] = [m00 m10 m20]
1855 // [dx/dv dy/dv dw/dv] [m01 m11 m21]
1856 SkPoint3 xyw;
1857 m.mapHomogeneousPoints(&xyw, &p, 1);
1858
1859 if (xyw.fZ < SK_ScalarNearlyZero) {
1860 // Reaching the discontinuity of xy/w and where the point would clip to w >= 0
1861 return SK_ScalarInfinity;
1862 }
1863 SkMatrix jacobian = SkMatrix::MakeAll(xyw.fX, xyw.fY, xyw.fZ,
1864 m.getScaleX(), m.getSkewY(), m.getPerspX(),
1865 m.getSkewX(), m.getScaleY(), m.getPerspY());
1866
1867 SkScalar denom = 1.f / xyw.fZ; // 1/w
1868 denom = denom * denom * denom; // 1/w^3
1869
1870 return SkScalarAbs(SkDoubleToScalar(sk_determinant(jacobian.fMat, true)) * denom);
1871 }
1872