2 * COPYRIGHT: GNU GPL, See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Coordinate systems
5 * FILE: subsystems/win32/win32k/objects/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
);
483 case MWT_MAX
+1: // Must be MWT_SET????
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 ((pxformUnsafe
!= NULL
) || (dwMode
!= MWT_IDENTITY
))
524 ProbeForRead(pxformUnsafe
, sizeof(XFORML
), 1);
525 RtlCopyMemory(&xformSafe
, pxformUnsafe
, sizeof(XFORML
));
527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
534 /* Safe to handle kernel mode data. */
535 if (Ret
) Ret
= GreModifyWorldTransform(pdc
, &xformSafe
, dwMode
);
542 NtGdiOffsetViewportOrgEx(
550 NTSTATUS Status
= STATUS_SUCCESS
;
555 EngSetLastError(ERROR_INVALID_HANDLE
);
558 pdcattr
= dc
->pdcattr
;
564 ProbeForWrite(UnsafePoint
, sizeof(POINT
), 1);
565 UnsafePoint
->x
= pdcattr
->ptlViewportOrg
.x
;
566 UnsafePoint
->y
= pdcattr
->ptlViewportOrg
.y
;
567 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
569 UnsafePoint
->x
= -UnsafePoint
->x
;
572 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
574 Status
= _SEH2_GetExceptionCode();
578 if (!NT_SUCCESS(Status
))
580 SetLastNtError(Status
);
586 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
590 pdcattr
->ptlViewportOrg
.x
+= XOffset
;
591 pdcattr
->ptlViewportOrg
.y
+= YOffset
;
592 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
601 NtGdiOffsetWindowOrgEx(
613 EngSetLastError(ERROR_INVALID_HANDLE
);
616 pdcattr
= dc
->pdcattr
;
620 NTSTATUS Status
= STATUS_SUCCESS
;
624 ProbeForWrite(Point
, sizeof(POINT
), 1);
625 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
626 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
628 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
630 Status
= _SEH2_GetExceptionCode();
634 if (!NT_SUCCESS(Status
))
636 SetLastNtError(Status
);
642 pdcattr
->ptlWindowOrg
.x
+= XOffset
;
643 pdcattr
->ptlWindowOrg
.y
+= YOffset
;
644 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
|DEVICE_TO_WORLD_INVALID
;
653 NtGdiScaleViewportExtEx(
666 pDC
= DC_LockDc(hDC
);
669 EngSetLastError(ERROR_INVALID_HANDLE
);
672 pdcattr
= pDC
->pdcattr
;
674 if (pdcattr
->iMapMode
> MM_TWIPS
)
676 if (Xdenom
&& Ydenom
)
678 DC_pszlViewportExt(pDC
);
679 X
= Xnum
* pdcattr
->szlViewportExt
.cx
/ Xdenom
;
682 Y
= Ynum
* pdcattr
->szlViewportExt
.cy
/ Ydenom
;
685 pdcattr
->szlViewportExt
.cx
= X
;
686 pdcattr
->szlViewportExt
.cy
= Y
;
687 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
689 IntMirrorWindowOrg(pDC
);
691 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
692 INVALIDATE_ATTRIBUTES
|
693 DEVICE_TO_WORLD_INVALID
);
695 if (pdcattr
->iMapMode
== MM_ISOTROPIC
)
697 DC_vFixIsotropicMapping(pDC
);
712 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
714 pSize
->cx
= pdcattr
->szlViewportExt
.cx
;
715 pSize
->cy
= pdcattr
->szlViewportExt
.cy
;
717 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
719 SetLastNtError(_SEH2_GetExceptionCode());
731 NtGdiScaleWindowExtEx(
744 pDC
= DC_LockDc(hDC
);
747 EngSetLastError(ERROR_INVALID_HANDLE
);
750 pdcattr
= pDC
->pdcattr
;
754 NTSTATUS Status
= STATUS_SUCCESS
;
758 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
760 X
= pdcattr
->szlWindowExt
.cx
;
761 if (pdcattr
->dwLayout
& LAYOUT_RTL
) X
= -X
;
763 pSize
->cy
= pdcattr
->szlWindowExt
.cy
;
765 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
767 Status
= _SEH2_GetExceptionCode();
771 if (!NT_SUCCESS(Status
))
773 SetLastNtError(Status
);
779 if (pdcattr
->iMapMode
> MM_TWIPS
)
781 if (Xdenom
&& Ydenom
)
783 X
= Xnum
* pdcattr
->szlWindowExt
.cx
/ Xdenom
;
786 Y
= Ynum
* pdcattr
->szlWindowExt
.cy
/ Ydenom
;
789 pdcattr
->szlWindowExt
.cx
= X
;
790 pdcattr
->szlWindowExt
.cy
= Y
;
792 IntMirrorWindowOrg(pDC
);
794 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
816 PDC_ATTR pdcattr
= dc
->pdcattr
;
818 flXform
= pdcattr
->flXform
& ~(ISO_OR_ANISO_MAP_MODE
|PTOD_EFM22_NEGATIVE
|
819 PTOD_EFM11_NEGATIVE
|POSITIVE_Y_IS_UP
|PAGE_TO_DEVICE_SCALE_IDENTITY
|
820 PAGE_TO_DEVICE_IDENTITY
);
825 pdcattr
->szlWindowExt
.cx
= 1;
826 pdcattr
->szlWindowExt
.cy
= 1;
827 pdcattr
->szlViewportExt
.cx
= 1;
828 pdcattr
->szlViewportExt
.cy
= 1;
829 flXform
|= PAGE_TO_DEVICE_SCALE_IDENTITY
;
833 flXform
|= ISO_OR_ANISO_MAP_MODE
;
837 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 10;
838 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 10;
839 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
840 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
844 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 100;
845 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 100;
846 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
847 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
851 pdcattr
->szlWindowExt
.cx
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
852 pdcattr
->szlWindowExt
.cy
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
853 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
854 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
858 pdcattr
->szlWindowExt
.cx
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
859 pdcattr
->szlWindowExt
.cy
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
860 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
861 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
865 pdcattr
->szlWindowExt
.cx
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
866 pdcattr
->szlWindowExt
.cy
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
867 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
868 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
872 flXform
&= ~(PAGE_TO_DEVICE_IDENTITY
|POSITIVE_Y_IS_UP
);
873 flXform
|= ISO_OR_ANISO_MAP_MODE
;
880 /* Save the old map mode and set the new one */
881 iPrevMapMode
= pdcattr
->iMapMode
;
882 pdcattr
->iMapMode
= MapMode
;
884 /* Update xform flags */
885 pdcattr
->flXform
= flXform
| (PAGE_XLATE_CHANGED
|PAGE_EXTENTS_CHANGED
|
886 INVALIDATE_ATTRIBUTES
|DEVICE_TO_PAGE_INVALID
|DEVICE_TO_WORLD_INVALID
);
894 NtGdiSetViewportOrgEx(
906 EngSetLastError(ERROR_INVALID_HANDLE
);
909 pdcattr
= dc
->pdcattr
;
913 NTSTATUS Status
= STATUS_SUCCESS
;
917 ProbeForWrite(Point
, sizeof(POINT
), 1);
918 Point
->x
= pdcattr
->ptlViewportOrg
.x
;
919 Point
->y
= pdcattr
->ptlViewportOrg
.y
;
921 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
923 Status
= _SEH2_GetExceptionCode();
927 if (!NT_SUCCESS(Status
))
929 SetLastNtError(Status
);
935 pdcattr
->ptlViewportOrg
.x
= X
;
936 pdcattr
->ptlViewportOrg
.y
= Y
;
937 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
958 EngSetLastError(ERROR_INVALID_HANDLE
);
961 pdcattr
= dc
->pdcattr
;
965 NTSTATUS Status
= STATUS_SUCCESS
;
969 ProbeForWrite(Point
, sizeof(POINT
), 1);
970 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
971 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
973 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
975 Status
= _SEH2_GetExceptionCode();
979 if (!NT_SUCCESS(Status
))
981 SetLastNtError(Status
);
987 pdcattr
->ptlWindowOrg
.x
= X
;
988 pdcattr
->ptlWindowOrg
.y
= Y
;
989 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
997 // Mirror Window function.
1001 IntMirrorWindowOrg(PDC dc
)
1006 pdcattr
= dc
->pdcattr
;
1008 if (!(pdcattr
->dwLayout
& LAYOUT_RTL
))
1010 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
; // Flip it back.
1014 /* Copy the window extension, so no one can mess with it */
1015 cx
= pdcattr
->szlViewportExt
.cx
;
1016 if (cx
== 0) return;
1018 // WOrgx = wox - (Width - 1) * WExtx / VExtx
1020 X
= (dc
->erclWindow
.right
- dc
->erclWindow
.left
) - 1; // Get device width - 1
1022 X
= (X
* pdcattr
->szlWindowExt
.cx
) / cx
;
1024 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
- X
; // Now set the inverted win origion.
1025 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
1037 PDC_ATTR pdcattr
= pdc
->pdcattr
;
1039 pdcattr
->dwLayout
= dwLayout
;
1041 if (!(dwLayout
& LAYOUT_ORIENTATIONMASK
)) return;
1043 if (dwLayout
& LAYOUT_RTL
)
1045 pdcattr
->iMapMode
= MM_ANISOTROPIC
;
1048 //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
1049 //pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x;
1052 // IntMirrorWindowOrg(pdc);
1054 // pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
1056 if (!(pdcattr
->flTextAlign
& TA_CENTER
)) pdcattr
->flTextAlign
|= TA_RIGHT
;
1058 if (pdc
->dclevel
.flPath
& DCPATH_CLOCKWISE
)
1059 pdc
->dclevel
.flPath
&= ~DCPATH_CLOCKWISE
;
1061 pdc
->dclevel
.flPath
|= DCPATH_CLOCKWISE
;
1063 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
1064 INVALIDATE_ATTRIBUTES
|
1065 DEVICE_TO_WORLD_INVALID
);
1070 // The default is left to right. This function changes it to right to left, which
1071 // is the standard in Arabic and Hebrew cultures.
1086 pdc
= DC_LockDc(hdc
);
1089 EngSetLastError(ERROR_INVALID_HANDLE
);
1093 dwOldLayout
= pdc
->pdcattr
->dwLayout
;
1094 DC_vSetLayout(pdc
, wox
, dwLayout
);
1105 NtGdiGetDeviceWidth(
1110 dc
= DC_LockDc(hdc
);
1113 EngSetLastError(ERROR_INVALID_HANDLE
);
1116 Ret
= dc
->erclWindow
.right
- dc
->erclWindow
.left
;
1126 NtGdiMirrorWindowOrg(
1130 dc
= DC_LockDc(hdc
);
1133 EngSetLastError(ERROR_INVALID_HANDLE
);
1136 IntMirrorWindowOrg(dc
);
1148 IN INT cxVirtualDevice
,
1149 IN INT cyVirtualDevice
)
1154 if (!cxVirtualDevice
|| !cyVirtualDevice
)
1159 dc
= DC_LockDc(hdc
);
1160 if (!dc
) return FALSE
;
1162 pdcattr
= dc
->pdcattr
;
1164 pdcattr
->szlVirtualDeviceSize
.cx
= cxVirtualDevice
;
1165 pdcattr
->szlVirtualDeviceSize
.cy
= cyVirtualDevice
;
1177 NtGdiSetVirtualResolution(
1179 IN INT cxVirtualDevicePixel
,
1180 IN INT cyVirtualDevicePixel
,
1181 IN INT cxVirtualDeviceMm
,
1182 IN INT cyVirtualDeviceMm
)
1187 /* Check parameters (all zeroes resets to real resolution) */
1188 if (cxVirtualDevicePixel
== 0 && cyVirtualDevicePixel
== 0 &&
1189 cxVirtualDeviceMm
== 0 && cyVirtualDeviceMm
== 0)
1191 cxVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, HORZRES
);
1192 cyVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, VERTRES
);
1193 cxVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, HORZSIZE
);
1194 cyVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, VERTSIZE
);
1196 else if (cxVirtualDevicePixel
== 0 || cyVirtualDevicePixel
== 0 ||
1197 cxVirtualDeviceMm
== 0 || cyVirtualDeviceMm
== 0)
1202 dc
= DC_LockDc(hdc
);
1203 if (!dc
) return FALSE
;
1205 pdcattr
= dc
->pdcattr
;
1207 pdcattr
->szlVirtualDevicePixel
.cx
= cxVirtualDevicePixel
;
1208 pdcattr
->szlVirtualDevicePixel
.cy
= cyVirtualDevicePixel
;
1209 pdcattr
->szlVirtualDeviceMm
.cx
= cxVirtualDeviceMm
;
1210 pdcattr
->szlVirtualDeviceMm
.cy
= cyVirtualDeviceMm
;
1212 // DC_vUpdateXforms(dc);
1219 DC_vGetAspectRatioFilter(PDC pDC
, LPSIZE AspectRatio
)
1221 if (pDC
->pdcattr
->flFontMapper
& 1) // TRUE assume 1.
1223 // "This specifies that Windows should only match fonts that have the
1224 // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1225 AspectRatio
->cx
= pDC
->ppdev
->gdiinfo
.ulLogPixelsX
;
1226 AspectRatio
->cy
= pDC
->ppdev
->gdiinfo
.ulLogPixelsY
;
1230 AspectRatio
->cx
= 0;
1231 AspectRatio
->cy
= 0;
1245 PSIZEL pszlViewportExt
;
1249 EngSetLastError(ERROR_INVALID_PARAMETER
);
1253 pdc
= DC_LockDc(hDC
);
1256 EngSetLastError(ERROR_INVALID_HANDLE
);
1262 case GdiGetViewPortExt
:
1263 pszlViewportExt
= DC_pszlViewportExt(pdc
);
1264 SafePoint
.x
= pszlViewportExt
->cx
;
1265 SafePoint
.y
= pszlViewportExt
->cy
;
1268 case GdiGetWindowExt
:
1269 SafePoint
.x
= pdc
->pdcattr
->szlWindowExt
.cx
;
1270 SafePoint
.y
= pdc
->pdcattr
->szlWindowExt
.cy
;
1273 case GdiGetViewPortOrg
:
1274 SafePoint
= pdc
->pdcattr
->ptlViewportOrg
;
1277 case GdiGetWindowOrg
:
1278 SafePoint
= pdc
->pdcattr
->ptlWindowOrg
;
1282 SafePoint
= pdc
->ptlDCOrig
;
1285 case GdiGetAspectRatioFilter
:
1286 DC_vGetAspectRatioFilter(pdc
, &Size
);
1287 SafePoint
.x
= Size
.cx
;
1288 SafePoint
.y
= Size
.cy
;
1292 EngSetLastError(ERROR_INVALID_PARAMETER
);
1301 ProbeForWrite(Point
, sizeof(POINT
), 1);
1304 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)