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.

1258 lines
45 KiB

  1. /******************************Module*Header*******************************\
  2. * Module Name: xformobj.cxx *
  3. * *
  4. * Xform object non-inline methods. *
  5. * *
  6. * Created: 12-Nov-1990 16:54:37 *
  7. * Author: Wendy Wu [wendywu] *
  8. * *
  9. * Copyright (c) 1990-1999 Microsoft Corporation *
  10. \**************************************************************************/
  11. #include "precomp.hxx"
  12. extern "C" {
  13. void __cdecl _fltused(void) {} // just so that we link clean...
  14. };
  15. #if defined(_AMD64_) || defined(_IA64_) || defined(BUILD_WOW6432)
  16. #define vSetTo1Over16(ef) (ef.e = EFLOAT_1Over16)
  17. #else
  18. #define vSetTo1Over16(ef) (ef.i.lMant = 0x040000000, ef.i.lExp = -2)
  19. #endif
  20. /******************************Data*Structure******************************\
  21. * matrixIdentity *
  22. * *
  23. * Defines the identity transform matrices in different formats. *
  24. * *
  25. * History: *
  26. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  27. * Wrote it. *
  28. \**************************************************************************/
  29. MATRIX gmxIdentity_LToFx =
  30. {
  31. EFLOAT_16, // efM11
  32. EFLOAT_0, // efM12
  33. EFLOAT_0, // efM21
  34. EFLOAT_16, // efM22
  35. EFLOAT_0, // efDx
  36. EFLOAT_0, // efDy
  37. 0, // fxDx
  38. 0, // fxDy
  39. XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION|XFORM_FORMAT_LTOFX
  40. };
  41. MATRIX gmxIdentity_LToL =
  42. {
  43. EFLOAT_1, // efM11
  44. EFLOAT_0, // efM12
  45. EFLOAT_0, // efM21
  46. EFLOAT_1, // efM22
  47. EFLOAT_0, // efDx
  48. EFLOAT_0, // efDy
  49. 0, // fxDx
  50. 0, // fxDy
  51. XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION|XFORM_FORMAT_LTOL
  52. };
  53. MATRIX gmxIdentity_FxToL =
  54. {
  55. EFLOAT_1Over16, // efM11
  56. EFLOAT_0, // efM12
  57. EFLOAT_0, // efM21
  58. EFLOAT_1Over16, // efM22
  59. EFLOAT_0, // efDx
  60. EFLOAT_0, // efDy
  61. 0, // fxDx
  62. 0, // fxDy
  63. XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION|XFORM_FORMAT_FXTOL
  64. };
  65. /******************************Member*Function*****************************\
  66. * EXFORMOBJ::EXFORMOBJ *
  67. * *
  68. * Get a transform matrix based on the request type. The only legitimate *
  69. * type for now is IDENTITY. *
  70. * *
  71. * History: *
  72. * 27-Mar-1991 -by- Wendy Wu [wendywu] *
  73. * Wrote it. *
  74. \**************************************************************************/
  75. EXFORMOBJ::EXFORMOBJ(ULONG iXform, ULONG iFormat)
  76. {
  77. ASSERTGDI((iXform == IDENTITY),"XFORMOBJ:invalid iXform\n");
  78. bMirrored = FALSE;
  79. if (iFormat == XFORM_FORMAT_LTOFX)
  80. pmx = &gmxIdentity_LToFx;
  81. else if (iFormat == XFORM_FORMAT_FXTOL)
  82. pmx = &gmxIdentity_FxToL;
  83. else
  84. pmx = &gmxIdentity_LToL;
  85. }
  86. /******************************Member*Function*****************************\
  87. * EXFORMOBJ::bEqual(EXFORMOBJ& xo) *
  88. * *
  89. * See if two transforms are identical. Matrices of different formats are *
  90. * considered different even though the coefficients are same. *
  91. * *
  92. * History: *
  93. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  94. * Wrote it. *
  95. \**************************************************************************/
  96. BOOL EXFORMOBJ::bEqual(EXFORMOBJ& xo)
  97. {
  98. if (pmx == xo.pmx)
  99. return(TRUE); // point to the same matrix
  100. // compare each and every element of the matrices as the structures may
  101. // be padded.
  102. return ((pmx->efM11 == xo.pmx->efM11) && (pmx->efM12 == xo.pmx->efM12) &&
  103. (pmx->efM21 == xo.pmx->efM21) && (pmx->efM22 == xo.pmx->efM22) &&
  104. (pmx->efDx == xo.pmx->efDx) && (pmx->efDy == xo.pmx->efDy));
  105. }
  106. /******************************Member*Function*****************************\
  107. * EXFORMOBJ::bEqualExceptTranslations *
  108. * *
  109. * See if two transforms are identical other than the translations elements.*
  110. * Matrices of different formats are considered different even though the *
  111. * coefficients are same. *
  112. * *
  113. * History: *
  114. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  115. * Wrote it. *
  116. \**************************************************************************/
  117. BOOL EXFORMOBJ::bEqualExceptTranslations(PMATRIX pmx_)
  118. {
  119. if (pmx == pmx_)
  120. return(TRUE); // point to the same matrix
  121. // compare each and every element of the matrices as the structures may
  122. // be padded.
  123. return ((pmx->efM11 == pmx_->efM11) && (pmx->efM12 == pmx_->efM12) &&
  124. (pmx->efM21 == pmx_->efM21) && (pmx->efM22 == pmx_->efM22));
  125. }
  126. /******************************Member*Function*****************************\
  127. * EXFORMOBJ::bXform *
  128. * *
  129. * Transform a list of POINTL to a list of POINTL. *
  130. * *
  131. * History: *
  132. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  133. * Wrote it. *
  134. \**************************************************************************/
  135. BOOL EXFORMOBJ::bXform(
  136. PPOINTL pptlSrc,
  137. PPOINTL pptlDst,
  138. SIZE_T cPts)
  139. {
  140. ASSERTGDI(cPts > 0, "Can take only positive count");
  141. ASSERTGDI( (((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOFX) ||
  142. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_FXTOL) ||
  143. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOL)),
  144. "EXFORMOBJ::bXformPtlToPtl: wrong xform format\n");
  145. // copy the source to the dest, This way we can use bCvtPts1 which is more efficient
  146. if (pptlSrc != pptlDst)
  147. {
  148. RtlCopyMemory(pptlDst, pptlSrc, cPts*sizeof(POINTL));
  149. }
  150. // Straight copy if identity transform.
  151. if (bIdentity())
  152. {
  153. return(TRUE);
  154. }
  155. BOOL bReturn = bCvtPts1(pmx, pptlDst, cPts);
  156. if (!bReturn)
  157. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  158. return(bReturn);
  159. }
  160. /******************************Member*Function*****************************\
  161. * EXFORMOBJ::bXform *
  162. * *
  163. * Transform a list of POINTL to a list of POINTFIX. *
  164. * *
  165. * History: *
  166. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  167. * Wrote it. *
  168. \**************************************************************************/
  169. BOOL EXFORMOBJ::bXform(
  170. PPOINTL pptlSrc,
  171. PPOINTFIX pptfxDst,
  172. SIZE_T cPts)
  173. {
  174. ASSERTGDI(cPts > 0, "Can take only positive count");
  175. ASSERTGDI((pmx->flAccel & XFORM_FORMAT_LTOFX),
  176. "EXFORMOBJ::bXformPtlToPtfx: wrong xform format\n");
  177. // Convert a list of POINTL to a list of POINTFIX if identity transform.
  178. if (bIdentity())
  179. {
  180. PPOINTL pptlSrcEnd = pptlSrc + cPts;
  181. for ( ; pptlSrc < pptlSrcEnd; pptlSrc++, pptfxDst++)
  182. {
  183. pptfxDst->x = LTOFX(pptlSrc->x);
  184. pptfxDst->y = LTOFX(pptlSrc->y);
  185. }
  186. return(TRUE);
  187. }
  188. BOOL bRet = bCvtPts(pmx, pptlSrc, (PPOINTL)pptfxDst, cPts);
  189. if (!bRet)
  190. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  191. return bRet;
  192. }
  193. /******************************Member*Function*****************************\
  194. * EXFORMOBJ::bXformRound *
  195. * *
  196. * Transform a list of POINTL to a list of POINTFIX. Round the resulting *
  197. * points to the nearest integers for Win31 compatibility. *
  198. * *
  199. * History: *
  200. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  201. * Wrote it. *
  202. \**************************************************************************/
  203. BOOL EXFORMOBJ::bXformRound(
  204. PPOINTL pptlSrc,
  205. PPOINTFIX pptfxDst,
  206. SIZE_T cPts)
  207. {
  208. ASSERTGDI(cPts > 0, "Can take only positive count");
  209. ASSERTGDI((pmx->flAccel & XFORM_FORMAT_LTOFX),
  210. "EXFORMOBJ::bXformPtlToPtfx: wrong xform format\n");
  211. // Convert a list of POINTL to a list of POINTFIX if identity transform.
  212. if (bIdentity())
  213. {
  214. PPOINTL pptlSrcEnd = pptlSrc + cPts;
  215. for ( ; pptlSrc < pptlSrcEnd; pptlSrc++, pptfxDst++)
  216. {
  217. pptfxDst->x = LTOFX(pptlSrc->x);
  218. pptfxDst->y = LTOFX(pptlSrc->y);
  219. }
  220. return(TRUE);
  221. }
  222. BOOL bRet = bCvtPts(pmx, pptlSrc, (PPOINTL)pptfxDst, cPts);
  223. if (!bRet)
  224. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  225. if (ulMode != GM_ADVANCED)
  226. {
  227. PPOINTFIX pptfxDstEnd = pptfxDst + cPts;
  228. for ( ; pptfxDst < pptfxDstEnd; pptfxDst++)
  229. {
  230. pptfxDst->x = (pptfxDst->x + FIX_HALF) & 0xFFFFFFF0;
  231. pptfxDst->y = (pptfxDst->y + FIX_HALF) & 0xFFFFFFF0;
  232. }
  233. }
  234. return bRet;
  235. }
  236. /******************************Member*Function*****************************\
  237. * EXFORMOBJ::bXform *
  238. * *
  239. * Transform a list of POINTFIX to a list of POINTL. *
  240. * *
  241. * History: *
  242. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  243. * Wrote it. *
  244. \**************************************************************************/
  245. BOOL EXFORMOBJ::bXform(
  246. PPOINTFIX pptfxSrc,
  247. PPOINTL pptlDst,
  248. SIZE_T cPts)
  249. {
  250. ASSERTGDI(cPts > 0, "Can take only positive count");
  251. ASSERTGDI((pmx->flAccel & XFORM_FORMAT_FXTOL),
  252. "EXFORMOBJ::bXformPtfxToPtl: wrong xform format\n");
  253. // Convert a list of POINTFIX to a list of POINTL if identity transform.
  254. if (bIdentity())
  255. {
  256. PPOINTFIX pptfxSrcEnd = pptfxSrc + cPts;
  257. for ( ; pptfxSrc < pptfxSrcEnd; pptfxSrc++, pptlDst++)
  258. {
  259. pptlDst->x = FXTOLROUND(pptfxSrc->x);
  260. pptlDst->y = FXTOLROUND(pptfxSrc->y);
  261. }
  262. return(TRUE); // never overflows
  263. }
  264. BOOL bRet = bCvtPts(pmx, (PPOINTL)pptfxSrc, pptlDst, cPts);
  265. if (!bRet)
  266. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  267. return bRet;
  268. }
  269. /******************************Member*Function*****************************\
  270. * BOOL EXFORMOBJ::bXform
  271. *
  272. * Given a list of vectors (pptflSrc) and number of points in the list (cVts)
  273. * transform the vectors and store into another list (pptflDst).
  274. *
  275. * History:
  276. * 28-Jan-1992 -by- Wendy Wu [wendywu]
  277. * Wrote it.
  278. \**************************************************************************/
  279. BOOL EXFORMOBJ::bXform(
  280. PVECTORFL pvtflSrc,
  281. PVECTORFL pvtflDst,
  282. SIZE_T cVts)
  283. {
  284. ASSERTGDI(cVts > 0, "Can take only positive count");
  285. // check for quick exit, if the transform consists of translations
  286. // only, there is nothing to do:
  287. if (bTranslationsOnly())
  288. {
  289. if (pvtflDst != pvtflSrc) // if not transforming in place
  290. {
  291. RtlCopyMemory(pvtflDst, pvtflSrc, cVts*sizeof(VECTORFL));
  292. }
  293. return(TRUE);
  294. }
  295. BOOL bRet;
  296. if (pmx->flAccel & XFORM_FORMAT_LTOL)
  297. {
  298. bRet = bCvtVts_FlToFl(pmx, pvtflSrc, pvtflDst, cVts);
  299. }
  300. else if (pmx->flAccel & XFORM_FORMAT_LTOFX)
  301. {
  302. pmx->efM11.vDivBy16();
  303. pmx->efM12.vDivBy16();
  304. pmx->efM21.vDivBy16();
  305. pmx->efM22.vDivBy16();
  306. bRet = bCvtVts_FlToFl(pmx, pvtflSrc, pvtflDst, cVts);
  307. pmx->efM11.vTimes16();
  308. pmx->efM12.vTimes16();
  309. pmx->efM21.vTimes16();
  310. pmx->efM22.vTimes16();
  311. }
  312. else
  313. {
  314. pmx->efM11.vTimes16();
  315. pmx->efM12.vTimes16();
  316. pmx->efM21.vTimes16();
  317. pmx->efM22.vTimes16();
  318. bRet = bCvtVts_FlToFl(pmx, pvtflSrc, pvtflDst, cVts);
  319. pmx->efM11.vDivBy16();
  320. pmx->efM12.vDivBy16();
  321. pmx->efM21.vDivBy16();
  322. pmx->efM22.vDivBy16();
  323. }
  324. if (!bRet)
  325. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  326. return bRet;
  327. }
  328. /******************************Member*Function*****************************\
  329. * EXFORMOBJ::bXform *
  330. * *
  331. * Transform a list of VECTORL to a list of VECTORL. *
  332. * *
  333. * History: *
  334. * 28-Jan-1992 -by- Wendy Wu [wendywu] *
  335. * Wrote it. *
  336. \**************************************************************************/
  337. BOOL EXFORMOBJ::bXform(
  338. PVECTORL pvtlSrc,
  339. PVECTORL pvtlDst,
  340. SIZE_T cVts)
  341. {
  342. ASSERTGDI(cVts > 0, "Can take only positive count");
  343. // Straight copy if identity transform.
  344. ASSERTGDI((pmx->flAccel & XFORM_FORMAT_LTOFX),
  345. "EXFORMOBJ::bXformVtlToVtl: wrong xform format\n");
  346. if (bTranslationsOnly())
  347. {
  348. if (pvtlDst != pvtlSrc)
  349. {
  350. RtlCopyMemory(pvtlDst, pvtlSrc, cVts*sizeof(VECTORL));
  351. return(TRUE);
  352. }
  353. }
  354. pmx->efM11.vDivBy16();
  355. pmx->efM12.vDivBy16();
  356. pmx->efM21.vDivBy16();
  357. pmx->efM22.vDivBy16();
  358. BOOL bReturn = bCvtVts(pmx, pvtlSrc, pvtlDst, cVts);
  359. pmx->efM11.vTimes16();
  360. pmx->efM12.vTimes16();
  361. pmx->efM21.vTimes16();
  362. pmx->efM22.vTimes16();
  363. if (!bReturn)
  364. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  365. return(bReturn);
  366. }
  367. /******************************Member*Function*****************************\
  368. * EXFORMOBJ::bXform *
  369. * *
  370. * Transform a list of VECTORL to a list of VECTORFX. *
  371. * *
  372. * History: *
  373. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  374. * Wrote it. *
  375. \**************************************************************************/
  376. BOOL EXFORMOBJ::bXform(
  377. PVECTORL pvtlSrc,
  378. PVECTORFX pvtfxDst,
  379. SIZE_T cVts)
  380. {
  381. ASSERTGDI(cVts > 0, "Can take only positive count");
  382. ASSERTGDI((pmx->flAccel & XFORM_FORMAT_LTOFX),
  383. "XFORMOBJ::bXformVtlToVtfx: wrong xform format\n");
  384. // Convert a list of VECTORL to a list of VECTORFX if identity transform.
  385. if (bTranslationsOnly())
  386. {
  387. PVECTORL pvtlSrcEnd = pvtlSrc + cVts;
  388. for ( ; pvtlSrc < pvtlSrcEnd; pvtlSrc++, pvtfxDst++)
  389. {
  390. if (BLTOFXOK(pvtlSrc->x) && BLTOFXOK(pvtlSrc->y))
  391. {
  392. pvtfxDst->x = LTOFX(pvtlSrc->x);
  393. pvtfxDst->y = LTOFX(pvtlSrc->y);
  394. }
  395. else
  396. {
  397. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  398. return(FALSE);
  399. }
  400. }
  401. return(TRUE);
  402. }
  403. BOOL bRet = bCvtVts(pmx, pvtlSrc, (PVECTORL)pvtfxDst, cVts);
  404. if (!bRet)
  405. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  406. return bRet;
  407. }
  408. /******************************Member*Function*****************************\
  409. * EXFORMOBJ::bXformRound *
  410. * *
  411. * Transform a list of VECTORL to a list of VECTORFIX. Round the resulting *
  412. * vectors to the nearest integers for Win31 compatibility. *
  413. * *
  414. * History: *
  415. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  416. * Wrote it. *
  417. \**************************************************************************/
  418. BOOL EXFORMOBJ::bXformRound(
  419. PVECTORL pvtlSrc,
  420. PVECTORFX pvtfxDst,
  421. SIZE_T cVts)
  422. {
  423. ASSERTGDI(cVts > 0, "Can take only positive count");
  424. ASSERTGDI((pmx->flAccel & XFORM_FORMAT_LTOFX),
  425. "XFORMOBJ::bXformVtlToVtfx: wrong xform format\n");
  426. // Convert a list of VECTORL to a list of VECTORFX if identity transform.
  427. if (bTranslationsOnly())
  428. {
  429. PVECTORL pvtlSrcEnd = pvtlSrc + cVts;
  430. for ( ; pvtlSrc < pvtlSrcEnd; pvtlSrc++, pvtfxDst++)
  431. {
  432. if (BLTOFXOK(pvtlSrc->x) && BLTOFXOK(pvtlSrc->y))
  433. {
  434. pvtfxDst->x = LTOFX(pvtlSrc->x);
  435. pvtfxDst->y = LTOFX(pvtlSrc->y);
  436. }
  437. else
  438. {
  439. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  440. return(FALSE);
  441. }
  442. }
  443. return(TRUE);
  444. }
  445. BOOL bRet = bCvtVts(pmx, pvtlSrc, (PVECTORL)pvtfxDst, cVts);
  446. if (!bRet)
  447. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  448. if (ulMode != GM_ADVANCED)
  449. {
  450. PVECTORFX pvtfxDstEnd = pvtfxDst + cVts;
  451. for ( ; pvtfxDst < pvtfxDstEnd; pvtfxDst++)
  452. {
  453. pvtfxDst->x = (pvtfxDst->x + FIX_HALF) & 0xFFFFFFF0;
  454. pvtfxDst->y = (pvtfxDst->y + FIX_HALF) & 0xFFFFFFF0;
  455. }
  456. }
  457. return bRet;
  458. }
  459. /******************************Member*Function*****************************\
  460. * EXFORMOBJ::bXform *
  461. * *
  462. * Transform a list of VECTORFX to a list of VECTORL. *
  463. * *
  464. * History: *
  465. * 06-Feb-1992 -by- Wendy Wu [wendywu] *
  466. * Wrote it. *
  467. \**************************************************************************/
  468. BOOL EXFORMOBJ::bXform(
  469. PVECTORFX pvtfxSrc,
  470. PVECTORL pvtlDst,
  471. SIZE_T cVts)
  472. {
  473. ASSERTGDI(cVts > 0, "Can take only positive count");
  474. ASSERTGDI((pmx->flAccel & XFORM_FORMAT_FXTOL),
  475. "EXFORMOBJ::bXformVtfxToVtl: wrong xform format\n");
  476. // Convert a list of VECTORFX to a list of VECTORL if identity transform.
  477. if (bTranslationsOnly())
  478. {
  479. PVECTORFX pvtfxSrcEnd = pvtfxSrc + cVts;
  480. for ( ; pvtfxSrc < pvtfxSrcEnd; pvtfxSrc++, pvtlDst++)
  481. {
  482. pvtlDst->x = FXTOL(pvtfxSrc->x);
  483. pvtlDst->y = FXTOL(pvtfxSrc->y);
  484. }
  485. return(TRUE);
  486. }
  487. BOOL bRet = bCvtVts(pmx, (PVECTORL)pvtfxSrc, pvtlDst, cVts);
  488. if (!bRet)
  489. SAVE_ERROR_CODE(ERROR_ARITHMETIC_OVERFLOW);
  490. return bRet;
  491. }
  492. /******************************Member*Function*****************************\
  493. * EXFORMOBJ::vComputeAccelFlags *
  494. * *
  495. * Set the accelerator flags for a given matrix. *
  496. * *
  497. * History: *
  498. * 06-Dec-1990 -by- Wendy Wu [wendywu] *
  499. * Wrote it. *
  500. \**************************************************************************/
  501. VOID EXFORMOBJ::vComputeAccelFlags(FLONG flFormat)
  502. {
  503. pmx->flAccel = flFormat; // clear the flag
  504. // set translation flag
  505. if ((pmx->fxDx == 0) && (pmx->fxDy == 0))
  506. pmx->flAccel |= XFORM_NO_TRANSLATION;
  507. if (pmx->efM12.bIsZero() && pmx->efM21.bIsZero())
  508. {
  509. // off diagonal elements are zeros
  510. pmx->flAccel |= XFORM_SCALE;
  511. switch(flFormat)
  512. {
  513. case XFORM_FORMAT_LTOFX:
  514. if (pmx->efM11.bIs16() && pmx->efM22.bIs16())
  515. pmx->flAccel |= XFORM_UNITY;
  516. break;
  517. case XFORM_FORMAT_LTOL:
  518. if (pmx->efM11.bIs1() && pmx->efM22.bIs1())
  519. pmx->flAccel |= XFORM_UNITY;
  520. break;
  521. default:
  522. if (pmx->efM11.bIs1Over16() && pmx->efM22.bIs1Over16())
  523. pmx->flAccel |= XFORM_UNITY;
  524. break;
  525. }
  526. }
  527. }
  528. /******************************Member*Function*****************************\
  529. * EXFORMOBJ::vCopy(EXFORMOBJ& xo) *
  530. * *
  531. * Copy the coefficient values of a transform to another. *
  532. * *
  533. * History: *
  534. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  535. * Wrote it. *
  536. \**************************************************************************/
  537. VOID EXFORMOBJ::vCopy(EXFORMOBJ& xo)
  538. {
  539. RtlCopyMemory(pmx, xo.pmx, sizeof(MATRIX));
  540. }
  541. /******************************Member*Function*****************************\
  542. * EXFORMOBJ::vRemoveTranslation() *
  543. * *
  544. * Remove the translation coefficients of a transform. *
  545. * *
  546. * History: *
  547. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  548. * Wrote it. *
  549. \**************************************************************************/
  550. VOID EXFORMOBJ::vRemoveTranslation()
  551. {
  552. pmx->fxDx = 0;
  553. pmx->fxDy = 0;
  554. pmx->efDx.vSetToZero();
  555. pmx->efDy.vSetToZero();
  556. pmx->flAccel |= XFORM_NO_TRANSLATION;
  557. }
  558. /******************************Member*Function*****************************\
  559. * EXFORMOBJ::vGetCoefficient() *
  560. * *
  561. * Get the coefficient of a transform matrix. This is used to convert *
  562. * our internal matrix structure into the GDI/DDI transform format. *
  563. * *
  564. * History: *
  565. * 12-Nov-1990 -by- Wendy Wu [wendywu] *
  566. * Wrote it. *
  567. \**************************************************************************/
  568. VOID EXFORMOBJ::vGetCoefficient(XFORML *pxf)
  569. {
  570. // The coefficients have already been range-checked before they are set
  571. // in the DC. So it's just a matter of converting them back to
  572. // IEEE FLOAT. They can't possibly overflow.
  573. // For i386, lEfToF() calls off to the assembly routine to do the EFLOAT
  574. // to FLOAT conversion and put the result in eax, we want the C compiler
  575. // to do direct copy to the destination here(no fstp), so some casting
  576. // is necessary. Note the return type of lEfToF() is LONG. We do the
  577. // same thing for MIPS so the code here can be shared.
  578. ASSERTGDI( (((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOFX) ||
  579. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_FXTOL) ||
  580. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOL)),
  581. "EXFORMOBJ::vGetCoefficient: wrong xform format\n");
  582. if (pmx->flAccel & XFORM_FORMAT_LTOFX)
  583. {
  584. MATRIX mxTmp;
  585. mxTmp = *pmx;
  586. mxTmp.efM11.vDivBy16();
  587. mxTmp.efM12.vDivBy16();
  588. mxTmp.efM21.vDivBy16();
  589. mxTmp.efM22.vDivBy16();
  590. mxTmp.efDx.vDivBy16();
  591. mxTmp.efDy.vDivBy16();
  592. *(LONG *)&pxf->eM11 = mxTmp.efM11.lEfToF();
  593. *(LONG *)&pxf->eM12 = mxTmp.efM12.lEfToF();
  594. *(LONG *)&pxf->eM21 = mxTmp.efM21.lEfToF();
  595. *(LONG *)&pxf->eM22 = mxTmp.efM22.lEfToF();
  596. *(LONG *)&pxf->eDx = mxTmp.efDx.lEfToF();
  597. *(LONG *)&pxf->eDy = mxTmp.efDy.lEfToF();
  598. }
  599. else if (pmx->flAccel & XFORM_FORMAT_FXTOL)
  600. {
  601. MATRIX mxTmp;
  602. mxTmp = *pmx;
  603. mxTmp.efM11.vTimes16();
  604. mxTmp.efM12.vTimes16();
  605. mxTmp.efM21.vTimes16();
  606. mxTmp.efM22.vTimes16();
  607. *(LONG *)&pxf->eM11 = mxTmp.efM11.lEfToF();
  608. *(LONG *)&pxf->eM12 = mxTmp.efM12.lEfToF();
  609. *(LONG *)&pxf->eM21 = mxTmp.efM21.lEfToF();
  610. *(LONG *)&pxf->eM22 = mxTmp.efM22.lEfToF();
  611. *(LONG *)&pxf->eDx = mxTmp.efDx.lEfToF();
  612. *(LONG *)&pxf->eDy = mxTmp.efDy.lEfToF();
  613. }
  614. else
  615. {
  616. *(LONG *)&pxf->eM11 = pmx->efM11.lEfToF();
  617. *(LONG *)&pxf->eM12 = pmx->efM12.lEfToF();
  618. *(LONG *)&pxf->eM21 = pmx->efM21.lEfToF();
  619. *(LONG *)&pxf->eM22 = pmx->efM22.lEfToF();
  620. *(LONG *)&pxf->eDx = pmx->efDx.lEfToF();
  621. *(LONG *)&pxf->eDy = pmx->efDy.lEfToF();
  622. }
  623. return;
  624. }
  625. /******************************Member*Function*****************************\
  626. * EXFORMOBJ::vGetCoefficient() *
  627. * *
  628. * Get the coefficient of a transform matrix. This is to convert EFLOAT's *
  629. * into FLOATOBJs which are now the same. *
  630. * *
  631. * History: *
  632. * 13-Mar-1995 -by- Eric Kutter [erick]
  633. * Wrote it. *
  634. \**************************************************************************/
  635. VOID EXFORMOBJ::vGetCoefficient(PFLOATOBJ_XFORM pxf)
  636. {
  637. // The coefficients have already been range-checked before they are set
  638. // in the DC. So it's just a matter of converting them back to
  639. // IEEE FLOAT. They can't possibly overflow.
  640. // For i386, lEfToF() calls off to the assembly routine to do the EFLOAT
  641. // to FLOAT conversion and put the result in eax, we want the C compiler
  642. // to do direct copy to the destination here(no fstp), so some casting
  643. // is necessary. Note the return type of lEfToF() is LONG. We do the
  644. // same thing for MIPS so the code here can be shared.
  645. ASSERTGDI( (((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOFX) ||
  646. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_FXTOL) ||
  647. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOL)),
  648. "EXFORMOBJ::vGetCoefficient: wrong xform format\n");
  649. if (pmx->flAccel & XFORM_FORMAT_LTOFX)
  650. {
  651. MATRIX mxTmp;
  652. mxTmp = *pmx;
  653. mxTmp.efM11.vDivBy16();
  654. mxTmp.efM12.vDivBy16();
  655. mxTmp.efM21.vDivBy16();
  656. mxTmp.efM22.vDivBy16();
  657. mxTmp.efDx.vDivBy16();
  658. mxTmp.efDy.vDivBy16();
  659. *(EFLOAT *)&pxf->eM11 = mxTmp.efM11;
  660. *(EFLOAT *)&pxf->eM12 = mxTmp.efM12;
  661. *(EFLOAT *)&pxf->eM21 = mxTmp.efM21;
  662. *(EFLOAT *)&pxf->eM22 = mxTmp.efM22;
  663. *(EFLOAT *)&pxf->eDx = mxTmp.efDx;
  664. *(EFLOAT *)&pxf->eDy = mxTmp.efDy;
  665. }
  666. else if (pmx->flAccel & XFORM_FORMAT_FXTOL)
  667. {
  668. MATRIX mxTmp;
  669. mxTmp = *pmx;
  670. mxTmp.efM11.vTimes16();
  671. mxTmp.efM12.vTimes16();
  672. mxTmp.efM21.vTimes16();
  673. mxTmp.efM22.vTimes16();
  674. *(EFLOAT *)&pxf->eM11 = mxTmp.efM11;
  675. *(EFLOAT *)&pxf->eM12 = mxTmp.efM12;
  676. *(EFLOAT *)&pxf->eM21 = mxTmp.efM21;
  677. *(EFLOAT *)&pxf->eM22 = mxTmp.efM22;
  678. *(EFLOAT *)&pxf->eDx = mxTmp.efDx;
  679. *(EFLOAT *)&pxf->eDy = mxTmp.efDy;
  680. }
  681. else
  682. {
  683. *(EFLOAT *)&pxf->eM11 = pmx->efM11;
  684. *(EFLOAT *)&pxf->eM12 = pmx->efM12;
  685. *(EFLOAT *)&pxf->eM21 = pmx->efM21;
  686. *(EFLOAT *)&pxf->eM22 = pmx->efM22;
  687. *(EFLOAT *)&pxf->eDx = pmx->efDx;
  688. *(EFLOAT *)&pxf->eDy = pmx->efDy;
  689. }
  690. return;
  691. }
  692. /******************************Member*Function*****************************\
  693. * EXFORMOBJ::vGetCoefficient()
  694. *
  695. * Get the coefficient of a transform matrix. This is used to convert
  696. * our internal matrix structure into the IFI transform format.
  697. *
  698. * History:
  699. * 04-Feb-1992 -by- Gilman Wong [gilmanw]
  700. * Adapted from vGetCoefficient.
  701. \**************************************************************************/
  702. VOID EXFORMOBJ::vGetCoefficient(PFD_XFORM pfd_xf)
  703. {
  704. // The coefficients have already been range-checked before they are set
  705. // in the DC. So it's just a matter of converting them back to
  706. // IEEE FLOAT. They can't possibly overflow.
  707. // For i386, lEfToF() calls off to the assembly routine to do the EFLOAT
  708. // to FLOAT conversion and put the result in eax, we want the C compiler
  709. // to do direct copy to the destination here(no fstp), so some casting
  710. // is necessary. Note the return type of lEfToF() is LONG. We do the
  711. // same thing for MIPS so the code here can be shared.
  712. ASSERTGDI( (((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOFX) ||
  713. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_FXTOL) ||
  714. ((pmx->flAccel & XFORM_FORMAT) == XFORM_FORMAT_LTOL)),
  715. "EXFORMOBJ::vGetCoefficient: wrong xform format\n");
  716. if (pmx->flAccel & XFORM_FORMAT_LTOFX)
  717. {
  718. MATRIX mxTmp;
  719. mxTmp = *pmx;
  720. mxTmp.efM11.vDivBy16();
  721. mxTmp.efM12.vDivBy16();
  722. mxTmp.efM21.vDivBy16();
  723. mxTmp.efM22.vDivBy16();
  724. *(LONG *)&pfd_xf->eXX = mxTmp.efM11.lEfToF();
  725. *(LONG *)&pfd_xf->eXY = mxTmp.efM12.lEfToF();
  726. *(LONG *)&pfd_xf->eYX = mxTmp.efM21.lEfToF();
  727. *(LONG *)&pfd_xf->eYY = mxTmp.efM22.lEfToF();
  728. }
  729. else if (pmx->flAccel & XFORM_FORMAT_FXTOL)
  730. {
  731. MATRIX mxTmp;
  732. mxTmp = *pmx;
  733. mxTmp.efM11.vTimes16();
  734. mxTmp.efM12.vTimes16();
  735. mxTmp.efM21.vTimes16();
  736. mxTmp.efM22.vTimes16();
  737. *(LONG *)&pfd_xf->eXX = mxTmp.efM11.lEfToF();
  738. *(LONG *)&pfd_xf->eXY = mxTmp.efM12.lEfToF();
  739. *(LONG *)&pfd_xf->eYX = mxTmp.efM21.lEfToF();
  740. *(LONG *)&pfd_xf->eYY = mxTmp.efM22.lEfToF();
  741. }
  742. else
  743. {
  744. *(LONG *)&pfd_xf->eXX = pmx->efM11.lEfToF();
  745. *(LONG *)&pfd_xf->eXY = pmx->efM12.lEfToF();
  746. *(LONG *)&pfd_xf->eYX = pmx->efM21.lEfToF();
  747. *(LONG *)&pfd_xf->eYY = pmx->efM22.lEfToF();
  748. }
  749. return;
  750. }
  751. /******************************Member*Function*****************************\
  752. * EXFORMOBJ::vOrder(RECTL &rcl)
  753. *
  754. * Order a rectangle based on the given transform. The rectangle will be
  755. * well ordered after the transform is applied. Note that the off-diagonal
  756. * elements of the transform MUST be zero's. ie. only scaling is allowed.
  757. *
  758. * History:
  759. * 18-Dec-1990 -by- Wendy Wu [wendywu]
  760. * Wrote it.
  761. \**************************************************************************/
  762. VOID EXFORMOBJ::vOrder(RECTL &rcl)
  763. {
  764. LONG lTmp;
  765. ASSERTGDI(bScale(), "vOrder error: not scaling transform");
  766. if ((pmx->efM11.bIsNegative() && (rcl.left < rcl.right)) ||
  767. (!pmx->efM11.bIsNegative() && (rcl.left > rcl.right)))
  768. {
  769. SWAPL(rcl.left, rcl.right, lTmp);
  770. }
  771. if ((pmx->efM22.bIsNegative() && (rcl.top < rcl.bottom)) ||
  772. (!pmx->efM22.bIsNegative() && (rcl.top > rcl.bottom)))
  773. {
  774. SWAPL(rcl.top, rcl.bottom, lTmp);
  775. }
  776. }
  777. /******************************Member*Function*****************************\
  778. * bMultiply(PMATRIX pmxLeft, PMATRIX pmxRight) *
  779. * *
  780. * Multiply two matrices together. Put the results in the XFORMOBJ. *
  781. * The target matrix CANNOT be the same as either of the two src matrices. *
  782. * *
  783. * History: *
  784. * Fri 20-Mar-1992 13:54:28 -by- Charles Whitmer [chuckwh] *
  785. * Rewrote with new EFLOAT math operations. We should never do any *
  786. * operations like efA=efB*efC+efD! They generate intensely bad code. *
  787. * *
  788. * 19-Nov-1990 -by- Wendy Wu [wendywu] *
  789. * Wrote it. *
  790. \**************************************************************************/
  791. BOOL EXFORMOBJ::bMultiply(PMATRIX pmxLeft, PMATRIX pmxRight, FLONG fl)
  792. {
  793. MATRIX *pmxTemp = pmx;
  794. ASSERTGDI((pmx != pmxLeft), "bMultiply error: pmx == pmxLeft\n");
  795. ASSERTGDI((pmx != pmxRight), "bMultiply error: pmx == pmxRight\n");
  796. EFLOAT efA,efB;
  797. if (pmxLeft->efM12.bIsZero() && pmxLeft->efM21.bIsZero() &&
  798. pmxRight->efM12.bIsZero() && pmxRight->efM21.bIsZero())
  799. {
  800. pmxTemp->efM11.eqMul(pmxLeft->efM11,pmxRight->efM11);
  801. pmxTemp->efM22.eqMul(pmxLeft->efM22,pmxRight->efM22);
  802. pmxTemp->efM12.vSetToZero();
  803. pmxTemp->efM21.vSetToZero();
  804. }
  805. else
  806. {
  807. // calculate the first row of the results
  808. efA.eqMul(pmxLeft->efM11,pmxRight->efM11);
  809. efB.eqMul(pmxLeft->efM12,pmxRight->efM21);
  810. pmxTemp->efM11.eqAdd(efA,efB);
  811. efA.eqMul(pmxLeft->efM11,pmxRight->efM12);
  812. efB.eqMul(pmxLeft->efM12,pmxRight->efM22);
  813. pmxTemp->efM12.eqAdd(efA,efB);
  814. // calculate the second row of the results
  815. efA.eqMul(pmxLeft->efM21,pmxRight->efM11);
  816. efB.eqMul(pmxLeft->efM22,pmxRight->efM21);
  817. pmxTemp->efM21.eqAdd(efA,efB);
  818. efA.eqMul(pmxLeft->efM21,pmxRight->efM12);
  819. efB.eqMul(pmxLeft->efM22,pmxRight->efM22);
  820. pmxTemp->efM22.eqAdd(efA,efB);
  821. }
  822. // calculate the translation
  823. if (pmxLeft->efDx.bIsZero() && pmxLeft->efDy.bIsZero())
  824. {
  825. pmxTemp->efDx = pmxRight->efDx;
  826. pmxTemp->efDy = pmxRight->efDy;
  827. pmxTemp->fxDx = pmxRight->fxDx;
  828. pmxTemp->fxDy = pmxRight->fxDy;
  829. }
  830. else
  831. {
  832. efA.eqMul(pmxLeft->efDx,pmxRight->efM11);
  833. efB.eqMul(pmxLeft->efDy,pmxRight->efM21);
  834. efB.eqAdd(efB,pmxRight->efDx);
  835. pmxTemp->efDx.eqAdd(efA,efB);
  836. efA.eqMul(pmxLeft->efDx,pmxRight->efM12);
  837. efB.eqMul(pmxLeft->efDy,pmxRight->efM22);
  838. efB.eqAdd(efB,pmxRight->efDy);
  839. pmxTemp->efDy.eqAdd(efA,efB);
  840. if (!pmxTemp->efDx.bEfToL(pmxTemp->fxDx))
  841. return(FALSE);
  842. if (!pmxTemp->efDy.bEfToL(pmxTemp->fxDy))
  843. return(FALSE);
  844. }
  845. if (fl & COMPUTE_FLAGS)
  846. vComputeAccelFlags(fl & XFORM_FORMAT);
  847. return(TRUE);
  848. }
  849. /******************************Member*Function*****************************\
  850. * EXFORMOBJ::bInverse(MATRIX& mxSrc) *
  851. * *
  852. * Calculate the inverse of a given matrix. *
  853. * *
  854. * The inverse is calculated as follows: *
  855. * *
  856. * If x' = D + xM then x = (-DM') + x'M' where M'M = 1. *
  857. * *
  858. * M'11 = M22/det, M'12 = -M12/det, M'21 = -M21/det, M'22 = M11/det, *
  859. * where det = M11*M22 - M12*M21 *
  860. * *
  861. * History: *
  862. * Fri 20-Mar-1992 13:54:28 -by- Charles Whitmer [chuckwh] *
  863. * Rewrote with new EFLOAT math operations. We should never do any *
  864. * operations like efA=efB*efC+efD! They generate intensely bad code. *
  865. * *
  866. * 19-Nov-1990 -by- Wendy Wu [wendywu] *
  867. * Wrote it. *
  868. \**************************************************************************/
  869. BOOL EXFORMOBJ::bInverse(MATRIX& mxSrc)
  870. {
  871. MATRIX *pmxTemp = pmx;
  872. ASSERTGDI((&mxSrc != pmx), "bInverse src, dest same matrix\n");
  873. ASSERTGDI((mxSrc.flAccel & XFORM_FORMAT_LTOFX), "bInverse: wrong xform format\n");
  874. // The accelerators of the destination matrix always equal to the
  875. // accelerators of the source matrix.
  876. pmxTemp->flAccel = (mxSrc.flAccel & ~XFORM_FORMAT_LTOFX) | XFORM_FORMAT_FXTOL;
  877. if (mxSrc.flAccel & XFORM_UNITY)
  878. {
  879. vSetTo1Over16(pmxTemp->efM11);
  880. vSetTo1Over16(pmxTemp->efM22);
  881. pmxTemp->efM12.vSetToZero();
  882. pmxTemp->efM21.vSetToZero();
  883. pmxTemp->efDx = mxSrc.efDx;
  884. pmxTemp->efDy = mxSrc.efDy;
  885. pmxTemp->efDx.vNegate();
  886. pmxTemp->efDy.vNegate();
  887. pmxTemp->efDx.vDivBy16();
  888. pmxTemp->efDy.vDivBy16();
  889. pmxTemp->fxDx = -FXTOL(mxSrc.fxDx);
  890. pmxTemp->fxDy = -FXTOL(mxSrc.fxDy);
  891. return(TRUE);
  892. }
  893. // calculate the determinant
  894. EFLOAT efDet;
  895. EFLOAT efA,efB;
  896. efA.eqMul(mxSrc.efM11,mxSrc.efM22);
  897. efB.eqMul(mxSrc.efM12,mxSrc.efM21);
  898. efDet.eqSub(efA,efB);
  899. // if determinant = 0, return false
  900. if (efDet.bIsZero())
  901. return(FALSE);
  902. if (mxSrc.flAccel & XFORM_SCALE)
  903. {
  904. pmxTemp->efM12.vSetToZero();
  905. pmxTemp->efM21.vSetToZero();
  906. }
  907. else
  908. {
  909. pmxTemp->efM12.eqDiv(mxSrc.efM12,efDet);
  910. pmxTemp->efM12.vNegate();
  911. pmxTemp->efM21.eqDiv(mxSrc.efM21,efDet);
  912. pmxTemp->efM21.vNegate();
  913. }
  914. pmxTemp->efM11.eqDiv(mxSrc.efM22,efDet);
  915. pmxTemp->efM22.eqDiv(mxSrc.efM11,efDet);
  916. // calculate the offset
  917. if (mxSrc.flAccel & XFORM_NO_TRANSLATION)
  918. {
  919. pmxTemp->efDx.vSetToZero();
  920. pmxTemp->efDy.vSetToZero();
  921. pmxTemp->fxDx = 0;
  922. pmxTemp->fxDy = 0;
  923. return(TRUE);
  924. }
  925. if (mxSrc.flAccel & XFORM_SCALE)
  926. {
  927. pmxTemp->efDx.eqMul(mxSrc.efDx,pmxTemp->efM11);
  928. pmxTemp->efDy.eqMul(mxSrc.efDy,pmxTemp->efM22);
  929. }
  930. else
  931. {
  932. efA.eqMul(mxSrc.efDx,pmxTemp->efM11);
  933. efB.eqMul(mxSrc.efDy,pmxTemp->efM21);
  934. pmxTemp->efDx.eqAdd(efA,efB);
  935. efA.eqMul(mxSrc.efDx,pmxTemp->efM12);
  936. efB.eqMul(mxSrc.efDy,pmxTemp->efM22);
  937. pmxTemp->efDy.eqAdd(efA,efB);
  938. }
  939. pmxTemp->efDx.vNegate();
  940. pmxTemp->efDy.vNegate();
  941. // Return FALSE if translations can't fit in LONG type.
  942. if (!pmxTemp->efDx.bEfToL(pmxTemp->fxDx))
  943. return(FALSE);
  944. if (!pmxTemp->efDy.bEfToL(pmxTemp->fxDy))
  945. return(FALSE);
  946. return(TRUE);
  947. }
  948. /******************************Public*Routine******************************\
  949. * bComputeUnits (lAngle,ppte,pefWD,pefDW) *
  950. * *
  951. * Given an angle in 1/10ths of a degree in logical coordinates, we *
  952. * transform a vector at that angle into device coordinates. We normalize *
  953. * the result into a unit vector and a scaling. *
  954. * *
  955. * Knowing the unit vector and scaling allows us to quickly calculate the *
  956. * transform of any vector parallel to the angle. *
  957. * *
  958. * Sun 15-Mar-1992 05:26:57 -by- Charles Whitmer [chuckwh] *
  959. * Wrote it. *
  960. \**************************************************************************/
  961. BOOL EXFORMOBJ::bComputeUnits
  962. (
  963. LONG lAngle, // Angle in tenths of a degree.
  964. POINTFL *ppte, // Unit vector in Device Coordinates.
  965. EFLOAT *pefWD, // World to Device multiplier.
  966. EFLOAT *pefDW // (Optional) Device to World multiplier.
  967. )
  968. {
  969. EVECTORFL vt;
  970. EFLOAT efA;
  971. EFLOAT efB;
  972. BOOL bNegate = FALSE;
  973. // Get rid of negative angles. (Modulo is unreliable on negatives.)
  974. if (lAngle < 0)
  975. {
  976. lAngle = -lAngle;
  977. bNegate = TRUE;
  978. }
  979. // Handle simple cases separately for greater accuracy.
  980. if (bScale() && (lAngle % 900 == 0))
  981. {
  982. lAngle /= 900;
  983. if (lAngle & 1)
  984. {
  985. vt.x = (LONG) 0;
  986. vt.y = (LONG) 1;
  987. efA = efM22();
  988. }
  989. else
  990. {
  991. vt.x = (LONG) 1;
  992. vt.y = (LONG) 0;
  993. efA = efM11();
  994. }
  995. if (efA.bIsZero())
  996. return(FALSE);
  997. if (lAngle & 2)
  998. efA.vNegate();
  999. if (efA.bIsNegative())
  1000. {
  1001. vt.x.vNegate();
  1002. vt.y.vNegate();
  1003. efA.vNegate();
  1004. }
  1005. }
  1006. else
  1007. {
  1008. // Get the angle.
  1009. EFLOATEXT efAngle = lAngle;
  1010. efAngle /= (LONG) 10;
  1011. // Make a unit vector at that angle.
  1012. vt.x = efCos(efAngle);
  1013. vt.y = efSin(efAngle);
  1014. // Transform it to device coordinates.
  1015. if (!bXform(vt))
  1016. return(FALSE);
  1017. // Determine its length.
  1018. efA.eqLength(*(POINTFL *) &vt);
  1019. if (efA.bIsZero())
  1020. return(FALSE);
  1021. // Make a unit vector.
  1022. vt.x /= efA;
  1023. vt.y /= efA;
  1024. efA.vTimes16();
  1025. }
  1026. // Copy the results out.
  1027. if (bNegate)
  1028. vt.y.vNegate();
  1029. *ppte = vt;
  1030. *pefWD = efA;
  1031. if (pefDW != (EFLOAT *) NULL)
  1032. {
  1033. // Calculate the inverse.
  1034. efB = (LONG) 1;
  1035. efB /= efA;
  1036. *pefDW = efB;
  1037. }
  1038. return(TRUE);
  1039. }