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