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
,
182 SetLastError(ERROR_INVALID_PARAMETER
);
185 if (lpPoints
== NULL
)
190 pdcattr
= GdiGetDcAttr(hdc
);
194 if (pdcattr
->iMapMode
== MM_ISOTROPIC
)
196 if (NtGdiGetDCPoint(hdc
, GdiGetViewPortExt
, (PPOINTL
)&sizlView
))
198 if (sizlView
.cx
== 0 || sizlView
.cy
== 0)
203 return NtGdiTransformPoints(hdc
, lpPoints
, lpPoints
, nCount
, GdiDpToLp
);
210 _Inout_updates_(nCount
) LPPOINT lpPoints
,
220 SetLastError(ERROR_INVALID_PARAMETER
);
223 if (lpPoints
== NULL
)
228 pdcattr
= GdiGetDcAttr(hdc
);
232 return NtGdiTransformPoints(hdc
, lpPoints
, lpPoints
, nCount
, GdiLpToDp
);
241 GetCurrentPositionEx(
243 _Out_ LPPOINT lpPoint
)
247 /* Get the DC attribute */
248 pdcattr
= GdiGetDcAttr(hdc
);
249 if ((pdcattr
== NULL
) || (lpPoint
== NULL
))
251 SetLastError(ERROR_INVALID_PARAMETER
);
255 if (pdcattr
->ulDirty_
& DIRTY_PTLCURRENT
) // have a hit!
257 lpPoint
->x
= pdcattr
->ptfxCurrent
.x
;
258 lpPoint
->y
= pdcattr
->ptfxCurrent
.y
;
259 DPtoLP(hdc
, lpPoint
, 1); // reconvert back.
260 pdcattr
->ptlCurrent
.x
= lpPoint
->x
; // save it
261 pdcattr
->ptlCurrent
.y
= lpPoint
->y
;
262 pdcattr
->ulDirty_
&= ~DIRTY_PTLCURRENT
; // clear bit
266 lpPoint
->x
= pdcattr
->ptlCurrent
.x
;
267 lpPoint
->y
= pdcattr
->ptlCurrent
.y
;
280 _Out_ LPXFORM pxform
)
284 pdcattr
= GdiGetDcAttr(hdc
);
287 SetLastError(ERROR_INVALID_HANDLE
);
291 if (pdcattr
->flXform
& ANY_XFORM_INVALID
)
293 GdiFixupTransforms(pdcattr
);
296 MatrixToXForm(pxform
, &pdcattr
->mxWorldToDevice
);
298 return NtGdiGetTransform(hdc
, GdiWorldSpaceToPageSpace
, pxform
);
306 _Out_ CONST XFORM
*pxform
)
308 return ModifyWorldTransform(hdc
, pxform
, MWT_SET
);
314 ModifyWorldTransform(
316 _In_opt_ CONST XFORM
*pxform
,
321 if (GDI_HANDLE_GET_TYPE(hdc
) == GDILoObjType_LO_METADC16_TYPE
)
324 if (dwMode
== MWT_SET
)
326 HANDLE_METADC(BOOL
, SetWorldTransform
, FALSE
, hdc
, pxform
);
330 HANDLE_METADC(BOOL
, ModifyWorldTransform
, FALSE
, hdc
, pxform
, dwMode
);
333 /* Get the DC attribute */
334 pdcattr
= GdiGetDcAttr(hdc
);
337 SetLastError(ERROR_INVALID_PARAMETER
);
341 /* Check that graphics mode is GM_ADVANCED */
342 if (pdcattr
->iGraphicsMode
!= GM_ADVANCED
)
345 /* Call win32k to do the work */
346 return NtGdiModifyWorldTransform(hdc
, (LPXFORM
)pxform
, dwMode
);
357 /* Get the DC attribute */
358 pdcattr
= GdiGetDcAttr(hdc
);
361 /* Do not set LastError here! */
365 /* Check if we need to update values */
366 if ((pdcattr
->flXform
& PAGE_EXTENTS_CHANGED
) &&
367 (pdcattr
->iMapMode
== MM_ISOTROPIC
))
369 /* Call win32k to do the work */
370 return NtGdiGetDCPoint(hdc
, GdiGetViewPortExt
, (PPOINTL
)lpSize
);
373 /* Nothing to calculate, return the current extension */
374 lpSize
->cx
= pdcattr
->szlViewportExt
.cx
;
375 lpSize
->cy
= pdcattr
->szlViewportExt
.cy
;
385 _Out_ LPPOINT lpPoint
)
389 /* Get the DC attribute */
390 pdcattr
= GdiGetDcAttr(hdc
);
393 /* Do not set LastError here! */
397 /* Get the current viewport org */
398 lpPoint
->x
= pdcattr
->ptlViewportOrg
.x
;
399 lpPoint
->y
= pdcattr
->ptlViewportOrg
.y
;
401 /* Handle right-to-left layout */
402 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
403 lpPoint
->x
= -lpPoint
->x
;
417 /* Get the DC attribute */
418 pdcattr
= GdiGetDcAttr(hdc
);
421 /* Do not set LastError here! */
425 /* Get the current window extension */
426 lpSize
->cx
= pdcattr
->szlWindowExt
.cx
;
427 lpSize
->cy
= pdcattr
->szlWindowExt
.cy
;
429 /* Handle right-to-left layout */
430 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
431 lpSize
->cx
= -lpSize
->cx
;
441 _Out_ LPPOINT lpPoint
)
445 /* Get the DC attribute */
446 pdcattr
= GdiGetDcAttr(hdc
);
449 /* Do not set LastError here! */
453 /* Get the current window origin */
454 lpPoint
->x
= pdcattr
->ptlWindowOrg
.x
;
455 lpPoint
->y
= pdcattr
->ptlWindowOrg
.y
;
469 _Out_opt_ LPSIZE lpSize
)
473 HANDLE_METADC(BOOL
, SetViewportExtEx
, FALSE
, hdc
, nXExtent
, nYExtent
, lpSize
);
475 /* Get the DC attribute */
476 pdcattr
= GdiGetDcAttr(hdc
);
479 SetLastError(ERROR_INVALID_PARAMETER
);
483 /* Check if the caller wants the old extension */
486 /* Return the current viewport extension */
487 lpSize
->cx
= pdcattr
->szlViewportExt
.cx
;
488 lpSize
->cy
= pdcattr
->szlViewportExt
.cy
;
491 /* Check for trivial case */
492 if ((pdcattr
->szlViewportExt
.cx
== nXExtent
) &&
493 (pdcattr
->szlViewportExt
.cy
== nYExtent
))
496 if (nXExtent
== 0 || nYExtent
== 0)
499 /* Only change viewport extension if we are in iso or aniso mode */
500 if ((pdcattr
->iMapMode
== MM_ISOTROPIC
) ||
501 (pdcattr
->iMapMode
== MM_ANISOTROPIC
))
503 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
505 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
507 NtGdiFlush(); // Sync up pdcattr from Kernel space.
508 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
512 /* Set the new viewport extension */
513 pdcattr
->szlViewportExt
.cx
= nXExtent
;
514 pdcattr
->szlViewportExt
.cy
= nYExtent
;
516 /* Handle right-to-left layout */
517 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
518 NtGdiMirrorWindowOrg(hdc
);
520 /* Update xform flags */
521 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
536 _Out_opt_ LPPOINT lpPoint
)
540 HANDLE_METADC(BOOL
, SetWindowOrgEx
, FALSE
, hdc
, X
, Y
, lpPoint
);
542 /* Get the DC attribute */
543 pdcattr
= GdiGetDcAttr(hdc
);
546 /* Do not set LastError here! */
552 lpPoint
->x
= pdcattr
->ptlWindowOrg
.x
;
553 lpPoint
->y
= pdcattr
->ptlWindowOrg
.y
;
556 if ((pdcattr
->ptlWindowOrg
.x
== X
) && (pdcattr
->ptlWindowOrg
.y
== Y
))
559 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
561 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
563 NtGdiFlush(); // Sync up pdcattr from Kernel space.
564 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
568 pdcattr
->ptlWindowOrg
.x
= X
;
569 pdcattr
->ptlWindowOrg
.y
= Y
;
571 pdcattr
->lWindowOrgx
= X
;
572 if (pdcattr
->dwLayout
& LAYOUT_RTL
) NtGdiMirrorWindowOrg(hdc
);
573 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|WORLD_XFORM_CHANGED
|DEVICE_TO_WORLD_INVALID
);
576 // return NtGdiSetWindowOrgEx(hdc, X, Y, lpPoint);
588 _Out_opt_ LPSIZE lpSize
)
592 HANDLE_METADC(BOOL
, SetWindowExtEx
, FALSE
, hdc
, nXExtent
, nYExtent
, lpSize
);
594 /* Get the DC attr */
595 pdcattr
= GdiGetDcAttr(hdc
);
598 /* Set the error value and return failure */
599 SetLastError(ERROR_INVALID_PARAMETER
);
603 /* Check if the caller wants the old extension */
606 /* Return the current window extension */
607 lpSize
->cx
= pdcattr
->szlWindowExt
.cx
;
608 lpSize
->cy
= pdcattr
->szlWindowExt
.cy
;
610 /* Handle right-to-left layout */
611 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
612 lpSize
->cx
= -lpSize
->cx
;
615 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
617 NtGdiMirrorWindowOrg(hdc
);
618 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
620 else if ((pdcattr
->iMapMode
== MM_ISOTROPIC
) ||
621 (pdcattr
->iMapMode
== MM_ANISOTROPIC
))
623 if ((pdcattr
->szlWindowExt
.cx
== nXExtent
) &&
624 (pdcattr
->szlWindowExt
.cy
== nYExtent
))
627 if ((!nXExtent
) || (!nYExtent
))
630 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
632 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
634 NtGdiFlush(); // Sync up Dc_Attr from Kernel space.
635 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
639 pdcattr
->szlWindowExt
.cx
= nXExtent
;
640 pdcattr
->szlWindowExt
.cy
= nYExtent
;
641 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
642 NtGdiMirrorWindowOrg(hdc
);
644 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
659 _Out_opt_ LPPOINT lpPoint
)
663 HANDLE_METADC(BOOL
, SetViewportOrgEx
, FALSE
, hdc
, X
, Y
, lpPoint
);
665 /* Get the DC attribute */
666 pdcattr
= GdiGetDcAttr(hdc
);
669 /* Do not set LastError here! */
672 //// HACK : XP+ doesn't do this. See CORE-16656 & CORE-16644.
673 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
675 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
678 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
684 lpPoint
->x
= pdcattr
->ptlViewportOrg
.x
;
685 lpPoint
->y
= pdcattr
->ptlViewportOrg
.y
;
686 if (pdcattr
->dwLayout
& LAYOUT_RTL
) lpPoint
->x
= -lpPoint
->x
;
688 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|WORLD_XFORM_CHANGED
|DEVICE_TO_WORLD_INVALID
);
689 if (pdcattr
->dwLayout
& LAYOUT_RTL
) X
= -X
;
690 pdcattr
->ptlViewportOrg
.x
= X
;
691 pdcattr
->ptlViewportOrg
.y
= Y
;
694 // return NtGdiSetViewportOrgEx(hdc,X,Y,lpPoint);
710 HANDLE_METADC(BOOL
, ScaleViewportExtEx
, FALSE
, hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
712 if (!GdiGetDcAttr(hdc
))
714 SetLastError(ERROR_INVALID_PARAMETER
);
718 return NtGdiScaleViewportExtEx(hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
734 HANDLE_METADC(BOOL
, ScaleWindowExtEx
, FALSE
, hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
736 if (!GdiGetDcAttr(hdc
))
738 SetLastError(ERROR_INVALID_PARAMETER
);
742 return NtGdiScaleWindowExtEx(hdc
, xNum
, xDenom
, yNum
, yDenom
, lpSize
);
755 /* METADC16 is not supported in this API */
756 if (GDI_HANDLE_GET_TYPE(hdc
) == GDILoObjType_LO_METADC16_TYPE
)
761 /* Get the DC attribute */
762 pdcattr
= GdiGetDcAttr(hdc
);
765 /* Set the error value and return failure */
766 SetLastError(ERROR_INVALID_PARAMETER
);
770 /* Return the layout */
771 return pdcattr
->dwLayout
;
784 HANDLE_METADC(DWORD
, SetLayout
, GDI_ERROR
, hdc
, dwLayout
);
786 if (!GdiGetDcAttr(hdc
))
788 SetLastError(ERROR_INVALID_PARAMETER
);
792 return NtGdiSetLayout(hdc
, -1, dwLayout
);
805 /* Only normal DCs are handled here */
806 if (GDI_HANDLE_GET_TYPE(hdc
) != GDILoObjType_LO_DC_TYPE
)
811 if (!GdiGetDcAttr(hdc
))
813 SetLastError(ERROR_INVALID_PARAMETER
);
817 return NtGdiSetLayout(hdc
, wox
, dwLayout
);
827 _Out_ LPPOINT lpPoint
)
829 return NtGdiGetDCPoint(hdc
, GdiGetDCOrg
, (PPOINTL
)lpPoint
);
843 /* Call the new API */
844 if (!GetDCOrgEx(hdc
, &pt
))
847 /* Return the point in the old way */
848 return(MAKELONG(pt
.x
, pt
.y
));
862 _Out_opt_ LPPOINT lpPoint
)
866 HANDLE_METADC(BOOL
, OffsetViewportOrgEx
, FALSE
, hdc
, nXOffset
, nYOffset
, lpPoint
);
868 /* Get the DC attribute */
869 pdcattr
= GdiGetDcAttr(hdc
);
872 /* Do not set LastError here! */
878 *lpPoint
= pdcattr
->ptlViewportOrg
;
879 if ( pdcattr
->dwLayout
& LAYOUT_RTL
) lpPoint
->x
= -lpPoint
->x
;
882 if ( nXOffset
|| nYOffset
!= nXOffset
)
884 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
886 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
889 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
893 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|WORLD_XFORM_CHANGED
|DEVICE_TO_WORLD_INVALID
);
894 if (pdcattr
->dwLayout
& LAYOUT_RTL
) nXOffset
= -nXOffset
;
895 pdcattr
->ptlViewportOrg
.x
+= nXOffset
;
896 pdcattr
->ptlViewportOrg
.y
+= nYOffset
;
900 // return NtGdiOffsetViewportOrgEx(hdc, nXOffset, nYOffset, lpPoint);
913 _Out_opt_ LPPOINT lpPoint
)
917 HANDLE_METADC(BOOL
, OffsetWindowOrgEx
, FALSE
, hdc
, nXOffset
, nYOffset
, lpPoint
);
919 /* Get the DC attribute */
920 pdcattr
= GdiGetDcAttr(hdc
);
923 /* Do not set LastError here! */
929 *lpPoint
= pdcattr
->ptlWindowOrg
;
930 //lpPoint->x = pdcattr->lWindowOrgx;
933 if ( nXOffset
|| nYOffset
!= nXOffset
)
935 if (NtCurrentTeb()->GdiTebBatch
.HDC
== hdc
)
937 if (pdcattr
->ulDirty_
& DC_MODE_DIRTY
)
940 pdcattr
->ulDirty_
&= ~DC_MODE_DIRTY
;
944 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|WORLD_XFORM_CHANGED
|DEVICE_TO_WORLD_INVALID
);
945 pdcattr
->ptlWindowOrg
.x
+= nXOffset
;
946 pdcattr
->ptlWindowOrg
.y
+= nYOffset
;
947 pdcattr
->lWindowOrgx
+= nXOffset
;
951 // return NtGdiOffsetWindowOrgEx(hdc, nXOffset, nYOffset, lpPoint);