1 /* 2 * PROJECT: ReactOS win32 kernel mode subsystem 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: win32ss/gdi/ntgdi/xformobj.c 5 * PURPOSE: XFORMOBJ API 6 * PROGRAMMERS: Timo Kreuzer 7 * Katayama Hirofumi MZ 8 */ 9 10 /** Includes ******************************************************************/ 11 12 #include <win32k.h> 13 #define NDEBUG 14 #include <debug.h> 15 16 #define DOES_VALUE_OVERFLOW_LONG(x) \ 17 (((__int64)((long)(x))) != (x)) 18 19 /** Inline helper functions ***************************************************/ 20 21 /* 22 * Inline helper to calculate pfo1 * pfo2 + pfo3 * pfo4 23 */ 24 FORCEINLINE 25 VOID 26 MulAdd( 27 PFLOATOBJ pfoDest, 28 PFLOATOBJ pfo1, 29 PFLOATOBJ pfo2, 30 PFLOATOBJ pfo3, 31 PFLOATOBJ pfo4) 32 { 33 FLOATOBJ foTmp; 34 35 *pfoDest = *pfo1; 36 FLOATOBJ_Mul(pfoDest, pfo2); 37 foTmp = *pfo3; 38 FLOATOBJ_Mul(&foTmp, pfo4); 39 FLOATOBJ_Add(pfoDest, &foTmp); 40 } 41 42 /* 43 * Inline helper to calculate pfo1 * l2 + pfo3 * l4 44 */ 45 FORCEINLINE 46 VOID 47 MulAddLong( 48 PFLOATOBJ pfoDest, 49 PFLOATOBJ pfo1, 50 LONG l2, 51 PFLOATOBJ pfo3, 52 LONG l4) 53 { 54 FLOATOBJ foTmp; 55 56 *pfoDest = *pfo1; 57 FLOATOBJ_MulLong(pfoDest, l2); 58 foTmp = *pfo3; 59 FLOATOBJ_MulLong(&foTmp, l4); 60 FLOATOBJ_Add(pfoDest, &foTmp); 61 } 62 63 /* 64 * Inline helper to calculate pfo1 * pfo2 - pfo3 * pfo4 65 */ 66 FORCEINLINE 67 VOID 68 MulSub( 69 PFLOATOBJ pfoDest, 70 PFLOATOBJ pfo1, 71 PFLOATOBJ pfo2, 72 PFLOATOBJ pfo3, 73 PFLOATOBJ pfo4) 74 { 75 FLOATOBJ foTmp; 76 77 *pfoDest = *pfo1; 78 FLOATOBJ_Mul(pfoDest, pfo2); 79 foTmp = *pfo3; 80 FLOATOBJ_Mul(&foTmp, pfo4); 81 FLOATOBJ_Sub(pfoDest, &foTmp); 82 } 83 84 /* 85 * Inline helper to get the complexity hint from flAccel 86 */ 87 FORCEINLINE 88 ULONG 89 HintFromAccel(ULONG flAccel) 90 { 91 switch (flAccel & (XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION)) 92 { 93 case (XFORM_SCALE|XFORM_UNITY|XFORM_NO_TRANSLATION): 94 return GX_IDENTITY; 95 case (XFORM_SCALE|XFORM_UNITY): 96 return GX_OFFSET; 97 case XFORM_SCALE: 98 return GX_SCALE; 99 default: 100 return GX_GENERAL; 101 } 102 } 103 104 /** Internal functions ********************************************************/ 105 106 ULONG 107 FASTCALL 108 MX_UpdateAccel(IN OUT PMATRIX pmx) 109 { 110 /* Copy Dx and Dy to FIX format */ 111 pmx->fxDx = FLOATOBJ_GetFix(&pmx->efDx); 112 pmx->fxDy = FLOATOBJ_GetFix(&pmx->efDy); 113 114 pmx->flAccel = 0; 115 116 if (FLOATOBJ_Equal0(&pmx->efDx) && 117 FLOATOBJ_Equal0(&pmx->efDy)) 118 { 119 pmx->flAccel |= XFORM_NO_TRANSLATION; 120 } 121 122 if (FLOATOBJ_Equal0(&pmx->efM12) && 123 FLOATOBJ_Equal0(&pmx->efM21)) 124 { 125 pmx->flAccel |= XFORM_SCALE; 126 } 127 128 if (FLOATOBJ_Equal1(&pmx->efM11) && 129 FLOATOBJ_Equal1(&pmx->efM22)) 130 { 131 pmx->flAccel |= XFORM_UNITY; 132 } 133 134 if (FLOATOBJ_IsLong(&pmx->efM11) && FLOATOBJ_IsLong(&pmx->efM12) && 135 FLOATOBJ_IsLong(&pmx->efM21) && FLOATOBJ_IsLong(&pmx->efM22)) 136 { 137 pmx->flAccel |= XFORM_INTEGER; 138 } 139 140 return HintFromAccel(pmx->flAccel); 141 } 142 143 ULONG 144 NTAPI 145 XFORMOBJ_UpdateAccel( 146 IN OUT XFORMOBJ *pxo) 147 { 148 PMATRIX pmx = XFORMOBJ_pmx(pxo); 149 150 return MX_UpdateAccel(pmx); 151 } 152 153 154 ULONG 155 NTAPI 156 XFORMOBJ_iSetXform( 157 IN OUT XFORMOBJ *pxo, 158 IN const XFORML *pxform) 159 { 160 PMATRIX pmx; 161 MATRIX mxTemp; 162 ULONG Hint; 163 164 /* Check parameters */ 165 if (!pxo || !pxform) return DDI_ERROR; 166 167 /* Copy members */ 168 FLOATOBJ_SetFloat(&mxTemp.efM11, pxform->eM11); 169 FLOATOBJ_SetFloat(&mxTemp.efM12, pxform->eM12); 170 FLOATOBJ_SetFloat(&mxTemp.efM21, pxform->eM21); 171 FLOATOBJ_SetFloat(&mxTemp.efM22, pxform->eM22); 172 FLOATOBJ_SetFloat(&mxTemp.efDx, pxform->eDx); 173 FLOATOBJ_SetFloat(&mxTemp.efDy, pxform->eDy); 174 175 /* Update accelerators and return complexity */ 176 Hint = MX_UpdateAccel(&mxTemp); 177 178 /* Check whether det = (M11 * M22 - M12 * M21) is non-zero */ 179 if (Hint == GX_SCALE) 180 { 181 if (FLOATOBJ_Equal0(&mxTemp.efM11) || FLOATOBJ_Equal0(&mxTemp.efM22)) 182 { 183 return DDI_ERROR; 184 } 185 } 186 else if (Hint == GX_GENERAL) 187 { 188 if (!MX_IsInvertible(&mxTemp)) 189 { 190 return DDI_ERROR; 191 } 192 } 193 194 /* Store */ 195 pmx = XFORMOBJ_pmx(pxo); 196 *pmx = mxTemp; 197 198 return Hint; 199 } 200 201 202 /* 203 * Multiplies pxo1 with pxo2 and stores the result in pxo. 204 * returns complexity hint 205 * | efM11 efM12 0 | 206 * | efM21 efM22 0 | 207 * | efDx efDy 1 | 208 */ 209 ULONG 210 NTAPI 211 XFORMOBJ_iCombine( 212 IN OUT XFORMOBJ *pxo, 213 IN XFORMOBJ *pxo1, 214 IN XFORMOBJ *pxo2) 215 { 216 MATRIX mx; 217 PMATRIX pmx, pmx1, pmx2; 218 219 /* Get the source matrices */ 220 pmx1 = XFORMOBJ_pmx(pxo1); 221 pmx2 = XFORMOBJ_pmx(pxo2); 222 223 /* Do a 3 x 3 matrix multiplication with mx as destinantion */ 224 MulAdd(&mx.efM11, &pmx1->efM11, &pmx2->efM11, &pmx1->efM12, &pmx2->efM21); 225 MulAdd(&mx.efM12, &pmx1->efM11, &pmx2->efM12, &pmx1->efM12, &pmx2->efM22); 226 MulAdd(&mx.efM21, &pmx1->efM21, &pmx2->efM11, &pmx1->efM22, &pmx2->efM21); 227 MulAdd(&mx.efM22, &pmx1->efM21, &pmx2->efM12, &pmx1->efM22, &pmx2->efM22); 228 MulAdd(&mx.efDx, &pmx1->efDx, &pmx2->efM11, &pmx1->efDy, &pmx2->efM21); 229 FLOATOBJ_Add(&mx.efDx, &pmx2->efDx); 230 MulAdd(&mx.efDy, &pmx1->efDx, &pmx2->efM12, &pmx1->efDy, &pmx2->efM22); 231 FLOATOBJ_Add(&mx.efDy, &pmx2->efDy); 232 233 /* Copy back */ 234 pmx = XFORMOBJ_pmx(pxo); 235 *pmx = mx; 236 237 /* Update accelerators and return complexity */ 238 return XFORMOBJ_UpdateAccel(pxo); 239 } 240 241 242 ULONG 243 NTAPI 244 XFORMOBJ_iCombineXform( 245 IN OUT XFORMOBJ *pxo, 246 IN XFORMOBJ *pxo1, 247 IN XFORML *pxform, 248 IN BOOL bLeftMultiply) 249 { 250 MATRIX mx; 251 XFORMOBJ xo2; 252 253 XFORMOBJ_vInit(&xo2, &mx); 254 XFORMOBJ_iSetXform(&xo2, pxform); 255 256 if (bLeftMultiply) 257 { 258 return XFORMOBJ_iCombine(pxo, &xo2, pxo1); 259 } 260 else 261 { 262 return XFORMOBJ_iCombine(pxo, pxo1, &xo2); 263 } 264 } 265 266 BOOL FASTCALL 267 MX_IsInvertible(IN PMATRIX pmx) 268 { 269 FLOATOBJ foDet; 270 MulSub(&foDet, &pmx->efM11, &pmx->efM22, &pmx->efM12, &pmx->efM21); 271 return !FLOATOBJ_Equal0(&foDet); 272 } 273 274 VOID FASTCALL 275 MX_Set0(OUT PMATRIX pmx) 276 { 277 FLOATOBJ_Set0(&pmx->efM11); 278 FLOATOBJ_Set0(&pmx->efM12); 279 FLOATOBJ_Set0(&pmx->efM21); 280 FLOATOBJ_Set0(&pmx->efM22); 281 FLOATOBJ_Set0(&pmx->efDx); 282 FLOATOBJ_Set0(&pmx->efDy); 283 } 284 285 /* 286 * A^-1 = adj(A) / det(AT) 287 * A^-1 = 1/(a*d - b*c) * (a22,-a12,a21,-a11) 288 */ 289 ULONG 290 NTAPI 291 XFORMOBJ_iInverse( 292 OUT XFORMOBJ *pxoDst, 293 IN XFORMOBJ *pxoSrc) 294 { 295 PMATRIX pmxDst, pmxSrc; 296 FLOATOBJ foDet; 297 XFORM xformSrc; 298 299 pmxDst = XFORMOBJ_pmx(pxoDst); 300 pmxSrc = XFORMOBJ_pmx(pxoSrc); 301 302 XFORMOBJ_iGetXform(pxoSrc, (XFORML*)&xformSrc); 303 304 /* det = M11 * M22 - M12 * M21 */ 305 MulSub(&foDet, &pmxSrc->efM11, &pmxSrc->efM22, &pmxSrc->efM12, &pmxSrc->efM21); 306 307 if (FLOATOBJ_Equal0(&foDet)) 308 { 309 /* Determinant is 0! */ 310 return DDI_ERROR; 311 } 312 313 /* Calculate adj(A) / det(A) */ 314 pmxDst->efM11 = pmxSrc->efM22; 315 FLOATOBJ_Div(&pmxDst->efM11, &foDet); 316 pmxDst->efM22 = pmxSrc->efM11; 317 FLOATOBJ_Div(&pmxDst->efM22, &foDet); 318 319 /* The other 2 are negative, negate foDet for that */ 320 FLOATOBJ_Neg(&foDet); 321 pmxDst->efM12 = pmxSrc->efM12; 322 FLOATOBJ_Div(&pmxDst->efM12, &foDet); 323 pmxDst->efM21 = pmxSrc->efM21; 324 FLOATOBJ_Div(&pmxDst->efM21, &foDet); 325 326 /* Calculate the inverted x shift: Dx' = -Dx * M11' - Dy * M21' */ 327 pmxDst->efDx = pmxSrc->efDx; 328 FLOATOBJ_Neg(&pmxDst->efDx); 329 MulSub(&pmxDst->efDx, &pmxDst->efDx, &pmxDst->efM11, &pmxSrc->efDy, &pmxDst->efM21); 330 331 /* Calculate the inverted y shift: Dy' = -Dy * M22' - Dx * M12' */ 332 pmxDst->efDy = pmxSrc->efDy; 333 FLOATOBJ_Neg(&pmxDst->efDy); 334 MulSub(&pmxDst->efDy, &pmxDst->efDy, &pmxDst->efM22, &pmxSrc->efDx, &pmxDst->efM12); 335 336 /* Update accelerators and return complexity */ 337 return XFORMOBJ_UpdateAccel(pxoDst); 338 } 339 340 341 /*! 342 * \brief Transforms fix-point coordinates in an array of POINTL structures using 343 * the transformation matrix from the XFORMOBJ. 344 * 345 * \param pxo - Pointer to the XFORMOBJ 346 * 347 * \param cPoints - Number of coordinates to transform 348 * 349 * \param pptIn - Pointer to an array of POINTL structures containing the 350 * source coordinates. 351 * 352 * \param pptOut - Pointer to an array of POINTL structures, receiving the 353 * transformed coordinates. Can be the same as pptIn. 354 * 355 * \return TRUE if the operation was successful, FALSE if any of the calculations 356 * caused an integer overflow. 357 * 358 * \note If the function returns FALSE, it might still have written to the 359 * output buffer. If pptIn and pptOut are equal, the source coordinates 360 * might have been partly overwritten! 361 */ 362 static 363 BOOL 364 NTAPI 365 XFORMOBJ_bXformFixPoints( 366 _In_ XFORMOBJ *pxo, 367 _In_ ULONG cPoints, 368 _In_reads_(cPoints) PPOINTL pptIn, 369 _Out_writes_(cPoints) PPOINTL pptOut) 370 { 371 PMATRIX pmx; 372 INT i; 373 FLOATOBJ fo1, fo2; 374 FLONG flAccel; 375 LONG lM11, lM12, lM21, lM22, lTemp; 376 register LONGLONG llx, lly; 377 378 pmx = XFORMOBJ_pmx(pxo); 379 flAccel = pmx->flAccel; 380 381 if ((flAccel & (XFORM_SCALE|XFORM_UNITY)) == (XFORM_SCALE|XFORM_UNITY)) 382 { 383 /* Identity transformation */ 384 RtlCopyMemory(pptOut, pptIn, cPoints * sizeof(POINTL)); 385 } 386 else if (flAccel & XFORM_INTEGER) 387 { 388 if (flAccel & XFORM_UNITY) 389 { 390 /* 1-scale integer transform, get the off-diagonal elements */ 391 if (!FLOATOBJ_bConvertToLong(&pmx->efM12, &lM12) || 392 !FLOATOBJ_bConvertToLong(&pmx->efM21, &lM21)) 393 { 394 NT_ASSERT(FALSE); 395 return FALSE; 396 } 397 398 i = cPoints - 1; 399 do 400 { 401 /* Calculate x in 64 bit and check for overflow */ 402 llx = Int32x32To64(pptIn[i].y, lM21) + pptIn[i].x; 403 if (DOES_VALUE_OVERFLOW_LONG(llx)) 404 { 405 return FALSE; 406 } 407 408 /* Calculate y in 64 bit and check for overflow */ 409 lly = Int32x32To64(pptIn[i].x, lM12) + pptIn[i].y; 410 if (DOES_VALUE_OVERFLOW_LONG(lly)) 411 { 412 return FALSE; 413 } 414 415 /* Write back the results */ 416 pptOut[i].x = (LONG)llx; 417 pptOut[i].y = (LONG)lly; 418 } 419 while (--i >= 0); 420 } 421 else if (flAccel & XFORM_SCALE) 422 { 423 /* Diagonal integer transform, get the diagonal elements */ 424 if (!FLOATOBJ_bConvertToLong(&pmx->efM11, &lM11) || 425 !FLOATOBJ_bConvertToLong(&pmx->efM22, &lM22)) 426 { 427 NT_ASSERT(FALSE); 428 return FALSE; 429 } 430 431 i = cPoints - 1; 432 do 433 { 434 /* Calculate x in 64 bit and check for overflow */ 435 llx = Int32x32To64(pptIn[i].x, lM11); 436 if (DOES_VALUE_OVERFLOW_LONG(llx)) 437 { 438 return FALSE; 439 } 440 441 /* Calculate y in 64 bit and check for overflow */ 442 lly = Int32x32To64(pptIn[i].y, lM22); 443 if (DOES_VALUE_OVERFLOW_LONG(lly)) 444 { 445 return FALSE; 446 } 447 448 /* Write back the results */ 449 pptOut[i].x = (LONG)llx; 450 pptOut[i].y = (LONG)lly; 451 } 452 while (--i >= 0); 453 } 454 else 455 { 456 /* Full integer transform */ 457 if (!FLOATOBJ_bConvertToLong(&pmx->efM11, &lM11) || 458 !FLOATOBJ_bConvertToLong(&pmx->efM12, &lM12) || 459 !FLOATOBJ_bConvertToLong(&pmx->efM21, &lM21) || 460 !FLOATOBJ_bConvertToLong(&pmx->efM22, &lM22)) 461 { 462 NT_ASSERT(FALSE); 463 return FALSE; 464 } 465 466 i = cPoints - 1; 467 do 468 { 469 /* Calculate x in 64 bit and check for overflow */ 470 llx = Int32x32To64(pptIn[i].x, lM11); 471 llx += Int32x32To64(pptIn[i].y, lM21); 472 if (DOES_VALUE_OVERFLOW_LONG(llx)) 473 { 474 return FALSE; 475 } 476 477 /* Calculate y in 64 bit and check for overflow */ 478 lly = Int32x32To64(pptIn[i].y, lM22); 479 lly += Int32x32To64(pptIn[i].x, lM12); 480 if (DOES_VALUE_OVERFLOW_LONG(lly)) 481 { 482 return FALSE; 483 } 484 485 /* Write back the results */ 486 pptOut[i].x = (LONG)llx; 487 pptOut[i].y = (LONG)lly; 488 } 489 while (--i >= 0); 490 } 491 } 492 else if (flAccel & XFORM_UNITY) 493 { 494 /* 1-scale transform */ 495 i = cPoints - 1; 496 do 497 { 498 /* Calculate x in 64 bit and check for overflow */ 499 fo1 = pmx->efM21; 500 FLOATOBJ_MulLong(&fo1, pptIn[i].y); 501 if (!FLOATOBJ_bConvertToLong(&fo1, &lTemp)) 502 { 503 return FALSE; 504 } 505 llx = (LONGLONG)pptIn[i].x + lTemp; 506 if (DOES_VALUE_OVERFLOW_LONG(llx)) 507 { 508 return FALSE; 509 } 510 511 /* Calculate y in 64 bit and check for overflow */ 512 fo2 = pmx->efM12; 513 FLOATOBJ_MulLong(&fo2, pptIn[i].x); 514 if (!FLOATOBJ_bConvertToLong(&fo2, &lTemp)) 515 { 516 return FALSE; 517 } 518 lly = (LONGLONG)pptIn[i].y + lTemp; 519 if (DOES_VALUE_OVERFLOW_LONG(lly)) 520 { 521 return FALSE; 522 } 523 524 /* Write back the results */ 525 pptOut[i].x = (LONG)llx; 526 pptOut[i].y = (LONG)lly; 527 } 528 while (--i >= 0); 529 } 530 else if (flAccel & XFORM_SCALE) 531 { 532 /* Diagonal float transform */ 533 i = cPoints - 1; 534 do 535 { 536 fo1 = pmx->efM11; 537 FLOATOBJ_MulLong(&fo1, pptIn[i].x); 538 if (!FLOATOBJ_bConvertToLong(&fo1, &pptOut[i].x)) 539 { 540 return FALSE; 541 } 542 543 fo2 = pmx->efM22; 544 FLOATOBJ_MulLong(&fo2, pptIn[i].y); 545 if (!FLOATOBJ_bConvertToLong(&fo2, &pptOut[i].y)) 546 { 547 return FALSE; 548 } 549 } 550 while (--i >= 0); 551 } 552 else 553 { 554 /* Full float transform */ 555 i = cPoints - 1; 556 do 557 { 558 /* Calculate x as FLOATOBJ */ 559 MulAddLong(&fo1, &pmx->efM11, pptIn[i].x, &pmx->efM21, pptIn[i].y); 560 561 /* Calculate y as FLOATOBJ */ 562 MulAddLong(&fo2, &pmx->efM12, pptIn[i].x, &pmx->efM22, pptIn[i].y); 563 564 if (!FLOATOBJ_bConvertToLong(&fo1, &pptOut[i].x)) 565 { 566 return FALSE; 567 } 568 569 if (!FLOATOBJ_bConvertToLong(&fo2, &pptOut[i].y)) 570 { 571 return FALSE; 572 } 573 } 574 while (--i >= 0); 575 } 576 577 if (!(pmx->flAccel & XFORM_NO_TRANSLATION)) 578 { 579 /* Translate points */ 580 i = cPoints - 1; 581 do 582 { 583 llx = (LONGLONG)pptOut[i].x + pmx->fxDx; 584 if (DOES_VALUE_OVERFLOW_LONG(llx)) 585 { 586 return FALSE; 587 } 588 pptOut[i].x = (LONG)llx; 589 590 lly = (LONGLONG)pptOut[i].y + pmx->fxDy; 591 if (DOES_VALUE_OVERFLOW_LONG(lly)) 592 { 593 return FALSE; 594 } 595 pptOut[i].y = (LONG)lly; 596 } 597 while (--i >= 0); 598 } 599 600 return TRUE; 601 } 602 603 /** Public functions **********************************************************/ 604 605 // www.osr.com/ddk/graphics/gdifncs_0s2v.htm 606 ULONG 607 APIENTRY 608 XFORMOBJ_iGetXform( 609 IN XFORMOBJ *pxo, 610 OUT XFORML *pxform) 611 { 612 PMATRIX pmx = XFORMOBJ_pmx(pxo); 613 614 /* Check parameters */ 615 if (!pxo || !pxform) 616 { 617 return DDI_ERROR; 618 } 619 620 /* Copy members */ 621 pxform->eM11 = FLOATOBJ_GetFloat(&pmx->efM11); 622 pxform->eM12 = FLOATOBJ_GetFloat(&pmx->efM12); 623 pxform->eM21 = FLOATOBJ_GetFloat(&pmx->efM21); 624 pxform->eM22 = FLOATOBJ_GetFloat(&pmx->efM22); 625 pxform->eDx = FLOATOBJ_GetFloat(&pmx->efDx); 626 pxform->eDy = FLOATOBJ_GetFloat(&pmx->efDy); 627 628 /* Return complexity hint */ 629 return HintFromAccel(pmx->flAccel); 630 } 631 632 633 // www.osr.com/ddk/graphics/gdifncs_5ig7.htm 634 ULONG 635 APIENTRY 636 XFORMOBJ_iGetFloatObjXform( 637 IN XFORMOBJ *pxo, 638 OUT FLOATOBJ_XFORM *pxfo) 639 { 640 PMATRIX pmx = XFORMOBJ_pmx(pxo); 641 642 /* Check parameters */ 643 if (!pxo || !pxfo) 644 { 645 return DDI_ERROR; 646 } 647 648 /* Copy members */ 649 pxfo->eM11 = pmx->efM11; 650 pxfo->eM12 = pmx->efM12; 651 pxfo->eM21 = pmx->efM21; 652 pxfo->eM22 = pmx->efM22; 653 pxfo->eDx = pmx->efDx; 654 pxfo->eDy = pmx->efDy; 655 656 /* Return complexity hint */ 657 return HintFromAccel(pmx->flAccel); 658 } 659 660 661 // www.osr.com/ddk/graphics/gdifncs_027b.htm 662 BOOL 663 APIENTRY 664 XFORMOBJ_bApplyXform( 665 IN XFORMOBJ *pxo, 666 IN ULONG iMode, 667 IN ULONG cPoints, 668 IN PVOID pvIn, 669 OUT PVOID pvOut) 670 { 671 MATRIX mx; 672 XFORMOBJ xoInv; 673 PPOINTL pptlIn, pptlOut; 674 INT i; 675 676 /* Check parameters */ 677 if (!pxo || !pvIn || !pvOut || cPoints < 1) 678 { 679 return FALSE; 680 } 681 682 /* Use inverse xform? */ 683 if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL) 684 { 685 XFORMOBJ_vInit(&xoInv, &mx); 686 if (XFORMOBJ_iInverse(&xoInv, pxo) == DDI_ERROR) 687 { 688 return FALSE; 689 } 690 pxo = &xoInv; 691 } 692 693 /* Convert POINTL to POINTFIX? */ 694 if (iMode == XF_LTOFX || iMode == XF_LTOL || iMode == XF_INV_LTOL) 695 { 696 pptlIn = pvIn; 697 pptlOut = pvOut; 698 for (i = cPoints - 1; i >= 0; i--) 699 { 700 pptlOut[i].x = LONG2FIX(pptlIn[i].x); 701 pptlOut[i].y = LONG2FIX(pptlIn[i].y); 702 } 703 704 /* The input is in the out buffer now! */ 705 pvIn = pvOut; 706 } 707 708 /* Do the actual fixpoint transformation */ 709 if (!XFORMOBJ_bXformFixPoints(pxo, cPoints, pvIn, pvOut)) 710 { 711 return FALSE; 712 } 713 714 /* Convert POINTFIX to POINTL? */ 715 if (iMode == XF_INV_FXTOL || iMode == XF_INV_LTOL || iMode == XF_LTOL) 716 { 717 pptlOut = pvOut; 718 for (i = cPoints - 1; i >= 0; i--) 719 { 720 pptlOut[i].x = FIX2LONG(pptlOut[i].x); 721 pptlOut[i].y = FIX2LONG(pptlOut[i].y); 722 } 723 } 724 725 return TRUE; 726 } 727 728 /* EOF */ 729