Line data Source code
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 : #ifndef SkMatrix_DEFINED
11 : #define SkMatrix_DEFINED
12 :
13 : #include "SkRect.h"
14 :
15 : struct SkRSXform;
16 : class SkString;
17 :
18 : /** \class SkMatrix
19 :
20 : The SkMatrix class holds a 3x3 matrix for transforming coordinates.
21 : SkMatrix does not have a constructor, so it must be explicitly initialized
22 : using either reset() - to construct an identity matrix, or one of the set
23 : functions (e.g. setTranslate, setRotate, etc.).
24 :
25 : SkMatrix is not thread safe unless you've first called SkMatrix::getType().
26 : */
27 : SK_BEGIN_REQUIRE_DENSE
28 : class SK_API SkMatrix {
29 : public:
30 0 : static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar sx, SkScalar sy) {
31 : SkMatrix m;
32 0 : m.setScale(sx, sy);
33 0 : return m;
34 : }
35 :
36 : static SkMatrix SK_WARN_UNUSED_RESULT MakeScale(SkScalar scale) {
37 : SkMatrix m;
38 : m.setScale(scale, scale);
39 : return m;
40 : }
41 :
42 4 : static SkMatrix SK_WARN_UNUSED_RESULT MakeTrans(SkScalar dx, SkScalar dy) {
43 : SkMatrix m;
44 4 : m.setTranslate(dx, dy);
45 4 : return m;
46 : }
47 :
48 : /** Enum of bit fields for the mask return by getType().
49 : Use this to identify the complexity of the matrix.
50 : */
51 : enum TypeMask {
52 : kIdentity_Mask = 0,
53 : kTranslate_Mask = 0x01, //!< set if the matrix has translation
54 : kScale_Mask = 0x02, //!< set if the matrix has X or Y scale
55 : kAffine_Mask = 0x04, //!< set if the matrix skews or rotates
56 : kPerspective_Mask = 0x08 //!< set if the matrix is in perspective
57 : };
58 :
59 : /** Returns a bitfield describing the transformations the matrix may
60 : perform. The bitfield is computed conservatively, so it may include
61 : false positives. For example, when kPerspective_Mask is true, all
62 : other bits may be set to true even in the case of a pure perspective
63 : transform.
64 : */
65 17266 : TypeMask getType() const {
66 17266 : if (fTypeMask & kUnknown_Mask) {
67 4004 : fTypeMask = this->computeTypeMask();
68 : }
69 : // only return the public masks
70 17266 : return (TypeMask)(fTypeMask & 0xF);
71 : }
72 :
73 : /** Returns true if the matrix is identity.
74 : */
75 1253 : bool isIdentity() const {
76 1253 : return this->getType() == 0;
77 : }
78 :
79 3733 : bool isScaleTranslate() const {
80 3733 : return !(this->getType() & ~(kScale_Mask | kTranslate_Mask));
81 : }
82 :
83 : /** Returns true if will map a rectangle to another rectangle. This can be
84 : true if the matrix is identity, scale-only, or rotates a multiple of
85 : 90 degrees, or mirrors in x or y.
86 : */
87 355 : bool rectStaysRect() const {
88 355 : if (fTypeMask & kUnknown_Mask) {
89 81 : fTypeMask = this->computeTypeMask();
90 : }
91 355 : return (fTypeMask & kRectStaysRect_Mask) != 0;
92 : }
93 : // alias for rectStaysRect()
94 0 : bool preservesAxisAlignment() const { return this->rectStaysRect(); }
95 :
96 : /**
97 : * Returns true if the matrix contains perspective elements.
98 : */
99 999 : bool hasPerspective() const {
100 999 : return SkToBool(this->getPerspectiveTypeMaskOnly() &
101 : kPerspective_Mask);
102 : }
103 :
104 : /** Returns true if the matrix contains only translation, rotation/reflection or uniform scale
105 : Returns false if other transformation types are included or is degenerate
106 : */
107 : bool isSimilarity(SkScalar tol = SK_ScalarNearlyZero) const;
108 :
109 : /** Returns true if the matrix contains only translation, rotation/reflection or scale
110 : (non-uniform scale is allowed).
111 : Returns false if other transformation types are included or is degenerate
112 : */
113 : bool preservesRightAngles(SkScalar tol = SK_ScalarNearlyZero) const;
114 :
115 : enum {
116 : kMScaleX,
117 : kMSkewX,
118 : kMTransX,
119 : kMSkewY,
120 : kMScaleY,
121 : kMTransY,
122 : kMPersp0,
123 : kMPersp1,
124 : kMPersp2
125 : };
126 :
127 : /** Affine arrays are in column major order
128 : because that's how PDF and XPS like it.
129 : */
130 : enum {
131 : kAScaleX,
132 : kASkewY,
133 : kASkewX,
134 : kAScaleY,
135 : kATransX,
136 : kATransY
137 : };
138 :
139 170 : SkScalar operator[](int index) const {
140 170 : SkASSERT((unsigned)index < 9);
141 170 : return fMat[index];
142 : }
143 :
144 0 : SkScalar get(int index) const {
145 0 : SkASSERT((unsigned)index < 9);
146 0 : return fMat[index];
147 : }
148 :
149 5858 : SkScalar getScaleX() const { return fMat[kMScaleX]; }
150 2183 : SkScalar getScaleY() const { return fMat[kMScaleY]; }
151 286 : SkScalar getSkewY() const { return fMat[kMSkewY]; }
152 4 : SkScalar getSkewX() const { return fMat[kMSkewX]; }
153 844 : SkScalar getTranslateX() const { return fMat[kMTransX]; }
154 844 : SkScalar getTranslateY() const { return fMat[kMTransY]; }
155 0 : SkScalar getPerspX() const { return fMat[kMPersp0]; }
156 0 : SkScalar getPerspY() const { return fMat[kMPersp1]; }
157 :
158 0 : SkScalar& operator[](int index) {
159 0 : SkASSERT((unsigned)index < 9);
160 0 : this->setTypeMask(kUnknown_Mask);
161 0 : return fMat[index];
162 : }
163 :
164 0 : void set(int index, SkScalar value) {
165 0 : SkASSERT((unsigned)index < 9);
166 0 : fMat[index] = value;
167 0 : this->setTypeMask(kUnknown_Mask);
168 0 : }
169 :
170 0 : void setScaleX(SkScalar v) { this->set(kMScaleX, v); }
171 : void setScaleY(SkScalar v) { this->set(kMScaleY, v); }
172 : void setSkewY(SkScalar v) { this->set(kMSkewY, v); }
173 : void setSkewX(SkScalar v) { this->set(kMSkewX, v); }
174 0 : void setTranslateX(SkScalar v) { this->set(kMTransX, v); }
175 0 : void setTranslateY(SkScalar v) { this->set(kMTransY, v); }
176 : void setPerspX(SkScalar v) { this->set(kMPersp0, v); }
177 : void setPerspY(SkScalar v) { this->set(kMPersp1, v); }
178 :
179 2162 : void setAll(SkScalar scaleX, SkScalar skewX, SkScalar transX,
180 : SkScalar skewY, SkScalar scaleY, SkScalar transY,
181 : SkScalar persp0, SkScalar persp1, SkScalar persp2) {
182 2162 : fMat[kMScaleX] = scaleX;
183 2162 : fMat[kMSkewX] = skewX;
184 2162 : fMat[kMTransX] = transX;
185 2162 : fMat[kMSkewY] = skewY;
186 2162 : fMat[kMScaleY] = scaleY;
187 2162 : fMat[kMTransY] = transY;
188 2162 : fMat[kMPersp0] = persp0;
189 2162 : fMat[kMPersp1] = persp1;
190 2162 : fMat[kMPersp2] = persp2;
191 2162 : this->setTypeMask(kUnknown_Mask);
192 2162 : }
193 :
194 : /**
195 : * Copy the 9 scalars for this matrix into buffer, in the same order as the kMScaleX
196 : * enum... scalex, skewx, transx, skewy, scaley, transy, persp0, persp1, persp2
197 : */
198 0 : void get9(SkScalar buffer[9]) const {
199 0 : memcpy(buffer, fMat, 9 * sizeof(SkScalar));
200 0 : }
201 :
202 : /**
203 : * Set this matrix to the 9 scalars from the buffer, in the same order as the kMScaleX
204 : * enum... scalex, skewx, transx, skewy, scaley, transy, persp0, persp1, persp2
205 : *
206 : * Note: calling set9 followed by get9 may not return the exact same values. Since the matrix
207 : * is used to map non-homogeneous coordinates, it is free to rescale the 9 values as needed.
208 : */
209 : void set9(const SkScalar buffer[9]);
210 :
211 : /** Set the matrix to identity
212 : */
213 : void reset();
214 : // alias for reset()
215 58 : void setIdentity() { this->reset(); }
216 :
217 : /** Set the matrix to translate by (dx, dy).
218 : */
219 : void setTranslate(SkScalar dx, SkScalar dy);
220 : void setTranslate(const SkVector& v) { this->setTranslate(v.fX, v.fY); }
221 :
222 : /** Set the matrix to scale by sx and sy, with a pivot point at (px, py).
223 : The pivot point is the coordinate that should remain unchanged by the
224 : specified transformation.
225 : */
226 : void setScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
227 : /** Set the matrix to scale by sx and sy.
228 : */
229 : void setScale(SkScalar sx, SkScalar sy);
230 : /** Set the matrix to scale by 1/divx and 1/divy. Returns false and doesn't
231 : touch the matrix if either divx or divy is zero.
232 : */
233 : bool setIDiv(int divx, int divy);
234 : /** Set the matrix to rotate by the specified number of degrees, with a
235 : pivot point at (px, py). The pivot point is the coordinate that should
236 : remain unchanged by the specified transformation.
237 : */
238 : void setRotate(SkScalar degrees, SkScalar px, SkScalar py);
239 : /** Set the matrix to rotate about (0,0) by the specified number of degrees.
240 : */
241 : void setRotate(SkScalar degrees);
242 : /** Set the matrix to rotate by the specified sine and cosine values, with
243 : a pivot point at (px, py). The pivot point is the coordinate that
244 : should remain unchanged by the specified transformation.
245 : */
246 : void setSinCos(SkScalar sinValue, SkScalar cosValue,
247 : SkScalar px, SkScalar py);
248 : /** Set the matrix to rotate by the specified sine and cosine values.
249 : */
250 : void setSinCos(SkScalar sinValue, SkScalar cosValue);
251 :
252 : SkMatrix& setRSXform(const SkRSXform&);
253 :
254 : /** Set the matrix to skew by sx and sy, with a pivot point at (px, py).
255 : The pivot point is the coordinate that should remain unchanged by the
256 : specified transformation.
257 : */
258 : void setSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
259 : /** Set the matrix to skew by sx and sy.
260 : */
261 : void setSkew(SkScalar kx, SkScalar ky);
262 : /** Set the matrix to the concatenation of the two specified matrices.
263 : Either of the two matrices may also be the target matrix.
264 : *this = a * b;
265 : */
266 : void setConcat(const SkMatrix& a, const SkMatrix& b);
267 :
268 : /** Preconcats the matrix with the specified translation.
269 : M' = M * T(dx, dy)
270 : */
271 : void preTranslate(SkScalar dx, SkScalar dy);
272 : /** Preconcats the matrix with the specified scale.
273 : M' = M * S(sx, sy, px, py)
274 : */
275 : void preScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
276 : /** Preconcats the matrix with the specified scale.
277 : M' = M * S(sx, sy)
278 : */
279 : void preScale(SkScalar sx, SkScalar sy);
280 : /** Preconcats the matrix with the specified rotation.
281 : M' = M * R(degrees, px, py)
282 : */
283 : void preRotate(SkScalar degrees, SkScalar px, SkScalar py);
284 : /** Preconcats the matrix with the specified rotation.
285 : M' = M * R(degrees)
286 : */
287 : void preRotate(SkScalar degrees);
288 : /** Preconcats the matrix with the specified skew.
289 : M' = M * K(kx, ky, px, py)
290 : */
291 : void preSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
292 : /** Preconcats the matrix with the specified skew.
293 : M' = M * K(kx, ky)
294 : */
295 : void preSkew(SkScalar kx, SkScalar ky);
296 : /** Preconcats the matrix with the specified matrix.
297 : M' = M * other
298 : */
299 : void preConcat(const SkMatrix& other);
300 :
301 : /** Postconcats the matrix with the specified translation.
302 : M' = T(dx, dy) * M
303 : */
304 : void postTranslate(SkScalar dx, SkScalar dy);
305 : /** Postconcats the matrix with the specified scale.
306 : M' = S(sx, sy, px, py) * M
307 : */
308 : void postScale(SkScalar sx, SkScalar sy, SkScalar px, SkScalar py);
309 : /** Postconcats the matrix with the specified scale.
310 : M' = S(sx, sy) * M
311 : */
312 : void postScale(SkScalar sx, SkScalar sy);
313 : /** Postconcats the matrix by dividing it by the specified integers.
314 : M' = S(1/divx, 1/divy, 0, 0) * M
315 : */
316 : bool postIDiv(int divx, int divy);
317 : /** Postconcats the matrix with the specified rotation.
318 : M' = R(degrees, px, py) * M
319 : */
320 : void postRotate(SkScalar degrees, SkScalar px, SkScalar py);
321 : /** Postconcats the matrix with the specified rotation.
322 : M' = R(degrees) * M
323 : */
324 : void postRotate(SkScalar degrees);
325 : /** Postconcats the matrix with the specified skew.
326 : M' = K(kx, ky, px, py) * M
327 : */
328 : void postSkew(SkScalar kx, SkScalar ky, SkScalar px, SkScalar py);
329 : /** Postconcats the matrix with the specified skew.
330 : M' = K(kx, ky) * M
331 : */
332 : void postSkew(SkScalar kx, SkScalar ky);
333 : /** Postconcats the matrix with the specified matrix.
334 : M' = other * M
335 : */
336 : void postConcat(const SkMatrix& other);
337 :
338 : enum ScaleToFit {
339 : /**
340 : * Scale in X and Y independently, so that src matches dst exactly.
341 : * This may change the aspect ratio of the src.
342 : */
343 : kFill_ScaleToFit,
344 : /**
345 : * Compute a scale that will maintain the original src aspect ratio,
346 : * but will also ensure that src fits entirely inside dst. At least one
347 : * axis (X or Y) will fit exactly. kStart aligns the result to the
348 : * left and top edges of dst.
349 : */
350 : kStart_ScaleToFit,
351 : /**
352 : * Compute a scale that will maintain the original src aspect ratio,
353 : * but will also ensure that src fits entirely inside dst. At least one
354 : * axis (X or Y) will fit exactly. The result is centered inside dst.
355 : */
356 : kCenter_ScaleToFit,
357 : /**
358 : * Compute a scale that will maintain the original src aspect ratio,
359 : * but will also ensure that src fits entirely inside dst. At least one
360 : * axis (X or Y) will fit exactly. kEnd aligns the result to the
361 : * right and bottom edges of dst.
362 : */
363 : kEnd_ScaleToFit
364 : };
365 :
366 : /** Set the matrix to the scale and translate values that map the source
367 : rectangle to the destination rectangle, returning true if the the result
368 : can be represented.
369 : @param src the source rectangle to map from.
370 : @param dst the destination rectangle to map to.
371 : @param stf the ScaleToFit option
372 : @return true if the matrix can be represented by the rectangle mapping.
373 : */
374 : bool setRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf);
375 0 : static SkMatrix MakeRectToRect(const SkRect& src, const SkRect& dst, ScaleToFit stf) {
376 : SkMatrix m;
377 0 : m.setRectToRect(src, dst, stf);
378 0 : return m;
379 : }
380 :
381 : /** Set the matrix such that the specified src points would map to the
382 : specified dst points. count must be within [0..4].
383 : @param src The array of src points
384 : @param dst The array of dst points
385 : @param count The number of points to use for the transformation
386 : @return true if the matrix was set to the specified transformation
387 : */
388 : bool setPolyToPoly(const SkPoint src[], const SkPoint dst[], int count);
389 :
390 : /** If this matrix can be inverted, return true and if inverse is not null,
391 : set inverse to be the inverse of this matrix. If this matrix cannot be
392 : inverted, ignore inverse and return false
393 : */
394 572 : bool SK_WARN_UNUSED_RESULT invert(SkMatrix* inverse) const {
395 : // Allow the trivial case to be inlined.
396 572 : if (this->isIdentity()) {
397 56 : if (inverse) {
398 31 : inverse->reset();
399 : }
400 56 : return true;
401 : }
402 516 : return this->invertNonIdentity(inverse);
403 : }
404 :
405 : /** Fills the passed array with affine identity values
406 : in column major order.
407 : @param affine The array to fill with affine identity values.
408 : Must not be NULL.
409 : */
410 : static void SetAffineIdentity(SkScalar affine[6]);
411 :
412 : /** Fills the passed array with the affine values in column major order.
413 : If the matrix is a perspective transform, returns false
414 : and does not change the passed array.
415 : @param affine The array to fill with affine values. Ignored if NULL.
416 : */
417 : bool SK_WARN_UNUSED_RESULT asAffine(SkScalar affine[6]) const;
418 :
419 : /** Set the matrix to the specified affine values.
420 : * Note: these are passed in column major order.
421 : */
422 : void setAffine(const SkScalar affine[6]);
423 :
424 : /** Apply this matrix to the array of points specified by src, and write
425 : the transformed points into the array of points specified by dst.
426 : dst[] = M * src[]
427 : @param dst Where the transformed coordinates are written. It must
428 : contain at least count entries
429 : @param src The original coordinates that are to be transformed. It
430 : must contain at least count entries
431 : @param count The number of points in src to read, and then transform
432 : into dst.
433 : */
434 318 : void mapPoints(SkPoint dst[], const SkPoint src[], int count) const {
435 318 : SkASSERT((dst && src && count > 0) || 0 == count);
436 : // no partial overlap
437 318 : SkASSERT(src == dst || &dst[count] <= &src[0] || &src[count] <= &dst[0]);
438 318 : this->getMapPtsProc()(*this, dst, src, count);
439 318 : }
440 :
441 : /** Apply this matrix to the array of points, overwriting it with the
442 : transformed values.
443 : dst[] = M * pts[]
444 : @param pts The points to be transformed. It must contain at least
445 : count entries
446 : @param count The number of points in pts.
447 : */
448 0 : void mapPoints(SkPoint pts[], int count) const {
449 0 : this->mapPoints(pts, pts, count);
450 0 : }
451 :
452 : /** Like mapPoints but with custom byte stride between the points. Stride
453 : * should be a multiple of sizeof(SkScalar).
454 : */
455 0 : void mapPointsWithStride(SkPoint pts[], size_t stride, int count) const {
456 0 : SkASSERT(stride >= sizeof(SkPoint));
457 0 : SkASSERT(0 == stride % sizeof(SkScalar));
458 0 : for (int i = 0; i < count; ++i) {
459 0 : this->mapPoints(pts, pts, 1);
460 0 : pts = (SkPoint*)((intptr_t)pts + stride);
461 : }
462 0 : }
463 :
464 : /** Like mapPoints but with custom byte stride between the points.
465 : */
466 0 : void mapPointsWithStride(SkPoint dst[], const SkPoint src[], size_t stride, int count) const {
467 0 : SkASSERT(stride >= sizeof(SkPoint));
468 0 : SkASSERT(0 == stride % sizeof(SkScalar));
469 0 : for (int i = 0; i < count; ++i) {
470 0 : this->mapPoints(dst, src, 1);
471 0 : src = (SkPoint*)((intptr_t)src + stride);
472 0 : dst = (SkPoint*)((intptr_t)dst + stride);
473 : }
474 0 : }
475 :
476 : /** Apply this matrix to the array of homogeneous points, specified by src,
477 : where a homogeneous point is defined by 3 contiguous scalar values,
478 : and write the transformed points into the array of scalars specified by dst.
479 : dst[] = M * src[]
480 : @param dst Where the transformed coordinates are written. It must
481 : contain at least 3 * count entries
482 : @param src The original coordinates that are to be transformed. It
483 : must contain at least 3 * count entries
484 : @param count The number of triples (homogeneous points) in src to read,
485 : and then transform into dst.
486 : */
487 : void mapHomogeneousPoints(SkScalar dst[], const SkScalar src[], int count) const;
488 :
489 0 : void mapXY(SkScalar x, SkScalar y, SkPoint* result) const {
490 0 : SkASSERT(result);
491 0 : this->getMapXYProc()(*this, x, y, result);
492 0 : }
493 :
494 0 : SkPoint mapXY(SkScalar x, SkScalar y) const {
495 : SkPoint result;
496 0 : this->getMapXYProc()(*this, x, y, &result);
497 0 : return result;
498 : }
499 :
500 : /** Apply this matrix to the array of vectors specified by src, and write
501 : the transformed vectors into the array of vectors specified by dst.
502 : This is similar to mapPoints, but ignores any translation in the matrix.
503 : @param dst Where the transformed coordinates are written. It must
504 : contain at least count entries
505 : @param src The original coordinates that are to be transformed. It
506 : must contain at least count entries
507 : @param count The number of vectors in src to read, and then transform
508 : into dst.
509 : */
510 : void mapVectors(SkVector dst[], const SkVector src[], int count) const;
511 :
512 : /** Apply this matrix to the array of vectors specified by src, and write
513 : the transformed vectors into the array of vectors specified by dst.
514 : This is similar to mapPoints, but ignores any translation in the matrix.
515 : @param vecs The vectors to be transformed. It must contain at least
516 : count entries
517 : @param count The number of vectors in vecs.
518 : */
519 0 : void mapVectors(SkVector vecs[], int count) const {
520 0 : this->mapVectors(vecs, vecs, count);
521 0 : }
522 :
523 : void mapVector(SkScalar dx, SkScalar dy, SkVector* result) const {
524 : SkVector vec = { dx, dy };
525 : this->mapVectors(result, &vec, 1);
526 : }
527 :
528 0 : SkVector mapVector(SkScalar dx, SkScalar dy) const {
529 0 : SkVector vec = { dx, dy };
530 0 : this->mapVectors(&vec, &vec, 1);
531 0 : return vec;
532 : }
533 :
534 : /** Apply this matrix to the src rectangle, and write the transformed
535 : rectangle into dst. This is accomplished by transforming the 4 corners
536 : of src, and then setting dst to the bounds of those points.
537 : @param dst Where the transformed rectangle is written.
538 : @param src The original rectangle to be transformed.
539 : @return the result of calling rectStaysRect()
540 : */
541 : bool mapRect(SkRect* dst, const SkRect& src) const;
542 :
543 : /** Apply this matrix to the rectangle, and write the transformed rectangle
544 : back into it. This is accomplished by transforming the 4 corners of
545 : rect, and then setting it to the bounds of those points
546 : @param rect The rectangle to transform.
547 : @return the result of calling rectStaysRect()
548 : */
549 39 : bool mapRect(SkRect* rect) const {
550 39 : return this->mapRect(rect, *rect);
551 : }
552 :
553 : /** Apply this matrix to the src rectangle, and write the four transformed
554 : points into dst. The points written to dst will be the original top-left, top-right,
555 : bottom-right, and bottom-left points transformed by the matrix.
556 : @param dst Where the transformed quad is written.
557 : @param rect The original rectangle to be transformed.
558 : */
559 0 : void mapRectToQuad(SkPoint dst[4], const SkRect& rect) const {
560 : // This could potentially be faster if we only transformed each x and y of the rect once.
561 0 : rect.toQuad(dst);
562 0 : this->mapPoints(dst, 4);
563 0 : }
564 :
565 : /**
566 : * Maps a rect to another rect, asserting (in debug mode) that the matrix only contains
567 : * scale and translate elements. If it contains other elements, the results are undefined.
568 : */
569 : void mapRectScaleTranslate(SkRect* dst, const SkRect& src) const;
570 :
571 : /** Return the mean radius of a circle after it has been mapped by
572 : this matrix. NOTE: in perspective this value assumes the circle
573 : has its center at the origin.
574 : */
575 : SkScalar mapRadius(SkScalar radius) const;
576 :
577 : typedef void (*MapXYProc)(const SkMatrix& mat, SkScalar x, SkScalar y,
578 : SkPoint* result);
579 :
580 187 : static MapXYProc GetMapXYProc(TypeMask mask) {
581 187 : SkASSERT((mask & ~kAllMasks) == 0);
582 187 : return gMapXYProcs[mask & kAllMasks];
583 : }
584 :
585 187 : MapXYProc getMapXYProc() const {
586 187 : return GetMapXYProc(this->getType());
587 : }
588 :
589 : typedef void (*MapPtsProc)(const SkMatrix& mat, SkPoint dst[],
590 : const SkPoint src[], int count);
591 :
592 333 : static MapPtsProc GetMapPtsProc(TypeMask mask) {
593 333 : SkASSERT((mask & ~kAllMasks) == 0);
594 333 : return gMapPtsProcs[mask & kAllMasks];
595 : }
596 :
597 333 : MapPtsProc getMapPtsProc() const {
598 333 : return GetMapPtsProc(this->getType());
599 : }
600 :
601 : /** Returns true if the matrix can be stepped in X (not complex
602 : perspective).
603 : */
604 : bool isFixedStepInX() const;
605 :
606 : /** If the matrix can be stepped in X (not complex perspective)
607 : then return the step value.
608 : If it cannot, behavior is undefined.
609 : */
610 : SkVector fixedStepInX(SkScalar y) const;
611 :
612 : /** Efficient comparison of two matrices. It distinguishes between zero and
613 : * negative zero. It will return false when the sign of zero values is the
614 : * only difference between the two matrices. It considers NaN values to be
615 : * equal to themselves. So a matrix full of NaNs is "cheap equal" to
616 : * another matrix full of NaNs iff the NaN values are bitwise identical
617 : * while according to strict the strict == test a matrix with a NaN value
618 : * is equal to nothing, including itself.
619 : */
620 0 : bool cheapEqualTo(const SkMatrix& m) const {
621 0 : return 0 == memcmp(fMat, m.fMat, sizeof(fMat));
622 : }
623 :
624 : friend SK_API bool operator==(const SkMatrix& a, const SkMatrix& b);
625 0 : friend SK_API bool operator!=(const SkMatrix& a, const SkMatrix& b) {
626 0 : return !(a == b);
627 : }
628 :
629 : enum {
630 : // writeTo/readFromMemory will never return a value larger than this
631 : kMaxFlattenSize = 9 * sizeof(SkScalar) + sizeof(uint32_t)
632 : };
633 : // return the number of bytes written, whether or not buffer is null
634 : size_t writeToMemory(void* buffer) const;
635 : /**
636 : * Reads data from the buffer parameter
637 : *
638 : * @param buffer Memory to read from
639 : * @param length Amount of memory available in the buffer
640 : * @return number of bytes read (must be a multiple of 4) or
641 : * 0 if there was not enough memory available
642 : */
643 : size_t readFromMemory(const void* buffer, size_t length);
644 :
645 : void dump() const;
646 : void toString(SkString*) const;
647 :
648 : /**
649 : * Calculates the minimum scaling factor of the matrix as computed from the SVD of the upper
650 : * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective)
651 : * -1 is returned.
652 : *
653 : * @return minimum scale factor
654 : */
655 : SkScalar getMinScale() const;
656 :
657 : /**
658 : * Calculates the maximum scaling factor of the matrix as computed from the SVD of the upper
659 : * left 2x2. If the max scale factor cannot be computed (for example overflow or perspective)
660 : * -1 is returned.
661 : *
662 : * @return maximum scale factor
663 : */
664 : SkScalar getMaxScale() const;
665 :
666 : /**
667 : * Gets both the min and max scale factors. The min scale factor is scaleFactors[0] and the max
668 : * is scaleFactors[1]. If the min/max scale factors cannot be computed false is returned and the
669 : * values of scaleFactors[] are undefined.
670 : */
671 : bool SK_WARN_UNUSED_RESULT getMinMaxScales(SkScalar scaleFactors[2]) const;
672 :
673 : /**
674 : * Attempt to decompose this matrix into a scale-only component and whatever remains, where
675 : * the scale component is to be applied first.
676 : *
677 : * M -> Remaining * Scale
678 : *
679 : * On success, return true and assign the scale and remaining components (assuming their
680 : * respective parameters are not null). On failure return false and ignore the parameters.
681 : *
682 : * Possible reasons to fail: perspective, one or more scale factors are zero.
683 : */
684 : bool decomposeScale(SkSize* scale, SkMatrix* remaining = NULL) const;
685 :
686 : /**
687 : * Return a reference to a const identity matrix
688 : */
689 : static const SkMatrix& I();
690 :
691 : /**
692 : * Return a reference to a const matrix that is "invalid", one that could
693 : * never be used.
694 : */
695 : static const SkMatrix& InvalidMatrix();
696 :
697 : /**
698 : * Return the concatenation of two matrices, a * b.
699 : */
700 617 : static SkMatrix Concat(const SkMatrix& a, const SkMatrix& b) {
701 : SkMatrix result;
702 617 : result.setConcat(a, b);
703 617 : return result;
704 : }
705 :
706 : /**
707 : * Testing routine; the matrix's type cache should never need to be
708 : * manually invalidated during normal use.
709 : */
710 : void dirtyMatrixTypeCache() {
711 : this->setTypeMask(kUnknown_Mask);
712 : }
713 :
714 : /**
715 : * Initialize the matrix to be scale + post-translate.
716 : */
717 221 : void setScaleTranslate(SkScalar sx, SkScalar sy, SkScalar tx, SkScalar ty) {
718 221 : fMat[kMScaleX] = sx;
719 221 : fMat[kMSkewX] = 0;
720 221 : fMat[kMTransX] = tx;
721 :
722 221 : fMat[kMSkewY] = 0;
723 221 : fMat[kMScaleY] = sy;
724 221 : fMat[kMTransY] = ty;
725 :
726 221 : fMat[kMPersp0] = 0;
727 221 : fMat[kMPersp1] = 0;
728 221 : fMat[kMPersp2] = 1;
729 :
730 221 : unsigned mask = 0;
731 221 : if (sx != 1 || sy != 1) {
732 20 : mask |= kScale_Mask;
733 : }
734 221 : if (tx || ty) {
735 93 : mask |= kTranslate_Mask;
736 : }
737 221 : this->setTypeMask(mask | kRectStaysRect_Mask);
738 221 : }
739 :
740 : /**
741 : * Are all elements of the matrix finite?
742 : */
743 25 : bool isFinite() const { return SkScalarsAreFinite(fMat, 9); }
744 :
745 : private:
746 : enum {
747 : /** Set if the matrix will map a rectangle to another rectangle. This
748 : can be true if the matrix is scale-only, or rotates a multiple of
749 : 90 degrees.
750 :
751 : This bit will be set on identity matrices
752 : */
753 : kRectStaysRect_Mask = 0x10,
754 :
755 : /** Set if the perspective bit is valid even though the rest of
756 : the matrix is Unknown.
757 : */
758 : kOnlyPerspectiveValid_Mask = 0x40,
759 :
760 : kUnknown_Mask = 0x80,
761 :
762 : kORableMasks = kTranslate_Mask |
763 : kScale_Mask |
764 : kAffine_Mask |
765 : kPerspective_Mask,
766 :
767 : kAllMasks = kTranslate_Mask |
768 : kScale_Mask |
769 : kAffine_Mask |
770 : kPerspective_Mask |
771 : kRectStaysRect_Mask
772 : };
773 :
774 : SkScalar fMat[9];
775 : mutable uint32_t fTypeMask;
776 :
777 : static void ComputeInv(SkScalar dst[9], const SkScalar src[9], double invDet, bool isPersp);
778 :
779 : uint8_t computeTypeMask() const;
780 : uint8_t computePerspectiveTypeMask() const;
781 :
782 3163 : void setTypeMask(int mask) {
783 : // allow kUnknown or a valid mask
784 3163 : SkASSERT(kUnknown_Mask == mask || (mask & kAllMasks) == mask ||
785 : ((kUnknown_Mask | kOnlyPerspectiveValid_Mask) & mask)
786 : == (kUnknown_Mask | kOnlyPerspectiveValid_Mask));
787 3163 : fTypeMask = SkToU8(mask);
788 3163 : }
789 :
790 0 : void orTypeMask(int mask) {
791 0 : SkASSERT((mask & kORableMasks) == mask);
792 0 : fTypeMask = SkToU8(fTypeMask | mask);
793 0 : }
794 :
795 15 : void clearTypeMask(int mask) {
796 : // only allow a valid mask
797 15 : SkASSERT((mask & kAllMasks) == mask);
798 15 : fTypeMask = fTypeMask & ~mask;
799 15 : }
800 :
801 999 : TypeMask getPerspectiveTypeMaskOnly() const {
802 1430 : if ((fTypeMask & kUnknown_Mask) &&
803 431 : !(fTypeMask & kOnlyPerspectiveValid_Mask)) {
804 394 : fTypeMask = this->computePerspectiveTypeMask();
805 : }
806 999 : return (TypeMask)(fTypeMask & 0xF);
807 : }
808 :
809 : /** Returns true if we already know that the matrix is identity;
810 : false otherwise.
811 : */
812 1327 : bool isTriviallyIdentity() const {
813 1327 : if (fTypeMask & kUnknown_Mask) {
814 0 : return false;
815 : }
816 1327 : return ((fTypeMask & 0xF) == 0);
817 : }
818 :
819 644 : inline void updateTranslateMask() {
820 644 : if ((fMat[kMTransX] != 0) | (fMat[kMTransY] != 0)) {
821 458 : fTypeMask |= kTranslate_Mask;
822 : } else {
823 186 : fTypeMask &= ~kTranslate_Mask;
824 : }
825 644 : }
826 :
827 : bool SK_WARN_UNUSED_RESULT invertNonIdentity(SkMatrix* inverse) const;
828 :
829 : static bool Poly2Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
830 : static bool Poly3Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
831 : static bool Poly4Proc(const SkPoint[], SkMatrix*, const SkPoint& scale);
832 :
833 : static void Identity_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
834 : static void Trans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
835 : static void Scale_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
836 : static void ScaleTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
837 : static void Rot_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
838 : static void RotTrans_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
839 : static void Persp_xy(const SkMatrix&, SkScalar, SkScalar, SkPoint*);
840 :
841 : static const MapXYProc gMapXYProcs[];
842 :
843 : static void Identity_pts(const SkMatrix&, SkPoint[], const SkPoint[], int);
844 : static void Trans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
845 : static void Scale_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
846 : static void ScaleTrans_pts(const SkMatrix&, SkPoint dst[], const SkPoint[],
847 : int count);
848 : static void Persp_pts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
849 :
850 : static void Affine_vpts(const SkMatrix&, SkPoint dst[], const SkPoint[], int);
851 :
852 : static const MapPtsProc gMapPtsProcs[];
853 :
854 : friend class SkPerspIter;
855 : friend class SkMatrixPriv;
856 : };
857 : SK_END_REQUIRE_DENSE
858 :
859 : #endif
|