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