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