Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

444 lines
11 KiB

  1. /**************************************************************************\
  2. *
  3. * Copyright (c) 1998 Microsoft Corporation
  4. *
  5. * Module Name:
  6. *
  7. * Matrix.hpp
  8. *
  9. * Abstract:
  10. *
  11. * Matrix used by GDI+ implementation
  12. *
  13. * Revision History:
  14. *
  15. * 12/01/1998 davidx
  16. * Created it.
  17. *
  18. \**************************************************************************/
  19. #ifndef __MATRIX_HPP
  20. #define __MATRIX_HPP
  21. // Common constants used for conversions.
  22. #define DEGREESPERRADIAN 57.2957795130823
  23. //--------------------------------------------------------------------------
  24. // Represents a 2D affine transformation matrix
  25. //--------------------------------------------------------------------------
  26. enum MatrixRotate
  27. {
  28. MatrixRotateBy0,
  29. MatrixRotateBy90,
  30. MatrixRotateBy180,
  31. MatrixRotateBy270,
  32. MatrixRotateByOther
  33. };
  34. class GpMatrix
  35. {
  36. private:
  37. // We now use an ObjectTag to determine if the object is valid
  38. // instead of using a BOOL. This is much more robust and helps
  39. // with debugging. It also enables us to version our objects
  40. // more easily with a version number in the ObjectTag.
  41. ObjectTag Tag; // Keep this as the 1st value in the object!
  42. protected:
  43. VOID SetValid(BOOL valid)
  44. {
  45. Tag = valid ? ObjectTagMatrix : ObjectTagInvalid;
  46. }
  47. // This method is here so that we have a virtual function table so
  48. // that we can add virtual methods in V2 without shifting the position
  49. // of the Tag value within the data structure.
  50. virtual VOID DontCallThis()
  51. {
  52. DontCallThis();
  53. }
  54. public:
  55. // Default constructor - set to identity matrix
  56. GpMatrix()
  57. {
  58. Reset();
  59. }
  60. ~GpMatrix()
  61. {
  62. SetValid(FALSE); // so we don't use a deleted object
  63. }
  64. // Reset the matrix object to identity
  65. VOID Reset()
  66. {
  67. M11 = M22 = 1;
  68. M12 = M21 = Dx = Dy = 0;
  69. Complexity = IdentityMask;
  70. SetValid(TRUE);
  71. }
  72. // Construct a GpMatrix object with the specified elements
  73. GpMatrix(REAL m11, REAL m12,
  74. REAL m21, REAL m22,
  75. REAL dx, REAL dy)
  76. {
  77. SetValid(TRUE);
  78. M11 = m11;
  79. M12 = m12;
  80. M21 = m21;
  81. M22 = m22;
  82. Dx = dx;
  83. Dy = dy;
  84. Complexity = ComputeComplexity();
  85. }
  86. GpMatrix(REAL *elems)
  87. {
  88. SetValid(TRUE);
  89. M11 = elems[0];
  90. M12 = elems[1];
  91. M21 = elems[2];
  92. M22 = elems[3];
  93. Dx = elems[4];
  94. Dy = elems[5];
  95. Complexity = ComputeComplexity();
  96. }
  97. GpMatrix(const GpMatrix &matrix)
  98. {
  99. SetValid(TRUE);
  100. M11 = matrix.M11;
  101. M12 = matrix.M12;
  102. M21 = matrix.M21;
  103. M22 = matrix.M22;
  104. Dx = matrix.Dx;
  105. Dy = matrix.Dy;
  106. Complexity = matrix.Complexity;
  107. }
  108. GpLockable *GetObjectLock() const
  109. {
  110. return &Lockable;
  111. }
  112. // If the matrix came from a different version of GDI+, its tag
  113. // will not match, and it won't be considered valid.
  114. BOOL IsValid() const
  115. {
  116. #ifdef _X86_
  117. // We have to guarantee that the Tag field doesn't move for
  118. // versioning to work between releases of GDI+.
  119. ASSERT(offsetof(GpMatrix, Tag) == 4);
  120. #endif
  121. ASSERT((Tag == ObjectTagMatrix) || (Tag == ObjectTagInvalid));
  122. #if DBG
  123. if (Tag == ObjectTagInvalid)
  124. {
  125. WARNING1("Invalid Matrix");
  126. }
  127. #endif
  128. return (Tag == ObjectTagMatrix);
  129. }
  130. // Construct a GpMatrix object by inferring from a rectangle-to-
  131. // parallelogram mapping:
  132. GpMatrix(const GpPointF* destPoints, const GpRectF& srcRect);
  133. GpStatus InferAffineMatrix(const GpPointF* destPoints, const GpRectF& srcRect);
  134. GpStatus InferAffineMatrix(const GpRectF& destRect, const GpRectF& srcRect);
  135. GpMatrix* Clone()
  136. {
  137. return new GpMatrix(*this);
  138. }
  139. // Transform an array of points using the matrix v' = v M:
  140. //
  141. // ( M11 M12 0 )
  142. // (vx', vy', 1) = (vx, vy, 1) ( M21 M22 0 )
  143. // ( dx dy 1 )
  144. VOID Transform(GpPointF* points, INT count = 1) const;
  145. VOID Transform(
  146. const GpPointF* srcPoints,
  147. GpPointF* destPoints,
  148. INT count = 1
  149. ) const;
  150. VOID Transform(
  151. const GpPointF* srcPoints,
  152. POINT * destPoints,
  153. INT count = 1
  154. ) const;
  155. VOID TransformRect(GpRectF & rect) const;
  156. VOID VectorTransform(GpPointF* points, INT count = 1) const;
  157. // XTransform returns only the x-component result of a vector
  158. // transformation:
  159. REAL XTransform(REAL x, REAL y)
  160. {
  161. return(x*M11 + y*M21 + Dx);
  162. }
  163. BOOL IsEqual(const GpMatrix * m) const
  164. {
  165. // Note that we can't assert here that the two cached
  166. // complexity's are equal, since it's perfectly legal to
  167. // have a cache complexity that indicates more complexity
  168. // than is actually there (such as the case of a sequence
  169. // of rotations that ends up back in an identity transform):
  170. // !!![andrewgo] This should probably be using an epsilon compare
  171. return((M11 == m->M11) &&
  172. (M12 == m->M12) &&
  173. (M21 == m->M21) &&
  174. (M22 == m->M22) &&
  175. (Dx == m->Dx) &&
  176. (Dy == m->Dy));
  177. }
  178. REAL GetDeterminant() const
  179. {
  180. return (M11*M22 - M12*M21);
  181. }
  182. // Compare to a scaled value of epsilon used for matrix complexity
  183. // calculations. Must scale maximum value of matrix members to be
  184. // in the right range for comparison.
  185. BOOL IsInvertible() const
  186. {
  187. return !IsCloseReal(0.0f, GetDeterminant());
  188. }
  189. GpStatus Invert();
  190. VOID Scale(REAL scaleX, REAL scaleY, GpMatrixOrder order = MatrixOrderPrepend);
  191. VOID Rotate(REAL angle, GpMatrixOrder order = MatrixOrderPrepend);
  192. VOID Translate(REAL offsetX, REAL offsetY, GpMatrixOrder order = MatrixOrderPrepend);
  193. VOID Shear(REAL shearX, REAL shearY, GpMatrixOrder order = MatrixOrderPrepend);
  194. VOID AppendScale(REAL scaleX, REAL scaleY)
  195. {
  196. M11 *= scaleX;
  197. M21 *= scaleX;
  198. M12 *= scaleY;
  199. M22 *= scaleY;
  200. Dx *= scaleX;
  201. Dy *= scaleY;
  202. Complexity = ComputeComplexity();
  203. }
  204. VOID AppendTranslate(REAL offsetX, REAL offsetY)
  205. {
  206. Dx += offsetX;
  207. Dy += offsetY;
  208. Complexity |= TranslationMask;
  209. AssertComplexity();
  210. }
  211. // Scale the entire matrix by the scale value
  212. static VOID ScaleMatrix(GpMatrix& m, const GpMatrix& m1,
  213. REAL scaleX, REAL scaleY);
  214. static VOID MultiplyMatrix(GpMatrix& m, const GpMatrix& m1, const GpMatrix& m2);
  215. VOID Append(const GpMatrix& m)
  216. {
  217. MultiplyMatrix(*this, *this, m);
  218. }
  219. VOID Prepend(const GpMatrix& m)
  220. {
  221. MultiplyMatrix(*this, m, *this);
  222. }
  223. // Get/set matrix elements
  224. VOID GetMatrix(REAL* m) const
  225. {
  226. m[0] = M11;
  227. m[1] = M12;
  228. m[2] = M21;
  229. m[3] = M22;
  230. m[4] = Dx;
  231. m[5] = Dy;
  232. }
  233. // This is for metafiles -- we don't save the complexity in the metafile
  234. VOID WriteMatrix(IStream * stream) const
  235. {
  236. REAL m[6];
  237. GetMatrix(m);
  238. stream->Write(m, 6 * sizeof(REAL), NULL);
  239. }
  240. VOID SetMatrix(const REAL* m)
  241. {
  242. M11 = m[0];
  243. M12 = m[1];
  244. M21 = m[2];
  245. M22 = m[3];
  246. Dx = m[4];
  247. Dy = m[5];
  248. Complexity = ComputeComplexity();
  249. }
  250. VOID SetMatrix(REAL m11, REAL m12,
  251. REAL m21, REAL m22,
  252. REAL dx, REAL dy)
  253. {
  254. M11 = m11;
  255. M12 = m12;
  256. M21 = m21;
  257. M22 = m22;
  258. Dx = dx;
  259. Dy = dy;
  260. Complexity = ComputeComplexity();
  261. }
  262. VOID RemoveTranslation()
  263. {
  264. Dx = 0;
  265. Dy = 0;
  266. Complexity &= ~TranslationMask;
  267. AssertComplexity();
  268. }
  269. // Determine matrix complexity
  270. enum
  271. {
  272. IdentityMask = 0x0000,
  273. TranslationMask = 0x0001,
  274. ScaleMask = 0x0002,
  275. RotationMask = 0x0004,
  276. ShearMask = 0x0008,
  277. ComplexMask = 0x000f
  278. };
  279. INT GetComplexity() const
  280. {
  281. return Complexity;
  282. }
  283. MatrixRotate GetRotation() const;
  284. RotateFlipType AnalyzeRotateFlip() const;
  285. // Returns TRUE if the matrix does not have anything other than
  286. // translation and/or scale (and/or identity). i.e. there is no rotation
  287. // or shear in the matrix. Returns FALSE if there is a rotation or shear.
  288. BOOL IsTranslateScale() const
  289. {
  290. return (!(Complexity &
  291. ~(GpMatrix::TranslationMask | GpMatrix::ScaleMask)));
  292. }
  293. BOOL IsIdentity() const
  294. {
  295. return (Complexity == IdentityMask);
  296. }
  297. BOOL IsTranslate() const
  298. {
  299. return ((Complexity & ~TranslationMask) == 0);
  300. }
  301. // Returns true if the matrix is a translate-only transform by an
  302. // integer number of pixels.
  303. BOOL IsIntegerTranslate() const
  304. {
  305. return (IsTranslate() &&
  306. (REALABS(static_cast<REAL>(GpRound(Dx)) - Dx) <= PIXEL_EPSILON) &&
  307. (REALABS(static_cast<REAL>(GpRound(Dy)) - Dy) <= PIXEL_EPSILON));
  308. }
  309. BOOL IsMinification() const
  310. {
  311. return (IsTranslateScale() &&
  312. ((M11-1.0f < -REAL_EPSILON) ||
  313. (M22-1.0f < -REAL_EPSILON)));
  314. }
  315. // Returns true if there is any minification or if the transform involves
  316. // rotation/shear.
  317. BOOL IsRotateOrMinification() const
  318. {
  319. return ( ((Complexity & ~(ScaleMask | TranslationMask))!= 0) ||
  320. IsMinification() );
  321. }
  322. BOOL IsRotateOrShear() const
  323. {
  324. return ( (Complexity & ~(ScaleMask | TranslationMask))!= 0);
  325. }
  326. BOOL IsShear() const
  327. {
  328. return ((Complexity & ShearMask) != 0);
  329. }
  330. REAL GetM11() const { return M11; }
  331. REAL GetM12() const { return M12; }
  332. REAL GetM21() const { return M21; }
  333. REAL GetM22() const { return M22; }
  334. REAL GetDx() const { return Dx; }
  335. REAL GetDy() const { return Dy; }
  336. // On checked builds, verify that the Matrix flags are correct.
  337. #if DBG
  338. VOID AssertComplexity() const;
  339. #else
  340. VOID AssertComplexity() const {}
  341. #endif
  342. protected:
  343. mutable GpLockable Lockable;
  344. REAL M11;
  345. REAL M12;
  346. REAL M21;
  347. REAL M22;
  348. REAL Dx;
  349. REAL Dy;
  350. INT Complexity; // Bit-mask short-cut
  351. INT ComputeComplexity() const;
  352. };
  353. #endif