02216a5859191cb323c914a13176a7cd877c396f
[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 * 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 */