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 * PROGRAMERS: Timo Kreuzer (timo.kreuzer@rectos.org)
7 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
10 /* Coordinate translation overview
11 * -------------------------------
13 * Windows uses 3 different coordinate systems, referred to as world space,
14 * page space and device space.
17 * This is the coordinate system of the physical device that displays the
18 * graphics. One unit matches one pixel of the surface. The coordinate system
19 * is always orthogonal.
22 * This is the coordinate system on the screen or on the paper layout for
23 * printer devices. The coordinate system is also orthogonal but one unit
24 * does not necessarily match one pixel. Instead there are different mapping
25 * modes that can be set using SetMapMode() that specify how page space units
26 * are transformed into device space units. These mapping modes are:
27 * - MM_TEXT: One unit matches one unit in device space (one pixel)
28 * - MM_TWIPS One unit matches 1/20 point (1/1440 inch)
29 * - MM_LOMETRIC: One unit matches 0.1 millimeter
30 * - MM_HIMETRIC: One unit matches 0.01 millimeter
31 * - MM_LOENGLISH: One unit matches 0.01 inch
32 * - MM_HIENGLISH: One unit matches 0.001 inch
35 * If the mapping mode is either MM_ISOTROPIC or MM_ANISOTROPIC, the actual
36 * transformation is calculated from the window and viewport extension.
37 * The window extension can be set using SetWindowExtEx() and describes the
38 * extents of an arbitrary window (not to confuse with the gui element!) in
39 * page space coordinates.
40 * The viewport extension can be set using SetViewportExtEx() and describes
41 * the extent of the same window in device space coordinates. If the mapping
42 * mode is MM_ISOTROPIC one of the viewport extensions can be adjusted by GDI
43 * to make sure the mapping stays isotropic, i.e. that it has the same x/y
44 * ratio as the window extension.
47 * World space is the coordinate system that is used for all GDI drawing
48 * operations. The metrics of this coordinate system depend on the DCs
49 * graphics mode, which can be set using SetGraphicsMode().
50 * If the graphics mode is GM_COMPATIBLE, world space is identical to page
51 * space and no additional transformation is applied.
52 * If the graphics mode is GM_ADVANCED, an arbitrary coordinate transformation
53 * can be set using SetWorldTransform(), which is applied to transform world
54 * space coordinates into page space coordinates.
57 * All coordinate translation data is stored in the DC attribute, so the values
58 * might be invalid. This has to be taken into account. Values might also be
59 * zero, so when a division is made, the value has to be read first and then
60 * checked! This is true for both integer and floating point values, even if
61 * we cannot get floating point exceptions on x86, we can get them on all other
62 * architectures that use the FPU directly instead of emulation.
63 * The result of all operations might be completely random and invalid, if it was
64 * messed with in an illegal way in user mode. This is not a problem, since the
65 * result of coordinate transformations are never expected to be "valid" values.
66 * In the worst case, the drawing operation draws rubbish into the DC.
69 /* INCLUDES ******************************************************************/
75 C_ASSERT(sizeof(XFORML
) == sizeof(XFORM
));
78 /* GLOBALS *******************************************************************/
80 const MATRIX gmxIdentity
=
82 FLOATOBJ_1
, FLOATOBJ_0
,
83 FLOATOBJ_0
, FLOATOBJ_1
,
84 FLOATOBJ_0
, FLOATOBJ_0
,
85 0, 0, XFORM_NO_TRANSLATION
|XFORM_FORMAT_LTOL
|XFORM_UNITY
|XFORM_SCALE
89 /* FUNCTIONS *****************************************************************/
93 DC_vFixIsotropicMapping(PDC pdc
)
98 SIZEL szlWindowExt
, szlViewportExt
;
99 ASSERT(pdc
->pdcattr
->iMapMode
== MM_ISOTROPIC
);
101 /* Get a pointer to the DC_ATTR */
102 pdcattr
= pdc
->pdcattr
;
104 /* Read the extents, we rely on non-null values */
105 szlWindowExt
= pdcattr
->szlWindowExt
;
106 szlViewportExt
= pdcattr
->szlViewportExt
;
108 /* Check if all values are valid */
109 if ((szlWindowExt
.cx
== 0) || (szlWindowExt
.cy
== 0) ||
110 (szlViewportExt
.cx
== 0) || (szlViewportExt
.cy
== 0))
112 /* Someone put rubbish into the fields, just ignore it. */
116 fx
= abs((LONG64
)szlWindowExt
.cx
* szlViewportExt
.cy
);
117 fy
= abs((LONG64
)szlWindowExt
.cy
* szlViewportExt
.cx
);
121 s
= (szlWindowExt
.cy
^ szlViewportExt
.cx
) > 0 ? 1 : -1;
122 pdcattr
->szlViewportExt
.cx
= (LONG
)(fx
* s
/ szlWindowExt
.cy
);
126 s
= (szlWindowExt
.cx
^ szlViewportExt
.cy
) > 0 ? 1 : -1;
127 pdcattr
->szlViewportExt
.cy
= (LONG
)(fy
* s
/ szlWindowExt
.cx
);
131 pdc
->pdcattr
->flXform
&= ~PAGE_EXTENTS_CHANGED
;
136 DC_vGetPageToDevice(PDC pdc
, MATRIX
*pmx
)
138 PDC_ATTR pdcattr
= pdc
->pdcattr
;
139 PSIZEL pszlViewPortExt
;
142 /* Get the viewport extension */
143 pszlViewPortExt
= DC_pszlViewportExt(pdc
);
145 /* Copy the window extension, so no one can mess with it */
146 szlWindowExt
= pdcattr
->szlWindowExt
;
148 /* No shearing / rotation */
149 FLOATOBJ_SetLong(&pmx
->efM12
, 0);
150 FLOATOBJ_SetLong(&pmx
->efM21
, 0);
152 /* Calculate scaling */
153 if (szlWindowExt
.cx
!= 0)
155 FLOATOBJ_SetLong(&pmx
->efM11
, pszlViewPortExt
->cx
);
156 FLOATOBJ_DivLong(&pmx
->efM11
, szlWindowExt
.cx
);
159 FLOATOBJ_SetLong(&pmx
->efM11
, 1);
161 if (szlWindowExt
.cy
!= 0)
163 FLOATOBJ_SetLong(&pmx
->efM22
, pszlViewPortExt
->cy
);
164 FLOATOBJ_DivLong(&pmx
->efM22
, szlWindowExt
.cy
);
167 FLOATOBJ_SetLong(&pmx
->efM22
, 1);
169 /* Calculate x offset */
170 FLOATOBJ_SetLong(&pmx
->efDx
, -pdcattr
->ptlWindowOrg
.x
);
171 FLOATOBJ_Mul(&pmx
->efDx
, &pmx
->efM11
);
172 FLOATOBJ_AddLong(&pmx
->efDx
, pdcattr
->ptlViewportOrg
.x
);
174 /* Calculate y offset */
175 FLOATOBJ_SetLong(&pmx
->efDy
, -pdcattr
->ptlWindowOrg
.y
);
176 FLOATOBJ_Mul(&pmx
->efDy
, &pmx
->efM22
);
177 FLOATOBJ_AddLong(&pmx
->efDy
, pdcattr
->ptlViewportOrg
.y
);
182 DC_vUpdateWorldToDevice(PDC pdc
)
184 XFORMOBJ xoPageToDevice
, xoWorldToPage
, xoWorldToDevice
;
185 MATRIX mxPageToDevice
;
187 // FIXME: make sure world-to-page is valid!
189 /* Construct a transformation to do the page-to-device conversion */
190 DC_vGetPageToDevice(pdc
, &mxPageToDevice
);
191 XFORMOBJ_vInit(&xoPageToDevice
, &mxPageToDevice
);
193 /* Recalculate the world-to-device xform */
194 XFORMOBJ_vInit(&xoWorldToPage
, &pdc
->pdcattr
->mxWorldToPage
);
195 XFORMOBJ_vInit(&xoWorldToDevice
, &pdc
->pdcattr
->mxWorldToDevice
);
196 XFORMOBJ_iCombine(&xoWorldToDevice
, &xoWorldToPage
, &xoPageToDevice
);
198 /* Reset the flags */
199 pdc
->pdcattr
->flXform
&= ~WORLD_XFORM_CHANGED
;
204 DC_vUpdateDeviceToWorld(PDC pdc
)
206 XFORMOBJ xoWorldToDevice
, xoDeviceToWorld
;
207 PMATRIX pmxWorldToDevice
;
209 /* Get the world-to-device translation */
210 pmxWorldToDevice
= DC_pmxWorldToDevice(pdc
);
211 XFORMOBJ_vInit(&xoWorldToDevice
, pmxWorldToDevice
);
213 /* Create inverse of world-to-device transformation */
214 XFORMOBJ_vInit(&xoDeviceToWorld
, &pdc
->pdcattr
->mxDeviceToWorld
);
215 if (XFORMOBJ_iInverse(&xoDeviceToWorld
, &xoWorldToDevice
) == DDI_ERROR
)
217 MX_Set0(&pdc
->pdcattr
->mxDeviceToWorld
);
222 pdc
->pdcattr
->flXform
&= ~DEVICE_TO_WORLD_INVALID
;
232 MATRIX mxDest
, mx1
, mx2
;
233 XFORMOBJ xoDest
, xo1
, xo2
;
235 /* Check for illegal parameters */
236 if (!pxformDest
|| !pxform1
|| !pxform2
) return FALSE
;
238 /* Initialize XFORMOBJs */
239 XFORMOBJ_vInit(&xoDest
, &mxDest
);
240 XFORMOBJ_vInit(&xo1
, &mx1
);
241 XFORMOBJ_vInit(&xo2
, &mx2
);
243 /* Convert the XFORMLs into XFORMOBJs */
244 XFORMOBJ_iSetXform(&xo1
, pxform1
);
245 XFORMOBJ_iSetXform(&xo2
, pxform2
);
248 XFORMOBJ_iCombine(&xoDest
, &xo1
, &xo2
);
250 /* Translate back into XFORML */
251 XFORMOBJ_iGetXform(&xoDest
, pxformDest
);
258 NtGdiCombineTransform(
259 LPXFORM UnsafeXFormResult
,
260 LPXFORM Unsafexform1
,
261 LPXFORM Unsafexform2
)
267 ProbeForWrite(UnsafeXFormResult
, sizeof(XFORM
), 1);
268 ProbeForRead(Unsafexform1
, sizeof(XFORM
), 1);
269 ProbeForRead(Unsafexform2
, sizeof(XFORM
), 1);
270 Ret
= GreCombineTransform((XFORML
*)UnsafeXFormResult
,
271 (XFORML
*)Unsafexform1
,
272 (XFORML
*)Unsafexform2
);
274 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
283 // FIXME: Should be XFORML and use XFORMOBJ functions directly
293 MATRIX mxPageToDevice
;
299 EngSetLastError(ERROR_INVALID_PARAMETER
);
303 pdc
= DC_LockDc(hdc
);
306 EngSetLastError(ERROR_INVALID_HANDLE
);
312 case GdiWorldSpaceToPageSpace
:
313 pmx
= DC_pmxWorldToPage(pdc
);
316 case GdiWorldSpaceToDeviceSpace
:
317 pmx
= DC_pmxWorldToDevice(pdc
);
320 case GdiDeviceSpaceToWorldSpace
:
321 pmx
= DC_pmxDeviceToWorld(pdc
);
324 case GdiPageSpaceToDeviceSpace
:
325 DC_vGetPageToDevice(pdc
, &mxPageToDevice
);
326 pmx
= &mxPageToDevice
;
330 DPRINT1("Unknown transform %lu\n", iXform
);
335 /* Initialize an XFORMOBJ */
336 XFORMOBJ_vInit(&xo
, pmx
);
340 ProbeForWrite(pXForm
, sizeof(XFORML
), 1);
341 XFORMOBJ_iGetXform(&xo
, (XFORML
*)pXForm
);
343 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
356 * Converts points from logical coordinates into device coordinates.
357 * Conversion depends on the mapping mode,
358 * world transfrom, viewport origin settings for the given device context.
359 * \param hDC device context.
360 * \param Points an array of POINT structures (in/out).
361 * \param Count number of elements in the array of POINT structures.
362 * \return TRUE if success, FALSE otherwise.
366 NtGdiTransformPoints(
381 if (!UnsafePtsIn
|| !UnsafePtOut
)
386 pdc
= DC_LockDc(hDC
);
392 Size
= Count
* sizeof(POINT
);
394 // FIXME: It would be wise to have a small stack buffer as optimization
395 Points
= ExAllocatePoolWithTag(PagedPool
, Size
, GDITAG_TEMP
);
399 EngSetLastError(ERROR_NOT_ENOUGH_MEMORY
);
405 ProbeForWrite(UnsafePtOut
, Size
, 1);
406 ProbeForRead(UnsafePtsIn
, Size
, 1);
407 RtlCopyMemory(Points
, UnsafePtsIn
, Size
);
409 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
411 /* Do not set last error */
412 _SEH2_YIELD(goto leave
;)
419 DC_vXformDeviceToWorld(pdc
, Count
, Points
, Points
);
423 DC_vXformWorldToDevice(pdc
, Count
, Points
, Points
);
426 case 2: // Not supported yet. Need testing.
429 EngSetLastError(ERROR_INVALID_PARAMETER
);
437 /* Pointer was already probed! */
438 RtlCopyMemory(UnsafePtOut
, Points
, Size
);
440 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
442 /* Do not set last error */
448 // If we are getting called that means User XForms is a mess!
452 ExFreePoolWithTag(Points
, GDITAG_TEMP
);
458 GreModifyWorldTransform(
460 const XFORML
*pxform
,
464 XFORMOBJ xoSrc
, xoDC
;
469 pdc
->pdcattr
->mxWorldToPage
= gmxIdentity
;
472 case MWT_LEFTMULTIPLY
:
473 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
474 XFORMOBJ_vInit(&xoSrc
, &mxSrc
);
475 if (XFORMOBJ_iSetXform(&xoSrc
, pxform
) == DDI_ERROR
)
477 XFORMOBJ_iCombine(&xoDC
, &xoSrc
, &xoDC
);
480 case MWT_RIGHTMULTIPLY
:
481 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
482 XFORMOBJ_vInit(&xoSrc
, &mxSrc
);
483 if (XFORMOBJ_iSetXform(&xoSrc
, pxform
) == DDI_ERROR
)
485 XFORMOBJ_iCombine(&xoDC
, &xoDC
, &xoSrc
);
489 XFORMOBJ_vInit(&xoDC
, &pdc
->pdcattr
->mxWorldToPage
);
490 if (XFORMOBJ_iSetXform(&xoDC
, pxform
) == DDI_ERROR
)
498 /*Set invalidation flags */
499 pdc
->pdcattr
->flXform
|= WORLD_XFORM_CHANGED
|DEVICE_TO_WORLD_INVALID
;
506 NtGdiModifyWorldTransform(
508 LPXFORM pxformUnsafe
,
515 pdc
= DC_LockDc(hdc
);
518 EngSetLastError(ERROR_INVALID_HANDLE
);
522 /* The xform is permitted to be NULL for MWT_IDENTITY.
523 * However, if it is not NULL, then it must be valid even
524 * though it is not used. */
525 if ((dwMode
!= MWT_IDENTITY
) && (pxformUnsafe
== NULL
))
531 if (pxformUnsafe
!= NULL
)
535 ProbeForRead(pxformUnsafe
, sizeof(XFORML
), 1);
536 RtlCopyMemory(&xformSafe
, pxformUnsafe
, sizeof(XFORML
));
538 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
545 /* Safe to handle kernel mode data. */
546 if (Ret
) Ret
= GreModifyWorldTransform(pdc
, &xformSafe
, dwMode
);
553 NtGdiOffsetViewportOrgEx(
561 NTSTATUS Status
= STATUS_SUCCESS
;
566 EngSetLastError(ERROR_INVALID_HANDLE
);
569 pdcattr
= dc
->pdcattr
;
575 ProbeForWrite(UnsafePoint
, sizeof(POINT
), 1);
576 UnsafePoint
->x
= pdcattr
->ptlViewportOrg
.x
;
577 UnsafePoint
->y
= pdcattr
->ptlViewportOrg
.y
;
578 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
580 UnsafePoint
->x
= -UnsafePoint
->x
;
583 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
585 Status
= _SEH2_GetExceptionCode();
589 if (!NT_SUCCESS(Status
))
591 SetLastNtError(Status
);
597 if (pdcattr
->dwLayout
& LAYOUT_RTL
)
601 pdcattr
->ptlViewportOrg
.x
+= XOffset
;
602 pdcattr
->ptlViewportOrg
.y
+= YOffset
;
603 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
| WORLD_XFORM_CHANGED
| DEVICE_TO_WORLD_INVALID
;
612 NtGdiOffsetWindowOrgEx(
624 EngSetLastError(ERROR_INVALID_HANDLE
);
627 pdcattr
= dc
->pdcattr
;
631 NTSTATUS Status
= STATUS_SUCCESS
;
635 ProbeForWrite(Point
, sizeof(POINT
), 1);
636 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
637 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
639 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
641 Status
= _SEH2_GetExceptionCode();
645 if (!NT_SUCCESS(Status
))
647 SetLastNtError(Status
);
653 pdcattr
->ptlWindowOrg
.x
+= XOffset
;
654 pdcattr
->ptlWindowOrg
.y
+= YOffset
;
655 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
| WORLD_XFORM_CHANGED
| DEVICE_TO_WORLD_INVALID
;
664 NtGdiScaleViewportExtEx(
677 pDC
= DC_LockDc(hDC
);
680 EngSetLastError(ERROR_INVALID_HANDLE
);
683 pdcattr
= pDC
->pdcattr
;
685 if (pdcattr
->iMapMode
> MM_TWIPS
)
687 if (Xdenom
&& Ydenom
)
689 DC_pszlViewportExt(pDC
);
690 X
= Xnum
* pdcattr
->szlViewportExt
.cx
/ Xdenom
;
693 Y
= Ynum
* pdcattr
->szlViewportExt
.cy
/ Ydenom
;
696 pdcattr
->szlViewportExt
.cx
= X
;
697 pdcattr
->szlViewportExt
.cy
= Y
;
698 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
;
700 IntMirrorWindowOrg(pDC
);
702 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
703 INVALIDATE_ATTRIBUTES
|
704 WORLD_XFORM_CHANGED
|
705 DEVICE_TO_WORLD_INVALID
);
707 if (pdcattr
->iMapMode
== MM_ISOTROPIC
)
709 DC_vFixIsotropicMapping(pDC
);
724 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
726 pSize
->cx
= pdcattr
->szlViewportExt
.cx
;
727 pSize
->cy
= pdcattr
->szlViewportExt
.cy
;
729 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
731 SetLastNtError(_SEH2_GetExceptionCode());
743 NtGdiScaleWindowExtEx(
756 pDC
= DC_LockDc(hDC
);
759 EngSetLastError(ERROR_INVALID_HANDLE
);
762 pdcattr
= pDC
->pdcattr
;
766 NTSTATUS Status
= STATUS_SUCCESS
;
770 ProbeForWrite(pSize
, sizeof(SIZE
), 1);
772 X
= pdcattr
->szlWindowExt
.cx
;
773 if (pdcattr
->dwLayout
& LAYOUT_RTL
) X
= -X
;
775 pSize
->cy
= pdcattr
->szlWindowExt
.cy
;
777 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
779 Status
= _SEH2_GetExceptionCode();
783 if (!NT_SUCCESS(Status
))
785 SetLastNtError(Status
);
791 if (pdcattr
->iMapMode
> MM_TWIPS
)
793 if (Xdenom
&& Ydenom
)
795 X
= Xnum
* pdcattr
->szlWindowExt
.cx
/ Xdenom
;
798 Y
= Ynum
* pdcattr
->szlWindowExt
.cy
/ Ydenom
;
801 pdcattr
->szlWindowExt
.cx
= X
;
802 pdcattr
->szlWindowExt
.cy
= Y
;
804 IntMirrorWindowOrg(pDC
);
806 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
807 INVALIDATE_ATTRIBUTES
|
808 WORLD_XFORM_CHANGED
|
809 DEVICE_TO_WORLD_INVALID
);
831 PDC_ATTR pdcattr
= dc
->pdcattr
;
833 if (MapMode
== pdcattr
->iMapMode
)
836 flXform
= pdcattr
->flXform
& ~(ISO_OR_ANISO_MAP_MODE
|PTOD_EFM22_NEGATIVE
|
837 PTOD_EFM11_NEGATIVE
|POSITIVE_Y_IS_UP
|PAGE_TO_DEVICE_SCALE_IDENTITY
|
838 PAGE_TO_DEVICE_IDENTITY
);
843 pdcattr
->szlWindowExt
.cx
= 1;
844 pdcattr
->szlWindowExt
.cy
= 1;
845 pdcattr
->szlViewportExt
.cx
= 1;
846 pdcattr
->szlViewportExt
.cy
= 1;
847 flXform
|= PAGE_TO_DEVICE_SCALE_IDENTITY
;
851 flXform
|= ISO_OR_ANISO_MAP_MODE
;
855 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 10;
856 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 10;
857 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
858 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
862 pdcattr
->szlWindowExt
.cx
= pdcattr
->szlVirtualDeviceMm
.cx
* 100;
863 pdcattr
->szlWindowExt
.cy
= pdcattr
->szlVirtualDeviceMm
.cy
* 100;
864 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
865 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
869 pdcattr
->szlWindowExt
.cx
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
870 pdcattr
->szlWindowExt
.cy
= MulDiv(1000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
871 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
872 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
876 pdcattr
->szlWindowExt
.cx
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
877 pdcattr
->szlWindowExt
.cy
= MulDiv(10000, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
878 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
879 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
883 pdcattr
->szlWindowExt
.cx
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cx
, 254);
884 pdcattr
->szlWindowExt
.cy
= MulDiv(14400, pdcattr
->szlVirtualDeviceMm
.cy
, 254);
885 pdcattr
->szlViewportExt
.cx
= pdcattr
->szlVirtualDevicePixel
.cx
;
886 pdcattr
->szlViewportExt
.cy
= -pdcattr
->szlVirtualDevicePixel
.cy
;
890 flXform
&= ~(PAGE_TO_DEVICE_IDENTITY
|POSITIVE_Y_IS_UP
);
891 flXform
|= ISO_OR_ANISO_MAP_MODE
;
898 /* Save the old map mode and set the new one */
899 iPrevMapMode
= pdcattr
->iMapMode
;
900 pdcattr
->iMapMode
= MapMode
;
902 /* Update xform flags */
903 pdcattr
->flXform
= flXform
| (PAGE_XLATE_CHANGED
| PAGE_EXTENTS_CHANGED
|
904 INVALIDATE_ATTRIBUTES
| DEVICE_TO_PAGE_INVALID
|
905 WORLD_XFORM_CHANGED
| DEVICE_TO_WORLD_INVALID
);
924 EngSetLastError(ERROR_INVALID_HANDLE
);
927 pdcattr
= dc
->pdcattr
;
931 Point
->x
= pdcattr
->ptlViewportOrg
.x
;
932 Point
->y
= pdcattr
->ptlViewportOrg
.y
;
935 pdcattr
->ptlViewportOrg
.x
= X
;
936 pdcattr
->ptlViewportOrg
.y
= Y
;
937 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
| WORLD_XFORM_CHANGED
| DEVICE_TO_WORLD_INVALID
;
945 NtGdiSetViewportOrgEx(
957 EngSetLastError(ERROR_INVALID_HANDLE
);
960 pdcattr
= dc
->pdcattr
;
964 NTSTATUS Status
= STATUS_SUCCESS
;
968 ProbeForWrite(Point
, sizeof(POINT
), 1);
969 Point
->x
= pdcattr
->ptlViewportOrg
.x
;
970 Point
->y
= pdcattr
->ptlViewportOrg
.y
;
972 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
974 Status
= _SEH2_GetExceptionCode();
978 if (!NT_SUCCESS(Status
))
980 SetLastNtError(Status
);
986 pdcattr
->ptlViewportOrg
.x
= X
;
987 pdcattr
->ptlViewportOrg
.y
= Y
;
988 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
| WORLD_XFORM_CHANGED
| DEVICE_TO_WORLD_INVALID
;
1006 dc
= DC_LockDc(hDC
);
1009 EngSetLastError(ERROR_INVALID_HANDLE
);
1012 pdcattr
= dc
->pdcattr
;
1016 NTSTATUS Status
= STATUS_SUCCESS
;
1020 ProbeForWrite(Point
, sizeof(POINT
), 1);
1021 Point
->x
= pdcattr
->ptlWindowOrg
.x
;
1022 Point
->y
= pdcattr
->ptlWindowOrg
.y
;
1024 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
1026 Status
= _SEH2_GetExceptionCode();
1030 if (!NT_SUCCESS(Status
))
1032 SetLastNtError(Status
);
1038 pdcattr
->ptlWindowOrg
.x
= X
;
1039 pdcattr
->ptlWindowOrg
.y
= Y
;
1040 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
| WORLD_XFORM_CHANGED
| DEVICE_TO_WORLD_INVALID
;
1048 // Mirror Window function.
1052 IntMirrorWindowOrg(PDC dc
)
1057 pdcattr
= dc
->pdcattr
;
1059 if (!(pdcattr
->dwLayout
& LAYOUT_RTL
))
1061 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
; // Flip it back.
1065 /* Copy the window extension, so no one can mess with it */
1066 cx
= pdcattr
->szlViewportExt
.cx
;
1067 if (cx
== 0) return;
1069 // WOrgx = wox - (Width - 1) * WExtx / VExtx
1071 X
= (dc
->erclWindow
.right
- dc
->erclWindow
.left
) - 1; // Get device width - 1
1073 X
= (X
* pdcattr
->szlWindowExt
.cx
) / cx
;
1075 pdcattr
->ptlWindowOrg
.x
= pdcattr
->lWindowOrgx
- X
; // Now set the inverted win origion.
1076 pdcattr
->flXform
|= PAGE_XLATE_CHANGED
| WORLD_XFORM_CHANGED
| DEVICE_TO_WORLD_INVALID
;
1088 PDC_ATTR pdcattr
= pdc
->pdcattr
;
1090 pdcattr
->dwLayout
= dwLayout
;
1092 if (!(dwLayout
& LAYOUT_ORIENTATIONMASK
)) return;
1094 if (dwLayout
& LAYOUT_RTL
)
1096 pdcattr
->iMapMode
= MM_ANISOTROPIC
;
1099 //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
1100 //pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x;
1103 // IntMirrorWindowOrg(pdc);
1105 // pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
1107 if (!(pdcattr
->flTextAlign
& TA_CENTER
)) pdcattr
->flTextAlign
|= TA_RIGHT
;
1109 if (pdc
->dclevel
.flPath
& DCPATH_CLOCKWISE
)
1110 pdc
->dclevel
.flPath
&= ~DCPATH_CLOCKWISE
;
1112 pdc
->dclevel
.flPath
|= DCPATH_CLOCKWISE
;
1114 pdcattr
->flXform
|= (PAGE_EXTENTS_CHANGED
|
1115 INVALIDATE_ATTRIBUTES
|
1116 WORLD_XFORM_CHANGED
|
1117 DEVICE_TO_WORLD_INVALID
);
1122 // The default is left to right. This function changes it to right to left, which
1123 // is the standard in Arabic and Hebrew cultures.
1138 pdc
= DC_LockDc(hdc
);
1141 EngSetLastError(ERROR_INVALID_HANDLE
);
1145 dwOldLayout
= pdc
->pdcattr
->dwLayout
;
1146 DC_vSetLayout(pdc
, wox
, dwLayout
);
1157 NtGdiGetDeviceWidth(
1162 dc
= DC_LockDc(hdc
);
1165 EngSetLastError(ERROR_INVALID_HANDLE
);
1168 Ret
= dc
->erclWindow
.right
- dc
->erclWindow
.left
;
1178 NtGdiMirrorWindowOrg(
1182 dc
= DC_LockDc(hdc
);
1185 EngSetLastError(ERROR_INVALID_HANDLE
);
1188 IntMirrorWindowOrg(dc
);
1200 IN INT cxVirtualDevice
,
1201 IN INT cyVirtualDevice
)
1206 if (!cxVirtualDevice
|| !cyVirtualDevice
)
1211 dc
= DC_LockDc(hdc
);
1212 if (!dc
) return FALSE
;
1214 pdcattr
= dc
->pdcattr
;
1216 pdcattr
->szlVirtualDeviceSize
.cx
= cxVirtualDevice
;
1217 pdcattr
->szlVirtualDeviceSize
.cy
= cyVirtualDevice
;
1229 NtGdiSetVirtualResolution(
1231 IN INT cxVirtualDevicePixel
,
1232 IN INT cyVirtualDevicePixel
,
1233 IN INT cxVirtualDeviceMm
,
1234 IN INT cyVirtualDeviceMm
)
1239 /* Check parameters (all zeroes resets to real resolution) */
1240 if (cxVirtualDevicePixel
== 0 && cyVirtualDevicePixel
== 0 &&
1241 cxVirtualDeviceMm
== 0 && cyVirtualDeviceMm
== 0)
1243 cxVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, HORZRES
);
1244 cyVirtualDevicePixel
= NtGdiGetDeviceCaps(hdc
, VERTRES
);
1245 cxVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, HORZSIZE
);
1246 cyVirtualDeviceMm
= NtGdiGetDeviceCaps(hdc
, VERTSIZE
);
1248 else if (cxVirtualDevicePixel
== 0 || cyVirtualDevicePixel
== 0 ||
1249 cxVirtualDeviceMm
== 0 || cyVirtualDeviceMm
== 0)
1254 dc
= DC_LockDc(hdc
);
1255 if (!dc
) return FALSE
;
1257 pdcattr
= dc
->pdcattr
;
1259 pdcattr
->szlVirtualDevicePixel
.cx
= cxVirtualDevicePixel
;
1260 pdcattr
->szlVirtualDevicePixel
.cy
= cyVirtualDevicePixel
;
1261 pdcattr
->szlVirtualDeviceMm
.cx
= cxVirtualDeviceMm
;
1262 pdcattr
->szlVirtualDeviceMm
.cy
= cyVirtualDeviceMm
;
1264 // DC_vUpdateXforms(dc);
1271 DC_vGetAspectRatioFilter(PDC pDC
, LPSIZE AspectRatio
)
1273 if (pDC
->pdcattr
->flFontMapper
& 1) // TRUE assume 1.
1275 // "This specifies that Windows should only match fonts that have the
1276 // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1277 AspectRatio
->cx
= pDC
->ppdev
->gdiinfo
.ulLogPixelsX
;
1278 AspectRatio
->cy
= pDC
->ppdev
->gdiinfo
.ulLogPixelsY
;
1282 AspectRatio
->cx
= 0;
1283 AspectRatio
->cy
= 0;
1296 PSIZEL pszlViewportExt
;
1300 EngSetLastError(ERROR_INVALID_PARAMETER
);
1304 pdc
= DC_LockDc(hDC
);
1307 EngSetLastError(ERROR_INVALID_HANDLE
);
1313 case GdiGetViewPortExt
:
1314 pszlViewportExt
= DC_pszlViewportExt(pdc
);
1315 Point
->x
= pszlViewportExt
->cx
;
1316 Point
->y
= pszlViewportExt
->cy
;
1319 case GdiGetWindowExt
:
1320 Point
->x
= pdc
->pdcattr
->szlWindowExt
.cx
;
1321 Point
->y
= pdc
->pdcattr
->szlWindowExt
.cy
;
1324 case GdiGetViewPortOrg
:
1325 *Point
= pdc
->pdcattr
->ptlViewportOrg
;
1328 case GdiGetWindowOrg
:
1329 *Point
= pdc
->pdcattr
->ptlWindowOrg
;
1333 *Point
= pdc
->ptlDCOrig
;
1336 case GdiGetAspectRatioFilter
:
1337 DC_vGetAspectRatioFilter(pdc
, &Size
);
1343 EngSetLastError(ERROR_INVALID_PARAMETER
);
1358 _In_opt_ PRECTL Rect
)
1362 dc
= DC_LockDc(hdc
);
1363 if (!dc
) return FALSE
;
1366 dc
->ptlDCOrig
.x
= x
;
1367 dc
->ptlDCOrig
.y
= y
;
1369 /* Recalculate Fill Origin */
1370 dc
->ptlFillOrigin
.x
= dc
->dclevel
.ptlBrushOrigin
.x
+ x
;
1371 dc
->ptlFillOrigin
.y
= dc
->dclevel
.ptlBrushOrigin
.y
+ y
;
1373 /* Set DC Window Rectangle */
1375 dc
->erclWindow
= *Rect
;
1385 _Out_ PPOINTL Point
,
1390 dc
= DC_LockDc(hdc
);
1391 if (!dc
) return FALSE
;
1393 /* Retrieve DC Window Rectangle without a check */
1394 *Rect
= dc
->erclWindow
;
1398 /* Use default call for DC Origin and parameter checking */
1399 return GreGetDCPoint( hdc
, GdiGetDCOrg
, Point
);
1406 _Out_ LPSIZE lpSize
)
1408 return GreGetDCPoint(hdc
, GdiGetWindowExt
, (PPOINTL
)lpSize
);
1413 GreGetViewportExtEx(
1415 _Out_ LPSIZE lpSize
)
1417 return GreGetDCPoint(hdc
, GdiGetViewPortExt
, (PPOINTL
)lpSize
);
1431 EngSetLastError(ERROR_INVALID_PARAMETER
);
1435 Ret
= GreGetDCPoint(hDC
, iPoint
, &SafePoint
);
1440 ProbeForWrite(Point
, sizeof(POINT
), 1);
1443 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)