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