2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Coordinate systems
5 * FILE: win32ss/gdi/ntgdi/coord.c
6 * PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
9 /* Coordinate translation overview
10 * -------------------------------
12 * Windows uses 3 different coordinate systems, referred to as world space,
13 * page space and device space.
16 * This is the coordinate system of the physical device that displays the
17 * graphics. One unit matches one pixel of the surface. The coordinate system
18 * is always orthogonal.
21 * This is the coordinate system on the screen or on the paper layout for
22 * printer devices. The coordinate system is also orthogonal but one unit
23 * does not necessarily match one pixel. Instead there are different mapping
24 * modes that can be set using SetMapMode() that specify how page space units
25 * are transformed into device space units. These mapping modes are:
26 * - MM_TEXT: One unit matches one unit in device space (one pixel)
27 * - MM_TWIPS One unit matches 1/20 point (1/1440 inch)
28 * - MM_LOMETRIC: One unit matches 0.1 millimeter
29 * - MM_HIMETRIC: One unit matches 0.01 millimeter
30 * - MM_LOENGLISH: One unit matches 0.01 inch
31 * - MM_HIENGLISH: One unit matches 0.001 inch
34 * If the mapping mode is either MM_ISOTROPIC or MM_ANISOTROPIC, the actual
35 * transformation is calculated from the window and viewport extension.
36 * The window extension can be set using SetWindowExtEx() and describes the
37 * extents of an arbitrary window (not to confuse with the gui element!) in
38 * page space coordinates.
39 * The viewport extension can be set using SetViewportExtEx() and describes
40 * the extent of the same window in device space coordinates. If the mapping
41 * mode is MM_ISOTROPIC one of the viewport extensions can be adjusted by GDI
42 * to make sure the mapping stays isotropic, i.e. that it has the same x/y
43 * ratio as the window extension.
46 * World space is the coordinate system that is used for all GDI drawing
47 * operations. The metrics of this coordinate system depend on the DCs
48 * graphics mode, which can be set using SetGraphicsMode().
49 * If the graphics mode is GM_COMPATIBLE, world space is identical to page
50 * space and no additional transformation is applied.
51 * If the graphics mode is GM_ADVANCED, an arbitrary coordinate transformation
52 * can be set using SetWorldTransform(), which is applied to transform world
53 * space coordinates into page space coordinates.
56 * All coordinate translation data is stored in the DC attribute, so the values
57 * might be invalid. This has to be taken into account. Values might also be
58 * zero, so when a division is made, the value has to be read first and then
59 * checked! This is true for both integer and floating point values, even if
60 * we cannot get floating point exceptions on x86, we can get them on all other
61 * architectures that use the FPU directly instead of emulation.
62 * The result of all operations might be completely random and invalid, if it was
63 * messed with in an illegal way in user mode. This is not a problem, since the
64 * result of coordinate transformations are never expected to be "valid" values.
65 * In the worst case, the drawing operation draws rubbish into the DC.
68 /* INCLUDES ******************************************************************/
74 C_ASSERT(sizeof(XFORML
) == sizeof(XFORM
));
77 /* GLOBALS *******************************************************************/
79 const MATRIX gmxIdentity
=
81 FLOATOBJ_1
, FLOATOBJ_0
,
82 FLOATOBJ_0
, FLOATOBJ_1
,
83 FLOATOBJ_0
, FLOATOBJ_0
,
84 0, 0, XFORM_NO_TRANSLATION
|XFORM_FORMAT_LTOL
|XFORM_UNITY
|XFORM_SCALE
88 /* FUNCTIONS *****************************************************************/
92 DC_vFixIsotropicMapping(PDC pdc
)
97 SIZEL szlWindowExt
, szlViewportExt
;
98 ASSERT(pdc
->pdcattr
->iMapMode
== MM_ISOTROPIC
);
100 /* Get a pointer to the DC_ATTR */
101 pdcattr
= pdc
->pdcattr
;
103 /* Read the extents, we rely on non-null values */
104 szlWindowExt
= pdcattr
->szlWindowExt
;
105 szlViewportExt
= pdcattr
->szlViewportExt
;
107 /* Check if all values are valid */
108 if ((szlWindowExt
.cx
== 0) || (szlWindowExt
.cy
== 0) ||
109 (szlViewportExt
.cx
== 0) || (szlViewportExt
.cy
== 0))
111 /* Someone put rubbish into the fields, just ignore it. */
115 fx
= abs((LONG64
)szlWindowExt
.cx
* szlViewportExt
.cy
);
116 fy
= abs((LONG64
)szlWindowExt
.cy
* szlViewportExt
.cx
);
120 s
= (szlWindowExt
.cy
^ szlViewportExt
.cx
) > 0 ? 1 : -1;
121 pdcattr
->szlViewportExt
.cx
= (LONG
)(fx
* s
/ szlWindowExt
.cy
);
125 s
= (szlWindowExt
.cx
^ szlViewportExt
.cy
) > 0 ? 1 : -1;
126 pdcattr
->szlViewportExt
.cy
= (LONG
)(fy
* s
/ szlWindowExt
.cx
);
130 pdc
->pdcattr
->flXform
&= ~PAGE_EXTENTS_CHANGED
;
135 DC_vGetPageToDevice(PDC pdc
, MATRIX
*pmx
)
137 PDC_ATTR pdcattr
= pdc
->pdcattr
;
138 PSIZEL pszlViewPortExt
;
141 /* Get the viewport extension */
142 pszlViewPortExt
= DC_pszlViewportExt(pdc
);
144 /* Copy the window extension, so no one can mess with it */
145 szlWindowExt
= pdcattr
->szlWindowExt
;
147 /* No shearing / rotation */
148 FLOATOBJ_SetLong(&pmx
->efM12
, 0);
149 FLOATOBJ_SetLong(&pmx
->efM21
, 0);
151 /* Calculate scaling */
152 if (szlWindowExt
.cx
!= 0)
154 FLOATOBJ_SetLong(&pmx
->efM11
, pszlViewPortExt
->cx
);
155 FLOATOBJ_DivLong(&pmx
->efM11
, szlWindowExt
.cx
);
158 FLOATOBJ_SetLong(&pmx
->efM11
, 1);
160 if (szlWindowExt
.cy
!= 0)
162 FLOATOBJ_SetLong(&pmx
->efM22
, pszlViewPortExt
->cy
);
163 FLOATOBJ_DivLong(&pmx
->efM22
, szlWindowExt
.cy
);
166 FLOATOBJ_SetLong(&pmx
->efM22
, 1);
168 /* Calculate x offset */
169 FLOATOBJ_SetLong(&pmx
->efDx
, -pdcattr
->ptlWindowOrg
.x
);
170 FLOATOBJ_Mul(&pmx
->efDx
, &pmx
->efM11
);
171 FLOATOBJ_AddLong(&pmx
->efDx
, pdcattr
->ptlViewportOrg
.x
);
173 /* Calculate y offset */
174 FLOATOBJ_SetLong(&pmx
->efDy
, -pdcattr
->ptlWindowOrg
.y
);
175 FLOATOBJ_Mul(&pmx
->efDy
, &pmx
->efM22
);
176 FLOATOBJ_AddLong(&pmx
->efDy
, pdcattr
->ptlViewportOrg
.y
);
181 DC_vUpdateWorldToDevice(PDC pdc
)
183 XFORMOBJ xoPageToDevice
, xoWorldToPage
, xoWorldToDevice
;
184 MATRIX mxPageToDevice
;
186 // FIXME: make sure world-to-page is valid!
188 /* Construct a transformation to do the page-to-device conversion */
189 DC_vGetPageToDevice(pdc
, &mxPageToDevice
);
190 XFORMOBJ_vInit(&xoPageToDevice
, &mxPageToDevice
);
192 /* Recalculate the world-to-device xform */
193 XFORMOBJ_vInit(&xoWorldToPage
, &pdc
->pdcattr
->mxWorldToPage
);
194 XFORMOBJ_vInit(&xoWorldToDevice
, &pdc
->pdcattr
->mxWorldToDevice
);
195 XFORMOBJ_iCombine(&xoWorldToDevice
, &xoWorldToPage
, &xoPageToDevice
);
197 /* Reset the flags */
198 pdc
->pdcattr
->flXform
&= ~(PAGE_XLATE_CHANGED
|PAGE_EXTENTS_CHANGED
|WORLD_XFORM_CHANGED
);
203 DC_vUpdateDeviceToWorld(PDC pdc
)
205 XFORMOBJ xoWorldToDevice
, xoDeviceToWorld
;
206 PMATRIX pmxWorldToDevice
;
208 /* Get the world-to-device translation */
209 pmxWorldToDevice
= DC_pmxWorldToDevice(pdc
);
210 XFORMOBJ_vInit(&xoWorldToDevice
, pmxWorldToDevice
);
212 /* Create inverse of world-to-device transformation */
213 XFORMOBJ_vInit(&xoDeviceToWorld
, &pdc
->pdcattr
->mxDeviceToWorld
);
214 if (XFORMOBJ_iInverse(&xoDeviceToWorld
, &xoWorldToDevice
) == DDI_ERROR
)
216 // FIXME: do we need to reset anything?
221 pdc
->pdcattr
->flXform
&= ~DEVICE_TO_WORLD_INVALID
;
231 MATRIX mxDest
, mx1
, mx2
;
232 XFORMOBJ xoDest
, xo1
, xo2
;
234 /* Check for illegal parameters */
235 if (!pxformDest
|| !pxform1
|| !pxform2
) return FALSE
;
237 /* Initialize XFORMOBJs */
238 XFORMOBJ_vInit(&xoDest
, &mxDest
);
239 XFORMOBJ_vInit(&xo1
, &mx1
);
240 XFORMOBJ_vInit(&xo2
, &mx2
);
242 /* Convert the XFORMLs into XFORMOBJs */
243 XFORMOBJ_iSetXform(&xo1
, pxform1
);
244 XFORMOBJ_iSetXform(&xo2
, pxform2
);
247 XFORMOBJ_iCombine(&xoDest
, &xo1
, &xo2
);
249 /* Translate back into XFORML */
250 XFORMOBJ_iGetXform(&xoDest
, pxformDest
);
257 NtGdiCombineTransform(
258 LPXFORM UnsafeXFormResult
,
259 LPXFORM Unsafexform1
,
260 LPXFORM Unsafexform2
)
266 ProbeForWrite(UnsafeXFormResult
, sizeof(XFORM
), 1);
267 ProbeForRead(Unsafexform1
, sizeof(XFORM
), 1);
268 ProbeForRead(Unsafexform2
, sizeof(XFORM
), 1);
269 Ret
= GreCombineTransform((XFORML
*)UnsafeXFormResult
,
270 (XFORML
*)Unsafexform1
,
271 (XFORML
*)Unsafexform2
);
273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
282 // FIXME: Should be XFORML and use XFORMOBJ functions directly
292 MATRIX mxPageToDevice
;
298 EngSetLastError(ERROR_INVALID_PARAMETER
);
302 pdc
= DC_LockDc(hdc
);
305 EngSetLastError(ERROR_INVALID_HANDLE
);
311 case GdiWorldSpaceToPageSpace
:
312 pmx
= DC_pmxWorldToPage(pdc
);
315 case GdiWorldSpaceToDeviceSpace
:
316 pmx
= DC_pmxWorldToDevice(pdc
);
319 case GdiDeviceSpaceToWorldSpace
:
320 pmx
= DC_pmxDeviceToWorld(pdc
);
323 case GdiPageSpaceToDeviceSpace
:
324 DC_vGetPageToDevice(pdc
, &mxPageToDevice
);
325 pmx
= &mxPageToDevice
;
329 DPRINT1("Unknown transform %lu\n", iXform
);
334 /* Initialize an XFORMOBJ */
335 XFORMOBJ_vInit(&xo
, pmx
);
339 ProbeForWrite(pXForm
, sizeof(XFORML
), 1);
340 XFORMOBJ_iGetXform(&xo
, (XFORML
*)pXForm
);
342 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
355 * Converts points from logical coordinates into device coordinates.
356 * Conversion depends on the mapping mode,
357 * world transfrom, viewport origin settings for the given device context.
358 * \param hDC device context.
359 * \param Points an array of POINT structures (in/out).
360 * \param Count number of elements in the array of POINT structures.
361 * \return TRUE if success, FALSE otherwise.
365 NtGdiTransformPoints(
380 pdc
= DC_LockDc(hDC
);
383 EngSetLastError(ERROR_INVALID_PARAMETER
);
387 Size
= Count
* sizeof(POINT
);
389 // FIXME: It would be wise to have a small stack buffer as optimization
390 Points
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEMP
);
394 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
400 ProbeForWrite(UnsafePtOut
, Size
, 1);
401 ProbeForRead(UnsafePtsIn
, Size
, 1);
402 RtlCopyMemory(Points
, UnsafePtsIn
, Size
);
404 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
406 /* Do not set last error */
407 _SEH2_YIELD(goto leave
;)
414 DC_vXformDeviceToWorld(pdc
, Count
, Points
, Points
);
418 DC_vXformWorldToDevice(pdc
, Count
, Points
, Points
);
421 case 2: // Not supported yet. Need testing.
424 EngSetLastError(ERROR_INVALID_PARAMETER
);
432 /* Pointer was already probed! */
433 RtlCopyMemory(UnsafePtOut
, Points
, Size
);
435 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
437 /* Do not set last error */
443 // If we are getting called that means User XForms is a mess!
447 ExFreePoolWithTag(Points
, GDITAG_TEMP
);
453 GreModifyWorldTransform(
455 const XFORML
*pxform
,
459 XFORMOBJ xoSrc
, xoDC
;
464 pdc
->pdcattr
->mxWorldToPage
= gmxIdentity
;
467 case MWT_LEFTMULTIPLY
:
468 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
469 XFORMOBJ_vInit(&xoSrc
, &mxSrc
);
470 if (XFORMOBJ_iSetXform(&xoSrc
, pxform
) == DDI_ERROR
)
472 XFORMOBJ_iCombine(&xoDC
, &xoSrc
, &xoDC
);
475 case MWT_RIGHTMULTIPLY
:
476 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
477 XFORMOBJ_vInit(&xoSrc
, &mxSrc
);
478 if (XFORMOBJ_iSetXform(&xoSrc
, pxform
) == DDI_ERROR
)
480 XFORMOBJ_iCombine(&xoDC
, &xoDC
, &xoSrc
);
484 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
485 if (XFORMOBJ_iSetXform(&xoDC
, pxform
) == DDI_ERROR
)
493 /*Set invalidation flags */
494 pdc
->pdcattr
->flXform
|= WORLD_XFORM_CHANGED
|DEVICE_TO_WORLD_INVALID
;
501 NtGdiModifyWorldTransform(
503 LPXFORM pxformUnsafe
,
510 pdc
= DC_LockDc(hdc
);
513 EngSetLastError(ERROR_INVALID_HANDLE
);
517 /* The xform is permitted to be NULL for MWT_IDENTITY.
518 * However, if it is not NULL, then it must be valid even
519 * though it is not used. */
520 if ((dwMode
!= MWT_IDENTITY
) && (pxformUnsafe
== NULL
))
526 if (pxformUnsafe
!= NULL
)
530 ProbeForRead(pxformUnsafe
, sizeof(XFORML
), 1);
531 RtlCopyMemory(&xformSafe
, pxformUnsafe
, sizeof(XFORML
));
533 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
540 /* Safe to handle kernel mode data. */
541 if (Ret
) Ret
= GreModifyWorldTransform(pdc
, &xformSafe
, dwMode
);
548 NtGdiOffsetViewportOrgEx(
556 NTSTATUS Status
= STATUS_SUCCESS
;
561 EngSetLastError(ERROR_INVALID_HANDLE
);
564 pdcattr
= dc
->pdcattr
;
570 ProbeForWrite(UnsafePoint
, sizeof(POINT
), 1);
571 UnsafePoint
->x
= pdcattr
->ptlViewportOrg
.x
;
572 UnsafePoint
->y
= pdcattr
->ptlViewportOrg
.y
;
573 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
575 UnsafePoint
->x
= -UnsafePoint
->x
;
578 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
580 Status
= _SEH2_GetExceptionCode();
584 if (!NT_SUCCESS(Status
))
586 SetLastNtError(Status
);
592 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
596 pdcattr
->ptlViewportOrg
.x
+= XOffset
;
597 pdcattr
->ptlViewportOrg
.y
+= YOffset
;
598 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
607 NtGdiOffsetWindowOrgEx(
619 EngSetLastError(ERROR_INVALID_HANDLE
);
622 pdcattr
= dc
->pdcattr
;
626 NTSTATUS Status
= STATUS_SUCCESS
;
630 ProbeForWrite(Point
, sizeof(POINT
), 1);
631 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
632 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
634 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
636 Status
= _SEH2_GetExceptionCode();
640 if (!NT_SUCCESS(Status
))
642 SetLastNtError(Status
);
648 pdcattr
->ptlWindowOrg
.x
+= XOffset
;
649 pdcattr
->ptlWindowOrg
.y
+= YOffset
;
650 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
|DEVICE_TO_WORLD_INVALID
;
659 NtGdiScaleViewportExtEx(
672 pDC
= DC_LockDc(hDC
);
675 EngSetLastError(ERROR_INVALID_HANDLE
);
678 pdcattr
= pDC
->pdcattr
;
680 if (pdcattr
->iMapMode
> MM_TWIPS
)
682 if (Xdenom
&& Ydenom
)
684 DC_pszlViewportExt(pDC
);
685 X
= Xnum
* pdcattr
->szlViewportExt
.cx
/ Xdenom
;
688 Y
= Ynum
* pdcattr
->szlViewportExt
.cy
/ Ydenom
;
691 pdcattr
->szlViewportExt
.cx
= X
;
692 pdcattr
->szlViewportExt
.cy
= Y
;
693 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
695 IntMirrorWindowOrg(pDC
);
697 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
698 INVALIDATE_ATTRIBUTES
|
699 DEVICE_TO_WORLD_INVALID
);
701 if (pdcattr
->iMapMode
== MM_ISOTROPIC
)
703 DC_vFixIsotropicMapping(pDC
);
718 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
720 pSize
->cx
= pdcattr
->szlViewportExt
.cx
;
721 pSize
->cy
= pdcattr
->szlViewportExt
.cy
;
723 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
725 SetLastNtError(_SEH2_GetExceptionCode());
737 NtGdiScaleWindowExtEx(
750 pDC
= DC_LockDc(hDC
);
753 EngSetLastError(ERROR_INVALID_HANDLE
);
756 pdcattr
= pDC
->pdcattr
;
760 NTSTATUS Status
= STATUS_SUCCESS
;
764 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
766 X
= pdcattr
->szlWindowExt
.cx
;
767 if (pdcattr
->dwLayout
& LAYOUT_RTL
) X
= -X
;
769 pSize
->cy
= pdcattr
->szlWindowExt
.cy
;
771 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
773 Status
= _SEH2_GetExceptionCode();
777 if (!NT_SUCCESS(Status
))
779 SetLastNtError(Status
);
785 if (pdcattr
->iMapMode
> MM_TWIPS
)
787 if (Xdenom
&& Ydenom
)
789 X
= Xnum
* pdcattr
->szlWindowExt
.cx
/ Xdenom
;
792 Y
= Ynum
* pdcattr
->szlWindowExt
.cy
/ Ydenom
;
795 pdcattr
->szlWindowExt
.cx
= X
;
796 pdcattr
->szlWindowExt
.cy
= Y
;
798 IntMirrorWindowOrg(pDC
);
800 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
822 PDC_ATTR pdcattr
= dc
->pdcattr
;
824 flXform
= pdcattr
->flXform
& ~(ISO_OR_ANISO_MAP_MODE
|PTOD_EFM22_NEGATIVE
|
825 PTOD_EFM11_NEGATIVE
|POSITIVE_Y_IS_UP
|PAGE_TO_DEVICE_SCALE_IDENTITY
|
826 PAGE_TO_DEVICE_IDENTITY
);
831 pdcattr
->szlWindowExt
.cx
= 1;
832 pdcattr
->szlWindowExt
.cy
= 1;
833 pdcattr
->szlViewportExt
.cx
= 1;
834 pdcattr
->szlViewportExt
.cy
= 1;
835 flXform
|= PAGE_TO_DEVICE_SCALE_IDENTITY
;
839 flXform
|= ISO_OR_ANISO_MAP_MODE
;
843 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 10;
844 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 10;
845 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
846 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
850 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 100;
851 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 100;
852 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
853 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
857 pdcattr
->szlWindowExt
.cx
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
858 pdcattr
->szlWindowExt
.cy
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
859 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
860 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
864 pdcattr
->szlWindowExt
.cx
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
865 pdcattr
->szlWindowExt
.cy
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
866 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
867 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
871 pdcattr
->szlWindowExt
.cx
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
872 pdcattr
->szlWindowExt
.cy
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
873 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
874 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
878 flXform
&= ~(PAGE_TO_DEVICE_IDENTITY
|POSITIVE_Y_IS_UP
);
879 flXform
|= ISO_OR_ANISO_MAP_MODE
;
886 /* Save the old map mode and set the new one */
887 iPrevMapMode
= pdcattr
->iMapMode
;
888 pdcattr
->iMapMode
= MapMode
;
890 /* Update xform flags */
891 pdcattr
->flXform
= flXform
| (PAGE_XLATE_CHANGED
|PAGE_EXTENTS_CHANGED
|
892 INVALIDATE_ATTRIBUTES
|DEVICE_TO_PAGE_INVALID
|DEVICE_TO_WORLD_INVALID
);
911 EngSetLastError(ERROR_INVALID_HANDLE
);
914 pdcattr
= dc
->pdcattr
;
918 Point
->x
= pdcattr
->ptlViewportOrg
.x
;
919 Point
->y
= pdcattr
->ptlViewportOrg
.y
;
922 pdcattr
->ptlViewportOrg
.x
= X
;
923 pdcattr
->ptlViewportOrg
.y
= Y
;
924 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
932 NtGdiSetViewportOrgEx(
944 EngSetLastError(ERROR_INVALID_HANDLE
);
947 pdcattr
= dc
->pdcattr
;
951 NTSTATUS Status
= STATUS_SUCCESS
;
955 ProbeForWrite(Point
, sizeof(POINT
), 1);
956 Point
->x
= pdcattr
->ptlViewportOrg
.x
;
957 Point
->y
= pdcattr
->ptlViewportOrg
.y
;
959 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
961 Status
= _SEH2_GetExceptionCode();
965 if (!NT_SUCCESS(Status
))
967 SetLastNtError(Status
);
973 pdcattr
->ptlViewportOrg
.x
= X
;
974 pdcattr
->ptlViewportOrg
.y
= Y
;
975 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
996 EngSetLastError(ERROR_INVALID_HANDLE
);
999 pdcattr
= dc
->pdcattr
;
1003 NTSTATUS Status
= STATUS_SUCCESS
;
1007 ProbeForWrite(Point
, sizeof(POINT
), 1);
1008 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
1009 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
1011 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1013 Status
= _SEH2_GetExceptionCode();
1017 if (!NT_SUCCESS(Status
))
1019 SetLastNtError(Status
);
1025 pdcattr
->ptlWindowOrg
.x
= X
;
1026 pdcattr
->ptlWindowOrg
.y
= Y
;
1027 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
1035 // Mirror Window function.
1039 IntMirrorWindowOrg(PDC dc
)
1044 pdcattr
= dc
->pdcattr
;
1046 if (!(pdcattr
->dwLayout
& LAYOUT_RTL
))
1048 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
; // Flip it back.
1052 /* Copy the window extension, so no one can mess with it */
1053 cx
= pdcattr
->szlViewportExt
.cx
;
1054 if (cx
== 0) return;
1056 // WOrgx = wox - (Width - 1) * WExtx / VExtx
1058 X
= (dc
->erclWindow
.right
- dc
->erclWindow
.left
) - 1; // Get device width - 1
1060 X
= (X
* pdcattr
->szlWindowExt
.cx
) / cx
;
1062 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
- X
; // Now set the inverted win origion.
1063 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
1075 PDC_ATTR pdcattr
= pdc
->pdcattr
;
1077 pdcattr
->dwLayout
= dwLayout
;
1079 if (!(dwLayout
& LAYOUT_ORIENTATIONMASK
)) return;
1081 if (dwLayout
& LAYOUT_RTL
)
1083 pdcattr
->iMapMode
= MM_ANISOTROPIC
;
1086 //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
1087 //pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x;
1090 // IntMirrorWindowOrg(pdc);
1092 // pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
1094 if (!(pdcattr
->flTextAlign
& TA_CENTER
)) pdcattr
->flTextAlign
|= TA_RIGHT
;
1096 if (pdc
->dclevel
.flPath
& DCPATH_CLOCKWISE
)
1097 pdc
->dclevel
.flPath
&= ~DCPATH_CLOCKWISE
;
1099 pdc
->dclevel
.flPath
|= DCPATH_CLOCKWISE
;
1101 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
1102 INVALIDATE_ATTRIBUTES
|
1103 DEVICE_TO_WORLD_INVALID
);
1108 // The default is left to right. This function changes it to right to left, which
1109 // is the standard in Arabic and Hebrew cultures.
1124 pdc
= DC_LockDc(hdc
);
1127 EngSetLastError(ERROR_INVALID_HANDLE
);
1131 dwOldLayout
= pdc
->pdcattr
->dwLayout
;
1132 DC_vSetLayout(pdc
, wox
, dwLayout
);
1143 NtGdiGetDeviceWidth(
1148 dc
= DC_LockDc(hdc
);
1151 EngSetLastError(ERROR_INVALID_HANDLE
);
1154 Ret
= dc
->erclWindow
.right
- dc
->erclWindow
.left
;
1164 NtGdiMirrorWindowOrg(
1168 dc
= DC_LockDc(hdc
);
1171 EngSetLastError(ERROR_INVALID_HANDLE
);
1174 IntMirrorWindowOrg(dc
);
1186 IN INT cxVirtualDevice
,
1187 IN INT cyVirtualDevice
)
1192 if (!cxVirtualDevice
|| !cyVirtualDevice
)
1197 dc
= DC_LockDc(hdc
);
1198 if (!dc
) return FALSE
;
1200 pdcattr
= dc
->pdcattr
;
1202 pdcattr
->szlVirtualDeviceSize
.cx
= cxVirtualDevice
;
1203 pdcattr
->szlVirtualDeviceSize
.cy
= cyVirtualDevice
;
1215 NtGdiSetVirtualResolution(
1217 IN INT cxVirtualDevicePixel
,
1218 IN INT cyVirtualDevicePixel
,
1219 IN INT cxVirtualDeviceMm
,
1220 IN INT cyVirtualDeviceMm
)
1225 /* Check parameters (all zeroes resets to real resolution) */
1226 if (cxVirtualDevicePixel
== 0 && cyVirtualDevicePixel
== 0 &&
1227 cxVirtualDeviceMm
== 0 && cyVirtualDeviceMm
== 0)
1229 cxVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, HORZRES
);
1230 cyVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, VERTRES
);
1231 cxVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, HORZSIZE
);
1232 cyVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, VERTSIZE
);
1234 else if (cxVirtualDevicePixel
== 0 || cyVirtualDevicePixel
== 0 ||
1235 cxVirtualDeviceMm
== 0 || cyVirtualDeviceMm
== 0)
1240 dc
= DC_LockDc(hdc
);
1241 if (!dc
) return FALSE
;
1243 pdcattr
= dc
->pdcattr
;
1245 pdcattr
->szlVirtualDevicePixel
.cx
= cxVirtualDevicePixel
;
1246 pdcattr
->szlVirtualDevicePixel
.cy
= cyVirtualDevicePixel
;
1247 pdcattr
->szlVirtualDeviceMm
.cx
= cxVirtualDeviceMm
;
1248 pdcattr
->szlVirtualDeviceMm
.cy
= cyVirtualDeviceMm
;
1250 // DC_vUpdateXforms(dc);
1257 DC_vGetAspectRatioFilter(PDC pDC
, LPSIZE AspectRatio
)
1259 if (pDC
->pdcattr
->flFontMapper
& 1) // TRUE assume 1.
1261 // "This specifies that Windows should only match fonts that have the
1262 // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1263 AspectRatio
->cx
= pDC
->ppdev
->gdiinfo
.ulLogPixelsX
;
1264 AspectRatio
->cy
= pDC
->ppdev
->gdiinfo
.ulLogPixelsY
;
1268 AspectRatio
->cx
= 0;
1269 AspectRatio
->cy
= 0;
1282 PSIZEL pszlViewportExt
;
1286 EngSetLastError(ERROR_INVALID_PARAMETER
);
1290 pdc
= DC_LockDc(hDC
);
1293 EngSetLastError(ERROR_INVALID_HANDLE
);
1299 case GdiGetViewPortExt
:
1300 pszlViewportExt
= DC_pszlViewportExt(pdc
);
1301 Point
->x
= pszlViewportExt
->cx
;
1302 Point
->y
= pszlViewportExt
->cy
;
1305 case GdiGetWindowExt
:
1306 Point
->x
= pdc
->pdcattr
->szlWindowExt
.cx
;
1307 Point
->y
= pdc
->pdcattr
->szlWindowExt
.cy
;
1310 case GdiGetViewPortOrg
:
1311 *Point
= pdc
->pdcattr
->ptlViewportOrg
;
1314 case GdiGetWindowOrg
:
1315 *Point
= pdc
->pdcattr
->ptlWindowOrg
;
1319 *Point
= pdc
->ptlDCOrig
;
1322 case GdiGetAspectRatioFilter
:
1323 DC_vGetAspectRatioFilter(pdc
, &Size
);
1329 EngSetLastError(ERROR_INVALID_PARAMETER
);
1344 _In_opt_ PRECTL Rect
)
1348 dc
= DC_LockDc(hdc
);
1349 if (!dc
) return FALSE
;
1352 dc
->ptlDCOrig
.x
= x
;
1353 dc
->ptlDCOrig
.y
= y
;
1355 /* Recalculate Fill Origin */
1356 dc
->ptlFillOrigin
.x
= dc
->dclevel
.ptlBrushOrigin
.x
+ x
;
1357 dc
->ptlFillOrigin
.y
= dc
->dclevel
.ptlBrushOrigin
.y
+ y
;
1359 /* Set DC Window Rectangle */
1361 dc
->erclWindow
= *Rect
;
1371 _Out_ PPOINTL Point
,
1376 dc
= DC_LockDc(hdc
);
1377 if (!dc
) return FALSE
;
1379 /* Retrieve DC Window Rectangle without a check */
1380 *Rect
= dc
->erclWindow
;
1384 /* Use default call for DC Origin and parameter checking */
1385 return GreGetDCPoint( hdc
, GdiGetDCOrg
, Point
);
1392 _Out_ LPSIZE lpSize
)
1394 return GreGetDCPoint(hdc
, GdiGetWindowExt
, (PPOINTL
)lpSize
);
1399 GreGetViewportExtEx(
1401 _Out_ LPSIZE lpSize
)
1403 return GreGetDCPoint(hdc
, GdiGetViewPortExt
, (PPOINTL
)lpSize
);
1417 EngSetLastError(ERROR_INVALID_PARAMETER
);
1421 Ret
= GreGetDCPoint(hDC
, iPoint
, &SafePoint
);
1426 ProbeForWrite(Point
, sizeof(POINT
), 1);
1429 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)