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