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