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