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 neccesarily 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 * transormation 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, that is it has the same x/y ratio
43 * 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. Integer values might be
58 * zero, so when a division is made, the value has to be read first and then
59 * checked! For floating point values (FLOATOBJ as well) these restrictions do
60 * not apply, since we cannot get dividy-by-zero exceptions.
61 * Though the result might be a completely random and invalid value, if it was
62 * messed with in an illegal way in user mode. This is not a problem, since the
63 * result of coordinate transformations are never expected to be "valid" values.
64 * In the worst case, the drawing operation draws rubbish into the DC.
67 /* INCLUDES ******************************************************************/
73 C_ASSERT(sizeof(XFORML
) == sizeof(XFORM
));
76 /* GLOBALS *******************************************************************/
78 const MATRIX gmxIdentity
=
80 FLOATOBJ_1
, FLOATOBJ_0
,
81 FLOATOBJ_0
, FLOATOBJ_1
,
82 FLOATOBJ_0
, FLOATOBJ_0
,
83 0, 0, XFORM_NO_TRANSLATION
|XFORM_FORMAT_LTOL
|XFORM_UNITY
|XFORM_SCALE
87 /* FUNCTIONS *****************************************************************/
91 DC_vFixIsotropicMapping(PDC pdc
)
96 SIZEL szlWindowExt
, szlViewportExt
;
97 ASSERT(pdc
->pdcattr
->iMapMode
== MM_ISOTROPIC
);
99 /* Get a pointer to the DC_ATTR */
100 pdcattr
= pdc
->pdcattr
;
102 /* Read the extents, we rely on non-null values */
103 szlWindowExt
= pdcattr
->szlWindowExt
;
104 szlViewportExt
= pdcattr
->szlViewportExt
;
106 /* Check if all values are valid */
107 if ((szlWindowExt
.cx
== 0) || (szlWindowExt
.cy
== 0) ||
108 (szlViewportExt
.cx
== 0) || (szlViewportExt
.cy
== 0))
110 /* Someone put rubbish into the fields, just ignore it. */
114 fx
= abs((LONG64
)szlWindowExt
.cx
* szlViewportExt
.cy
);
115 fy
= abs((LONG64
)szlWindowExt
.cy
* szlViewportExt
.cx
);
119 s
= (szlWindowExt
.cy
^ szlViewportExt
.cx
) > 0 ? 1 : -1;
120 pdcattr
->szlViewportExt
.cx
= (LONG
)(fx
* s
/ szlWindowExt
.cy
);
124 s
= (szlWindowExt
.cx
^ szlViewportExt
.cy
) > 0 ? 1 : -1;
125 pdcattr
->szlViewportExt
.cy
= (LONG
)(fy
* s
/ szlWindowExt
.cx
);
129 pdc
->pdcattr
->flXform
&= ~PAGE_EXTENTS_CHANGED
;
134 DC_vGetPageToDevice(PDC pdc
, MATRIX
*pmx
)
136 PDC_ATTR pdcattr
= pdc
->pdcattr
;
137 PSIZEL pszlViewPortExt
;
139 /* Get the viewport extension */
140 pszlViewPortExt
= DC_pszlViewportExt(pdc
);
142 /* No shearing / rotation */
143 FLOATOBJ_SetLong(&pmx
->efM12
, 0);
144 FLOATOBJ_SetLong(&pmx
->efM21
, 0);
146 /* Calculate scaling */
147 if (pdcattr
->szlWindowExt
.cx
!= 0)
149 FLOATOBJ_SetLong(&pmx
->efM11
, pszlViewPortExt
->cx
);
150 FLOATOBJ_DivLong(&pmx
->efM11
, pdcattr
->szlWindowExt
.cx
);
153 FLOATOBJ_SetLong(&pmx
->efM11
, 1);
155 if (pdcattr
->szlWindowExt
.cy
!= 0)
157 FLOATOBJ_SetLong(&pmx
->efM22
, pszlViewPortExt
->cy
);
158 FLOATOBJ_DivLong(&pmx
->efM22
, pdcattr
->szlWindowExt
.cy
);
161 FLOATOBJ_SetLong(&pmx
->efM22
, 1);
163 /* Calculate x offset */
164 FLOATOBJ_SetLong(&pmx
->efDx
, -pdcattr
->ptlWindowOrg
.x
);
165 FLOATOBJ_Mul(&pmx
->efDx
, &pmx
->efM11
);
166 FLOATOBJ_AddLong(&pmx
->efDx
, pdcattr
->ptlViewportOrg
.x
);
168 /* Calculate y offset */
169 FLOATOBJ_SetLong(&pmx
->efDy
, -pdcattr
->ptlWindowOrg
.y
);
170 FLOATOBJ_Mul(&pmx
->efDy
, &pmx
->efM22
);
171 FLOATOBJ_AddLong(&pmx
->efDy
, pdcattr
->ptlViewportOrg
.y
);
176 DC_vUpdateWorldToDevice(PDC pdc
)
178 XFORMOBJ xoPageToDevice
, xoWorldToPage
, xoWorldToDevice
;
179 MATRIX mxPageToDevice
;
181 // FIXME: make sure world-to-page is valid!
183 /* Construct a transformation to do the page-to-device conversion */
184 DC_vGetPageToDevice(pdc
, &mxPageToDevice
);
185 XFORMOBJ_vInit(&xoPageToDevice
, &mxPageToDevice
);
187 /* Recalculate the world-to-device xform */
188 XFORMOBJ_vInit(&xoWorldToPage
, &pdc
->pdcattr
->mxWorldToPage
);
189 XFORMOBJ_vInit(&xoWorldToDevice
, &pdc
->pdcattr
->mxWorldToDevice
);
190 XFORMOBJ_iCombine(&xoWorldToDevice
, &xoWorldToPage
, &xoPageToDevice
);
192 /* Reset the flags */
193 pdc
->pdcattr
->flXform
&= ~(PAGE_XLATE_CHANGED
|PAGE_EXTENTS_CHANGED
|WORLD_XFORM_CHANGED
);
198 DC_vUpdateDeviceToWorld(PDC pdc
)
200 XFORMOBJ xoWorldToDevice
, xoDeviceToWorld
;
201 PMATRIX pmxWorldToDevice
;
203 /* Get the world-to-device translation */
204 pmxWorldToDevice
= DC_pmxWorldToDevice(pdc
);
205 XFORMOBJ_vInit(&xoWorldToDevice
, pmxWorldToDevice
);
207 /* Create inverse of world-to-device transformation */
208 XFORMOBJ_vInit(&xoDeviceToWorld
, &pdc
->pdcattr
->mxDeviceToWorld
);
209 if (XFORMOBJ_iInverse(&xoDeviceToWorld
, &xoWorldToDevice
) == DDI_ERROR
)
211 // FIXME: do we need to reset anything?
216 pdc
->pdcattr
->flXform
&= ~DEVICE_TO_WORLD_INVALID
;
226 MATRIX mxDest
, mx1
, mx2
;
227 XFORMOBJ xoDest
, xo1
, xo2
;
229 /* Check for illegal parameters */
230 if (!pxformDest
|| !pxform1
|| !pxform2
) return FALSE
;
232 /* Initialize XFORMOBJs */
233 XFORMOBJ_vInit(&xoDest
, &mxDest
);
234 XFORMOBJ_vInit(&xo1
, &mx1
);
235 XFORMOBJ_vInit(&xo2
, &mx2
);
237 /* Convert the XFORMLs into XFORMOBJs */
238 XFORMOBJ_iSetXform(&xo1
, pxform1
);
239 XFORMOBJ_iSetXform(&xo2
, pxform2
);
242 XFORMOBJ_iCombine(&xoDest
, &xo1
, &xo2
);
244 /* Translate back into XFORML */
245 XFORMOBJ_iGetXform(&xoDest
, pxformDest
);
252 NtGdiCombineTransform(
253 LPXFORM UnsafeXFormResult
,
254 LPXFORM Unsafexform1
,
255 LPXFORM Unsafexform2
)
261 ProbeForWrite(UnsafeXFormResult
, sizeof(XFORM
), 1);
262 ProbeForRead(Unsafexform1
, sizeof(XFORM
), 1);
263 ProbeForRead(Unsafexform2
, sizeof(XFORM
), 1);
264 Ret
= GreCombineTransform((XFORML
*)UnsafeXFormResult
,
265 (XFORML
*)Unsafexform1
,
266 (XFORML
*)Unsafexform2
);
268 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
277 // FIXME: Should be XFORML and use XFORMOBJ functions directly
287 MATRIX mxPageToDevice
;
293 EngSetLastError(ERROR_INVALID_PARAMETER
);
297 pdc
= DC_LockDc(hdc
);
300 EngSetLastError(ERROR_INVALID_HANDLE
);
306 case GdiWorldSpaceToPageSpace
:
307 pmx
= DC_pmxWorldToPage(pdc
);
310 case GdiWorldSpaceToDeviceSpace
:
311 pmx
= DC_pmxWorldToDevice(pdc
);
314 case GdiDeviceSpaceToWorldSpace
:
315 pmx
= DC_pmxDeviceToWorld(pdc
);
318 case GdiPageSpaceToDeviceSpace
:
319 DC_vGetPageToDevice(pdc
, &mxPageToDevice
);
320 pmx
= &mxPageToDevice
;
324 DPRINT1("Unknown transform %lu\n", iXform
);
329 /* Initialize an XFORMOBJ */
330 XFORMOBJ_vInit(&xo
, pmx
);
334 ProbeForWrite(pXForm
, sizeof(XFORML
), 1);
335 XFORMOBJ_iGetXform(&xo
, (XFORML
*)pXForm
);
337 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
350 * Converts points from logical coordinates into device coordinates.
351 * Conversion depends on the mapping mode,
352 * world transfrom, viewport origin settings for the given device context.
353 * \param hDC device context.
354 * \param Points an array of POINT structures (in/out).
355 * \param Count number of elements in the array of POINT structures.
356 * \return TRUE if success, FALSE otherwise.
360 NtGdiTransformPoints(
375 pdc
= DC_LockDc(hDC
);
378 EngSetLastError(ERROR_INVALID_PARAMETER
);
382 Size
= Count
* sizeof(POINT
);
384 // FIXME: It would be wise to have a small stack buffer as optimization
385 Points
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEMP
);
389 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
395 ProbeForWrite(UnsafePtOut
, Size
, 1);
396 ProbeForRead(UnsafePtsIn
, Size
, 1);
397 RtlCopyMemory(Points
, UnsafePtsIn
, Size
);
399 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
401 /* Do not set last error */
402 _SEH2_YIELD(goto leave
;)
409 DC_vXformDeviceToWorld(pdc
, Count
, Points
, Points
);
413 DC_vXformWorldToDevice(pdc
, Count
, Points
, Points
);
416 case 2: // Not supported yet. Need testing.
419 EngSetLastError(ERROR_INVALID_PARAMETER
);
427 /* Pointer was already probed! */
428 RtlCopyMemory(UnsafePtOut
, Points
, Size
);
430 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
432 /* Do not set last error */
438 // If we are getting called that means User XForms is a mess!
442 ExFreePoolWithTag(Points
, GDITAG_TEMP
);
448 GreModifyWorldTransform(
450 const XFORML
*pxform
,
454 XFORMOBJ xoSrc
, xoDC
;
459 pdc
->pdcattr
->mxWorldToPage
= gmxIdentity
;
462 case MWT_LEFTMULTIPLY
:
463 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
464 XFORMOBJ_vInit(&xoSrc
, &mxSrc
);
465 if (XFORMOBJ_iSetXform(&xoSrc
, pxform
) == DDI_ERROR
)
467 XFORMOBJ_iCombine(&xoDC
, &xoSrc
, &xoDC
);
470 case MWT_RIGHTMULTIPLY
:
471 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
472 XFORMOBJ_vInit(&xoSrc
, &mxSrc
);
473 if (XFORMOBJ_iSetXform(&xoSrc
, pxform
) == DDI_ERROR
)
475 XFORMOBJ_iCombine(&xoDC
, &xoDC
, &xoSrc
);
478 case MWT_MAX
+1: // Must be MWT_SET????
479 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
480 if (XFORMOBJ_iSetXform(&xoDC
, pxform
) == DDI_ERROR
)
488 /*Set invalidation flags */
489 pdc
->pdcattr
->flXform
|= WORLD_XFORM_CHANGED
|DEVICE_TO_WORLD_INVALID
;
496 NtGdiModifyWorldTransform(
498 LPXFORM pxformUnsafe
,
505 pdc
= DC_LockDc(hdc
);
508 EngSetLastError(ERROR_INVALID_HANDLE
);
512 /* The xform is permitted to be NULL for MWT_IDENTITY.
513 * However, if it is not NULL, then it must be valid even
514 * though it is not used. */
515 if (pxformUnsafe
!= NULL
|| dwMode
!= MWT_IDENTITY
)
519 ProbeForRead(pxformUnsafe
, sizeof(XFORML
), 1);
520 RtlCopyMemory(&xformSafe
, pxformUnsafe
, sizeof(XFORML
));
522 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
529 /* Safe to handle kernel mode data. */
530 if (Ret
) Ret
= GreModifyWorldTransform(pdc
, &xformSafe
, dwMode
);
537 NtGdiOffsetViewportOrgEx(
545 NTSTATUS Status
= STATUS_SUCCESS
;
550 EngSetLastError(ERROR_INVALID_HANDLE
);
553 pdcattr
= dc
->pdcattr
;
559 ProbeForWrite(UnsafePoint
, sizeof(POINT
), 1);
560 UnsafePoint
->x
= pdcattr
->ptlViewportOrg
.x
;
561 UnsafePoint
->y
= pdcattr
->ptlViewportOrg
.y
;
562 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
564 UnsafePoint
->x
= -UnsafePoint
->x
;
567 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
569 Status
= _SEH2_GetExceptionCode();
573 if (!NT_SUCCESS(Status
))
575 SetLastNtError(Status
);
581 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
585 pdcattr
->ptlViewportOrg
.x
+= XOffset
;
586 pdcattr
->ptlViewportOrg
.y
+= YOffset
;
587 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
596 NtGdiOffsetWindowOrgEx(
608 EngSetLastError(ERROR_INVALID_HANDLE
);
611 pdcattr
= dc
->pdcattr
;
615 NTSTATUS Status
= STATUS_SUCCESS
;
619 ProbeForWrite(Point
, sizeof(POINT
), 1);
620 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
621 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
623 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
625 Status
= _SEH2_GetExceptionCode();
629 if (!NT_SUCCESS(Status
))
631 SetLastNtError(Status
);
637 pdcattr
->ptlWindowOrg
.x
+= XOffset
;
638 pdcattr
->ptlWindowOrg
.y
+= YOffset
;
639 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
|DEVICE_TO_WORLD_INVALID
;
648 NtGdiScaleViewportExtEx(
661 pDC
= DC_LockDc(hDC
);
664 EngSetLastError(ERROR_INVALID_HANDLE
);
667 pdcattr
= pDC
->pdcattr
;
669 if (pdcattr
->iMapMode
> MM_TWIPS
)
671 if (Xdenom
&& Ydenom
)
673 DC_pszlViewportExt(pDC
);
674 X
= Xnum
* pdcattr
->szlViewportExt
.cx
/ Xdenom
;
677 Y
= Ynum
* pdcattr
->szlViewportExt
.cy
/ Ydenom
;
680 pdcattr
->szlViewportExt
.cx
= X
;
681 pdcattr
->szlViewportExt
.cy
= Y
;
682 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
684 IntMirrorWindowOrg(pDC
);
686 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
687 INVALIDATE_ATTRIBUTES
|
688 DEVICE_TO_WORLD_INVALID
);
690 if (pdcattr
->iMapMode
== MM_ISOTROPIC
)
692 DC_vFixIsotropicMapping(pDC
);
707 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
709 pSize
->cx
= pdcattr
->szlViewportExt
.cx
;
710 pSize
->cy
= pdcattr
->szlViewportExt
.cy
;
712 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
714 SetLastNtError(_SEH2_GetExceptionCode());
726 NtGdiScaleWindowExtEx(
739 pDC
= DC_LockDc(hDC
);
742 EngSetLastError(ERROR_INVALID_HANDLE
);
745 pdcattr
= pDC
->pdcattr
;
749 NTSTATUS Status
= STATUS_SUCCESS
;
753 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
755 X
= pdcattr
->szlWindowExt
.cx
;
756 if (pdcattr
->dwLayout
& LAYOUT_RTL
) X
= -X
;
758 pSize
->cy
= pdcattr
->szlWindowExt
.cy
;
760 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
762 Status
= _SEH2_GetExceptionCode();
766 if (!NT_SUCCESS(Status
))
768 SetLastNtError(Status
);
774 if (pdcattr
->iMapMode
> MM_TWIPS
)
776 if (Xdenom
&& Ydenom
)
778 X
= Xnum
* pdcattr
->szlWindowExt
.cx
/ Xdenom
;
781 Y
= Ynum
* pdcattr
->szlWindowExt
.cy
/ Ydenom
;
784 pdcattr
->szlWindowExt
.cx
= X
;
785 pdcattr
->szlWindowExt
.cy
= Y
;
787 IntMirrorWindowOrg(pDC
);
789 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|INVALIDATE_ATTRIBUTES
|DEVICE_TO_WORLD_INVALID
);
810 PDC_ATTR pdcattr
= dc
->pdcattr
;
812 PrevMapMode
= pdcattr
->iMapMode
;
814 pdcattr
->iMapMode
= MapMode
;
815 pdcattr
->flXform
&= ~(ISO_OR_ANISO_MAP_MODE
|PTOD_EFM22_NEGATIVE
|
816 PTOD_EFM11_NEGATIVE
|POSITIVE_Y_IS_UP
|PAGE_TO_DEVICE_SCALE_IDENTITY
|
817 PAGE_TO_DEVICE_IDENTITY
);
822 pdcattr
->szlWindowExt
.cx
= 1;
823 pdcattr
->szlWindowExt
.cy
= 1;
824 pdcattr
->szlViewportExt
.cx
= 1;
825 pdcattr
->szlViewportExt
.cy
= 1;
826 pdcattr
->flXform
|= PAGE_TO_DEVICE_SCALE_IDENTITY
;
830 pdcattr
->flXform
|= ISO_OR_ANISO_MAP_MODE
;
834 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 10;
835 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 10;
836 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
837 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
841 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 100;
842 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 100;
843 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
844 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
848 pdcattr
->szlWindowExt
.cx
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
849 pdcattr
->szlWindowExt
.cy
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
850 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
851 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
855 pdcattr
->szlWindowExt
.cx
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
856 pdcattr
->szlWindowExt
.cy
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
857 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
858 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
862 pdcattr
->szlWindowExt
.cx
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
863 pdcattr
->szlWindowExt
.cy
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
864 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
865 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
869 pdcattr
->flXform
&= ~(PAGE_TO_DEVICE_IDENTITY
|POSITIVE_Y_IS_UP
);
870 pdcattr
->flXform
|= ISO_OR_ANISO_MAP_MODE
;
874 pdcattr
->iMapMode
= PrevMapMode
;
878 pdcattr
->flXform
|= (PAGE_XLATE_CHANGED
|PAGE_EXTENTS_CHANGED
|
879 INVALIDATE_ATTRIBUTES
|DEVICE_TO_PAGE_INVALID
|DEVICE_TO_WORLD_INVALID
);
887 NtGdiSetViewportOrgEx(
899 EngSetLastError(ERROR_INVALID_HANDLE
);
902 pdcattr
= dc
->pdcattr
;
906 NTSTATUS Status
= STATUS_SUCCESS
;
910 ProbeForWrite(Point
, sizeof(POINT
), 1);
911 Point
->x
= pdcattr
->ptlViewportOrg
.x
;
912 Point
->y
= pdcattr
->ptlViewportOrg
.y
;
914 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
916 Status
= _SEH2_GetExceptionCode();
920 if (!NT_SUCCESS(Status
))
922 SetLastNtError(Status
);
928 pdcattr
->ptlViewportOrg
.x
= X
;
929 pdcattr
->ptlViewportOrg
.y
= Y
;
930 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
951 EngSetLastError(ERROR_INVALID_HANDLE
);
954 pdcattr
= dc
->pdcattr
;
958 NTSTATUS Status
= STATUS_SUCCESS
;
962 ProbeForWrite(Point
, sizeof(POINT
), 1);
963 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
964 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
966 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
968 Status
= _SEH2_GetExceptionCode();
972 if (!NT_SUCCESS(Status
))
974 SetLastNtError(Status
);
980 pdcattr
->ptlWindowOrg
.x
= X
;
981 pdcattr
->ptlWindowOrg
.y
= Y
;
982 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
990 // Mirror Window function.
994 IntMirrorWindowOrg(PDC dc
)
999 pdcattr
= dc
->pdcattr
;
1001 if (!(pdcattr
->dwLayout
& LAYOUT_RTL
))
1003 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
; // Flip it back.
1006 if (!pdcattr
->szlViewportExt
.cx
) return;
1008 // WOrgx = wox - (Width - 1) * WExtx / VExtx
1010 X
= (dc
->erclWindow
.right
- dc
->erclWindow
.left
) - 1; // Get device width - 1
1012 X
= (X
* pdcattr
->szlWindowExt
.cx
) / pdcattr
->szlViewportExt
.cx
;
1014 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
- X
; // Now set the inverted win origion.
1015 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
1027 PDC_ATTR pdcattr
= pdc
->pdcattr
;
1029 pdcattr
->dwLayout
= dwLayout
;
1031 if (!(dwLayout
& LAYOUT_ORIENTATIONMASK
)) return;
1033 if (dwLayout
& LAYOUT_RTL
)
1035 pdcattr
->iMapMode
= MM_ANISOTROPIC
;
1038 //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
1039 //pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x;
1042 // IntMirrorWindowOrg(pdc);
1044 // pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
1046 if (!(pdcattr
->flTextAlign
& TA_CENTER
)) pdcattr
->flTextAlign
|= TA_RIGHT
;
1048 if (pdc
->dclevel
.flPath
& DCPATH_CLOCKWISE
)
1049 pdc
->dclevel
.flPath
&= ~DCPATH_CLOCKWISE
;
1051 pdc
->dclevel
.flPath
|= DCPATH_CLOCKWISE
;
1053 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
1054 INVALIDATE_ATTRIBUTES
|
1055 DEVICE_TO_WORLD_INVALID
);
1060 // The default is left to right. This function changes it to right to left, which
1061 // is the standard in Arabic and Hebrew cultures.
1076 pdc
= DC_LockDc(hdc
);
1079 EngSetLastError(ERROR_INVALID_HANDLE
);
1083 dwOldLayout
= pdc
->pdcattr
->dwLayout
;
1084 DC_vSetLayout(pdc
, wox
, dwLayout
);
1095 NtGdiGetDeviceWidth(
1100 dc
= DC_LockDc(hdc
);
1103 EngSetLastError(ERROR_INVALID_HANDLE
);
1106 Ret
= dc
->erclWindow
.right
- dc
->erclWindow
.left
;
1116 NtGdiMirrorWindowOrg(
1120 dc
= DC_LockDc(hdc
);
1123 EngSetLastError(ERROR_INVALID_HANDLE
);
1126 IntMirrorWindowOrg(dc
);
1138 IN INT cxVirtualDevice
,
1139 IN INT cyVirtualDevice
)
1144 if (!cxVirtualDevice
|| !cyVirtualDevice
)
1149 dc
= DC_LockDc(hdc
);
1150 if (!dc
) return FALSE
;
1152 pdcattr
= dc
->pdcattr
;
1154 pdcattr
->szlVirtualDeviceSize
.cx
= cxVirtualDevice
;
1155 pdcattr
->szlVirtualDeviceSize
.cy
= cyVirtualDevice
;
1167 NtGdiSetVirtualResolution(
1169 IN INT cxVirtualDevicePixel
,
1170 IN INT cyVirtualDevicePixel
,
1171 IN INT cxVirtualDeviceMm
,
1172 IN INT cyVirtualDeviceMm
)
1177 /* Check parameters (all zeroes resets to real resolution) */
1178 if (cxVirtualDevicePixel
== 0 && cyVirtualDevicePixel
== 0 &&
1179 cxVirtualDeviceMm
== 0 && cyVirtualDeviceMm
== 0)
1181 cxVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, HORZRES
);
1182 cyVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, VERTRES
);
1183 cxVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, HORZSIZE
);
1184 cyVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, VERTSIZE
);
1186 else if (cxVirtualDevicePixel
== 0 || cyVirtualDevicePixel
== 0 ||
1187 cxVirtualDeviceMm
== 0 || cyVirtualDeviceMm
== 0)
1192 dc
= DC_LockDc(hdc
);
1193 if (!dc
) return FALSE
;
1195 pdcattr
= dc
->pdcattr
;
1197 pdcattr
->szlVirtualDevicePixel
.cx
= cxVirtualDevicePixel
;
1198 pdcattr
->szlVirtualDevicePixel
.cy
= cyVirtualDevicePixel
;
1199 pdcattr
->szlVirtualDeviceMm
.cx
= cxVirtualDeviceMm
;
1200 pdcattr
->szlVirtualDeviceMm
.cy
= cyVirtualDeviceMm
;
1202 // DC_vUpdateXforms(dc);
1209 DC_vGetAspectRatioFilter(PDC pDC
, LPSIZE AspectRatio
)
1211 if (pDC
->pdcattr
->flFontMapper
& 1) // TRUE assume 1.
1213 // "This specifies that Windows should only match fonts that have the
1214 // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1215 AspectRatio
->cx
= pDC
->ppdev
->gdiinfo
.ulLogPixelsX
;
1216 AspectRatio
->cy
= pDC
->ppdev
->gdiinfo
.ulLogPixelsY
;
1220 AspectRatio
->cx
= 0;
1221 AspectRatio
->cy
= 0;
1235 PSIZEL pszlViewportExt
;
1239 EngSetLastError(ERROR_INVALID_PARAMETER
);
1243 pdc
= DC_LockDc(hDC
);
1246 EngSetLastError(ERROR_INVALID_HANDLE
);
1252 case GdiGetViewPortExt
:
1253 pszlViewportExt
= DC_pszlViewportExt(pdc
);
1254 SafePoint
.x
= pszlViewportExt
->cx
;
1255 SafePoint
.y
= pszlViewportExt
->cy
;
1258 case GdiGetWindowExt
:
1259 SafePoint
.x
= pdc
->pdcattr
->szlWindowExt
.cx
;
1260 SafePoint
.y
= pdc
->pdcattr
->szlWindowExt
.cy
;
1263 case GdiGetViewPortOrg
:
1264 SafePoint
= pdc
->pdcattr
->ptlViewportOrg
;
1267 case GdiGetWindowOrg
:
1268 SafePoint
= pdc
->pdcattr
->ptlWindowOrg
;
1272 SafePoint
= pdc
->ptlDCOrig
;
1275 case GdiGetAspectRatioFilter
:
1276 DC_vGetAspectRatioFilter(pdc
, &Size
);
1277 SafePoint
.x
= Size
.cx
;
1278 SafePoint
.y
= Size
.cy
;
1282 EngSetLastError(ERROR_INVALID_PARAMETER
);
1291 ProbeForWrite(Point
, sizeof(POINT
), 1);
1294 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)