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