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