2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS System Libraries
4 * FILE: win32ss/gdi/gdi32/objects/coord.c
5 * PURPOSE: Functions for coordinate transformation
10 /* Currently we use a MATRIX inside the DC_ATTR containing the
11 coordinate transformations, while we deal with XFORM structures
12 internally. If we move all coordinate transformation to gdi32,
13 we might as well have an XFORM structure in the DC_ATTR. */
15 MatrixToXForm(XFORM
*pxform
, const MATRIX
*pmx
)
17 XFORML
*pxforml
= (XFORML
*)pxform
;
18 pxforml
->eM11
= FOtoF(&pmx
->efM11
);
19 pxforml
->eM12
= FOtoF(&pmx
->efM12
);
20 pxforml
->eM21
= FOtoF(&pmx
->efM21
);
21 pxforml
->eM22
= FOtoF(&pmx
->efM22
);
22 pxforml
->eDx
= FOtoF(&pmx
->efDx
);
23 pxforml
->eDy
= FOtoF(&pmx
->efDy
);
29 _Out_writes_(nCount
) PPOINT pptOut
,
30 _In_reads_(nCount
) PPOINT pptIn
,
36 for (i
= 0; i
< nCount
; i
++)
38 x
= pptIn
[i
].x
* pxform
->eM11
+ pptIn
[i
].y
* pxform
->eM12
+ pxform
->eDx
;
39 pptOut
[i
].x
= _lrintf(x
);
40 y
= pptIn
[i
].x
* pxform
->eM21
+ pptIn
[i
].y
* pxform
->eM22
+ pxform
->eDy
;
41 pptOut
[i
].y
= _lrintf(y
);
49 _Out_writes_(nCount
) PPOINT pptOut
,
50 _In_reads_(nCount
) PPOINT pptIn
,
55 MatrixToXForm(&xform
, pmx
);
56 GdiTransformPoints2(&xform
, pptOut
, pptIn
, nCount
);
59 #define MAX_OFFSET 4294967041.0
60 #define _fmul(x,y) (((x) == 0) ? 0 : (x) * (y))
65 _Out_ LPXFORM pxfResult
,
66 _In_
const XFORM
*pxf1
,
67 _In_
const XFORM
*pxf2
)
72 if (!pxfResult
|| !pxf1
|| !pxf2
) return FALSE
;
74 /* Do matrix multiplication, start with scaling elements */
75 xformTmp
.eM11
= (pxf1
->eM11
* pxf2
->eM11
) + (pxf1
->eM12
* pxf2
->eM21
);
76 xformTmp
.eM22
= (pxf1
->eM21
* pxf2
->eM12
) + (pxf1
->eM22
* pxf2
->eM22
);
78 /* Calculate shear/rotate elements only of they are present */
79 if ((pxf1
->eM12
!= 0.) || (pxf1
->eM21
!= 0.) ||
80 (pxf2
->eM12
!= 0.) || (pxf2
->eM21
!= 0.))
82 xformTmp
.eM12
= (pxf1
->eM11
* pxf2
->eM12
) + (pxf1
->eM12
* pxf2
->eM22
);
83 xformTmp
.eM21
= (pxf1
->eM21
* pxf2
->eM11
) + (pxf1
->eM22
* pxf2
->eM21
);
91 /* Calculate the offset */
92 xformTmp
.eDx
= _fmul(pxf1
->eDx
, pxf2
->eM11
) + _fmul(pxf1
->eDy
, pxf2
->eM21
) + pxf2
->eDx
;
93 xformTmp
.eDy
= _fmul(pxf1
->eDx
, pxf2
->eM12
) + _fmul(pxf1
->eDy
, pxf2
->eM22
) + pxf2
->eDy
;
95 /* Check for invalid offset ranges */
96 if ((xformTmp
.eDx
> MAX_OFFSET
) || (xformTmp
.eDx
< -MAX_OFFSET
) ||
97 (xformTmp
.eDy
> MAX_OFFSET
) || (xformTmp
.eDy
< -MAX_OFFSET
))
102 /* All is ok, return the calculated values */
103 *pxfResult
= xformTmp
;
119 /* Get the DC attribute */
120 pdcattr
= GdiGetDcAttr(hdc
);
123 SetLastError(ERROR_INVALID_PARAMETER
);
127 /* Return the map mode */
128 return pdcattr
->iMapMode
;
142 /* Handle METADC16 here, since we don't have a DCATTR. */
143 if (GDI_HANDLE_GET_TYPE(hdc
) == GDILoObjType_LO_METADC16_TYPE
) \
145 return GetAndSetDCDWord(hdc
, GdiGetSetMapMode
, iMode
, 0, 0, 0 );
148 /* Get the DC attribute */
149 pdcattr
= GdiGetDcAttr(hdc
);
152 SetLastError(ERROR_INVALID_PARAMETER
);
156 /* Force change if Isotropic is set for recompute. */
157 if ((iMode
!= pdcattr
->iMapMode
) || (iMode
== MM_ISOTROPIC
))
159 pdcattr
->ulDirty_
&= ~SLOW_WIDTHS
;
160 return GetAndSetDCDWord(hdc
, GdiGetSetMapMode
, iMode
, 0, 0, 0 );
163 return pdcattr
->iMapMode
;
171 _Inout_updates_(nCount
) LPPOINT lpPoints
,
178 /* Get the DC attribute */
179 pdcattr
= GdiGetDcAttr(hdc
);
182 SetLastError(ERROR_INVALID_PARAMETER
);
186 if (pdcattr
->flXform
& ANY_XFORM_CHANGES
)
188 GdiFixupTransforms(pdcattr
);
191 // FIXME: can this fail on Windows?
192 GdiTransformPoints(&pdcattr
->mxDeviceToWorld
, lpPoints
, lpPoints
, nCount
);
196 return NtGdiTransformPoints(hdc
, lpPoints
, lpPoints
, nCount
, GdiDpToLp
);
203 _Inout_updates_(nCount
) LPPOINT lpPoints
,
210 /* Get the DC attribute */
211 pdcattr
= GdiGetDcAttr(hdc
);
214 SetLastError(ERROR_INVALID_PARAMETER
);
218 if (pdcattr
->flXform
& ANY_XFORM_CHANGES
)
220 GdiFixupTransforms(pdcattr
);
223 // FIXME: can this fail on Windows?
224 GdiTransformPoints(&pdcattr
->mxWorldToDevice
, lpPoints
, lpPoints
, nCount
);
228 return NtGdiTransformPoints(hdc
, lpPoints
, lpPoints
, nCount
, GdiLpToDp
);
237 GetCurrentPositionEx(
239 _Out_ LPPOINT lpPoint
)
243 /* Get the DC attribute */
244 pdcattr
= GdiGetDcAttr(hdc
);
245 if ((pdcattr
== NULL
) || (lpPoint
== NULL
))
247 SetLastError(ERROR_INVALID_PARAMETER
);
251 if (pdcattr
->ulDirty_
& DIRTY_PTLCURRENT
) // have a hit!
253 lpPoint
->x
= pdcattr
->ptfxCurrent
.x
;
254 lpPoint
->y
= pdcattr
->ptfxCurrent
.y
;
255 DPtoLP(hdc
, lpPoint
, 1); // reconvert back.
256 pdcattr
->ptlCurrent
.x
= lpPoint
->x
; // save it
257 pdcattr
->ptlCurrent
.y
= lpPoint
->y
;
258 pdcattr
->ulDirty_
&= ~DIRTY_PTLCURRENT
; // clear bit
262 lpPoint
->x
= pdcattr
->ptlCurrent
.x
;
263 lpPoint
->y
= pdcattr
->ptlCurrent
.y
;
276 _Out_ LPXFORM pxform
)
281 pdcattr
= GdiGetDcAttr(hdc
);
284 SetLastError(ERROR_INVALID_HANDLE
);
288 if (pdcattr
->flXform
& ANY_XFORM_INVALID
)
290 GdiFixupTransforms(pdcattr
);
293 MatrixToXForm(pxform
, &pdcattr
->mxWorldToDevice
);
295 return NtGdiGetTransform(hdc
, GdiWorldSpaceToPageSpace
, pxform
);
303 _Out_ CONST XFORM
*pxform
)
305 return ModifyWorldTransform(hdc
, pxform
, MWT_SET
);
311 ModifyWorldTransform(
313 _In_opt_ CONST XFORM
*pxform
,
318 if (GDI_HANDLE_GET_TYPE(hdc
) == GDILoObjType_LO_METADC16_TYPE
)
321 if (dwMode
== MWT_SET
)
323 HANDLE_METADC(BOOL
, SetWorldTransform
, FALSE
, hdc
, pxform
);
327 HANDLE_METADC(BOOL
, ModifyWorldTransform
, FALSE
, hdc
, pxform
, dwMode
);
330 /* Get the DC attribute */
331 pdcattr
= GdiGetDcAttr(hdc
);
334 SetLastError(ERROR_INVALID_PARAMETER
);
338 /* Check that graphics mode is GM_ADVANCED */
339 if (pdcattr
->iGraphicsMode
!= GM_ADVANCED
)
342 /* Call win32k to do the work */
343 return NtGdiModifyWorldTransform(hdc
, (LPXFORM
)pxform
, dwMode
);
354 /* Get the DC attribute */
355 pdcattr
= GdiGetDcAttr(hdc
);
358 /* Do not set LastError here! */
362 /* Check if we need to update values */
363 if ((pdcattr
->flXform
& PAGE_EXTENTS_CHANGED
) &&
364 (pdcattr
->iMapMode
== MM_ISOTROPIC
))
366 /* Call win32k to do the work */
367 return NtGdiGetDCPoint(hdc
, GdiGetViewPortExt
, (PPOINTL
)lpSize
);
370 /* Nothing to calculate, return the current extension */
371 lpSize
->cx
= pdcattr
->szlViewportExt
.cx
;
372 lpSize
->cy
= pdcattr
->szlViewportExt
.cy
;
382 _Out_ LPPOINT lpPoint
)
386 /* Get the DC attribute */
387 pdcattr
= GdiGetDcAttr(hdc
);
390 /* Do not set LastError here! */
394 /* Get the current viewport org */
395 lpPoint
->x
= pdcattr
->ptlViewportOrg
.x
;
396 lpPoint
->y
= pdcattr
->ptlViewportOrg
.y
;
398 /* Handle right-to-left layout */
399 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
400 lpPoint
->x
= -lpPoint
->x
;
414 /* Get the DC attribute */
415 pdcattr
= GdiGetDcAttr(hdc
);
418 /* Do not set LastError here! */
422 /* Get the current window extension */
423 lpSize
->cx
= pdcattr
->szlWindowExt
.cx
;
424 lpSize
->cy
= pdcattr
->szlWindowExt
.cy
;
426 /* Handle right-to-left layout */
427 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
428 lpSize
->cx
= -lpSize
->cx
;
438 _Out_ LPPOINT lpPoint
)
442 /* Get the DC attribute */
443 pdcattr
= GdiGetDcAttr(hdc
);
446 /* Do not set LastError here! */
450 /* Get the current window origin */
451 lpPoint
->x
= pdcattr
->ptlWindowOrg
.x
;
452 lpPoint
->y
= pdcattr
->ptlWindowOrg
.y
;
466 _Out_opt_ LPSIZE lpSize
)
470 HANDLE_METADC(BOOL
, SetViewportExtEx
, FALSE
, hdc
, nXExtent
, nYExtent
, lpSize
);
472 /* Get the DC attribute */
473 pdcattr
= GdiGetDcAttr(hdc
);
476 SetLastError(ERROR_INVALID_PARAMETER
);
480 /* Check if the caller wants the old extension */
483 /* Return the current viewport extension */
484 lpSize
->cx
= pdcattr
->szlViewportExt
.cx
;
485 lpSize
->cy
= pdcattr
->szlViewportExt
.cy
;
488 /* Check for trivial case */
489 if ((pdcattr
->szlViewportExt
.cx
== nXExtent
) &&
490 (pdcattr
->szlViewportExt
.cy
== nYExtent
))
493 /* Only change viewport extension if we are in iso or aniso mode */
494 if ((pdcattr
->iMapMode
== MM_ISOTROPIC
) ||
495 (pdcattr
->iMapMode
== MM_ANISOTROPIC
))
497 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
499 if (pdcattr
->ulDirty_
& DC_FONTTEXT_DIRTY
)
501 NtGdiFlush(); // Sync up pdcattr from Kernel space.
502 pdcattr
->ulDirty_
&= ~(DC_MODE_DIRTY
|DC_FONTTEXT_DIRTY
);
506 /* Set the new viewport extension */
507 pdcattr
->szlViewportExt
.cx
= nXExtent
;
508 pdcattr
->szlViewportExt
.cy
= nYExtent
;
510 /* Handle right-to-left layout */
511 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
512 NtGdiMirrorWindowOrg(hdc
);
514 /* Update xform flags */
515 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
530 _Out_opt_ LPPOINT lpPoint
)
534 HANDLE_METADC(BOOL
, SetWindowOrgEx
, FALSE
, hdc
, X
, Y
, lpPoint
);
536 /* Get the DC attribute */
537 pdcattr
= GdiGetDcAttr(hdc
);
540 /* Do not set LastError here! */
546 lpPoint
->x
= pdcattr
->ptlWindowOrg
.x
;
547 lpPoint
->y
= pdcattr
->ptlWindowOrg
.y
;
550 if ((pdcattr
->ptlWindowOrg
.x
== X
) && (pdcattr
->ptlWindowOrg
.y
== Y
))
553 if (NtCurrentTeb()->GdiTebBatch
.HDC
== (ULONG
)hdc
)
555 if (pdcattr
->ulDirty_
& DC_FONTTEXT_DIRTY
)
557 NtGdiFlush(); // Sync up pdcattr from Kernel space.
558 pdcattr
->ulDirty_
&= ~(DC_MODE_DIRTY
|DC_FONTTEXT_DIRTY
);
562 pdcattr
->ptlWindowOrg
.x
= X
;
563 pdcattr
->lWindowOrgx
= X
;
564 pdcattr
->ptlWindowOrg
.y
= Y
;
565 if (pdcattr
->dwLayout
& LAYOUT_RTL
) NtGdiMirrorWindowOrg(hdc
);
566 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|DEVICE_TO_WORLD_INVALID
);
569 return NtGdiSetWindowOrgEx(hdc
, X
, Y
, lpPoint
);
581 _Out_opt_ LPSIZE lpSize
)
585 HANDLE_METADC(BOOL
, SetWindowExtEx
, FALSE
, hdc
, nXExtent
, nYExtent
, lpSize
);
587 /* Get the DC attr */
588 pdcattr
= GdiGetDcAttr(hdc
);
591 /* Set the error value and return failure */
592 SetLastError(ERROR_INVALID_PARAMETER
);
596 /* Check if the caller wants the old extension */
599 /* Return the current window extension */
600 lpSize
->cx
= pdcattr
->szlWindowExt
.cx
;
601 lpSize
->cy
= pdcattr
->szlWindowExt
.cy
;
603 /* Handle right-to-left layout */
604 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
605 lpSize
->cx
= -lpSize
->cx
;
608 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
610 NtGdiMirrorWindowOrg(hdc
);
611 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
613 else if ((pdcattr
->iMapMode
== MM_ISOTROPIC
) ||
614 (pdcattr
->iMapMode
== MM_ANISOTROPIC
))
616 if ((pdcattr
->szlWindowExt
.cx
== nXExtent
) &&
617 (pdcattr
->szlWindowExt
.cy
== nYExtent
))
620 if ((!nXExtent
) || (!nYExtent
))
623 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
625 if (pdcattr
->ulDirty_
& DC_FONTTEXT_DIRTY
)
627 NtGdiFlush(); // Sync up Dc_Attr from Kernel space.
628 pdcattr
->ulDirty_
&= ~(DC_MODE_DIRTY
|DC_FONTTEXT_DIRTY
);
632 pdcattr
->szlWindowExt
.cx
= nXExtent
;
633 pdcattr
->szlWindowExt
.cy
= nYExtent
;
634 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
635 NtGdiMirrorWindowOrg(hdc
);
637 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
652 _Out_opt_ LPPOINT lpPoint
)
656 HANDLE_METADC(BOOL
, SetViewportOrgEx
, FALSE
, hdc
, X
, Y
, lpPoint
);
658 /* Get the DC attribute */
659 pdcattr
= GdiGetDcAttr(hdc
);
662 /* Do not set LastError here! */
669 lpPoint
->x
= pdcattr
->ptlViewportOrg
.x
;
670 lpPoint
->y
= pdcattr
->ptlViewportOrg
.y
;
671 if (pdcattr
->dwLayout
& LAYOUT_RTL
) lpPoint
->x
= -lpPoint
->x
;
673 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|DEVICE_TO_WORLD_INVALID
);
674 if (pdcattr
->dwLayout
& LAYOUT_RTL
) X
= -X
;
675 pdcattr
->ptlViewportOrg
.x
= X
;
676 pdcattr
->ptlViewportOrg
.y
= Y
;
679 return NtGdiSetViewportOrgEx(hdc
,X
,Y
,lpPoint
);
695 HANDLE_METADC(BOOL
, ScaleViewportExtEx
, FALSE
, hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
697 if (!GdiGetDcAttr(hdc
))
699 SetLastError(ERROR_INVALID_PARAMETER
);
703 return NtGdiScaleViewportExtEx(hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
719 HANDLE_METADC(BOOL
, ScaleWindowExtEx
, FALSE
, hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
721 if (!GdiGetDcAttr(hdc
))
723 SetLastError(ERROR_INVALID_PARAMETER
);
727 return NtGdiScaleWindowExtEx(hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
740 /* METADC16 is not supported in this API */
741 if (GDI_HANDLE_GET_TYPE(hdc
) == GDILoObjType_LO_METADC16_TYPE
)
746 /* Get the DC attribute */
747 pdcattr
= GdiGetDcAttr(hdc
);
750 /* Set the error value and return failure */
751 SetLastError(ERROR_INVALID_PARAMETER
);
755 /* Return the layout */
756 return pdcattr
->dwLayout
;
769 HANDLE_METADC(DWORD
, SetLayout
, GDI_ERROR
, hdc
, dwLayout
);
771 if (!GdiGetDcAttr(hdc
))
773 SetLastError(ERROR_INVALID_PARAMETER
);
777 return NtGdiSetLayout(hdc
, -1, dwLayout
);
790 /* Only normal DCs are handled here */
791 if (GDI_HANDLE_GET_TYPE(hdc
) != GDILoObjType_LO_DC_TYPE
)
796 if (!GdiGetDcAttr(hdc
))
798 SetLastError(ERROR_INVALID_PARAMETER
);
802 return NtGdiSetLayout(hdc
, wox
, dwLayout
);
812 _Out_ LPPOINT lpPoint
)
814 return NtGdiGetDCPoint(hdc
, GdiGetDCOrg
, (PPOINTL
)lpPoint
);
828 /* Call the new API */
829 if (!GetDCOrgEx(hdc
, &pt
))
832 /* Return the point in the old way */
833 return(MAKELONG(pt
.x
, pt
.y
));
847 _Out_opt_ LPPOINT lpPoint
)
851 HANDLE_METADC(BOOL
, OffsetViewportOrgEx
, FALSE
, hdc
, nXOffset
, nYOffset
, lpPoint
);
854 /* Get the DC attribute */
855 pdcattr
= GdiGetDcAttr(hdc
);
858 /* Do not set LastError here! */
864 *lpPoint
= (POINT
)pdcattr
->ptlViewportOrg
;
865 if ( pdcattr
->dwLayout
& LAYOUT_RTL
) lpPoint
->x
= -lpPoint
->x
;
868 if ( nXOffset
|| nYOffset
!= nXOffset
)
870 if (NtCurrentTeb()->GdiTebBatch
.HDC
== (ULONG
)hdc
)
872 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
875 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
879 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|DEVICE_TO_WORLD_INVALID
);
880 if (pdcattr
->dwLayout
& LAYOUT_RTL
) nXOffset
= -nXOffset
;
881 pdcattr
->ptlViewportOrg
.x
+= nXOffset
;
882 pdcattr
->ptlViewportOrg
.y
+= nYOffset
;
886 return NtGdiOffsetViewportOrgEx(hdc
, nXOffset
, nYOffset
, lpPoint
);
899 _Out_opt_ LPPOINT lpPoint
)
903 HANDLE_METADC(BOOL
, OffsetWindowOrgEx
, FALSE
, hdc
, nXOffset
, nYOffset
, lpPoint
);
906 /* Get the DC attribute */
907 pdcattr
= GdiGetDcAttr(hdc
);
910 /* Do not set LastError here! */
916 *lpPoint
= (POINT
)pdcattr
->ptlWindowOrg
;
917 lpPoint
->x
= pdcattr
->lWindowOrgx
;
920 if ( nXOffset
|| nYOffset
!= nXOffset
)
922 if (NtCurrentTeb()->GdiTebBatch
.HDC
== (ULONG
)hdc
)
924 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
927 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
931 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|DEVICE_TO_WORLD_INVALID
);
932 pdcattr
->ptlWindowOrg
.x
+= nXOffset
;
933 pdcattr
->ptlWindowOrg
.y
+= nYOffset
;
934 pdcattr
->lWindowOrgx
+= nXOffset
;
938 return NtGdiOffsetWindowOrgEx(hdc
, nXOffset
, nYOffset
, lpPoint
);