xref: /reactos/win32ss/gdi/ntgdi/coord.c (revision 3435c3b5)
1 /*
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)
8  */
9 
10 /* Coordinate translation overview
11  * -------------------------------
12  *
13  * Windows uses 3 different coordinate systems, referred to as world space,
14  * page space and device space.
15  *
16  * 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.
20  *
21  * Page space:
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
33  * - MM_ISOTROPIC:
34  * - MM_ANISOTROPIC:
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.
45  *
46  * World space:
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.
55  *
56  * User mode data:
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.
67  */
68 
69 /* INCLUDES ******************************************************************/
70 
71 #include <win32k.h>
72 
73 #define NDEBUG
74 #include <debug.h>
75 C_ASSERT(sizeof(XFORML) == sizeof(XFORM));
76 
77 
78 /* GLOBALS *******************************************************************/
79 
80 const MATRIX gmxIdentity =
81 {
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
86 };
87 
88 
89 /* FUNCTIONS *****************************************************************/
90 
91 VOID
92 FASTCALL
93 DC_vFixIsotropicMapping(PDC pdc)
94 {
95     PDC_ATTR pdcattr;
96     LONG64 fx, fy;
97     LONG s;
98     SIZEL szlWindowExt, szlViewportExt;
99     ASSERT(pdc->pdcattr->iMapMode == MM_ISOTROPIC);
100 
101     /* Get a pointer to the DC_ATTR */
102     pdcattr = pdc->pdcattr;
103 
104     /* Read the extents, we rely on non-null values */
105     szlWindowExt = pdcattr->szlWindowExt;
106     szlViewportExt = pdcattr->szlViewportExt;
107 
108     /* Check if all values are valid */
109     if ((szlWindowExt.cx == 0) || (szlWindowExt.cy == 0) ||
110         (szlViewportExt.cx == 0) || (szlViewportExt.cy == 0))
111     {
112         /* Someone put rubbish into the fields, just ignore it. */
113         return;
114     }
115 
116     fx = abs((LONG64)szlWindowExt.cx * szlViewportExt.cy);
117     fy = abs((LONG64)szlWindowExt.cy * szlViewportExt.cx);
118 
119     if (fx < fy)
120     {
121         s = (szlWindowExt.cy ^ szlViewportExt.cx) > 0 ? 1 : -1;
122         pdcattr->szlViewportExt.cx = (LONG)(fx * s / szlWindowExt.cy);
123     }
124     else if (fx > fy)
125     {
126         s = (szlWindowExt.cx ^ szlViewportExt.cy) > 0 ? 1 : -1;
127         pdcattr->szlViewportExt.cy = (LONG)(fy * s / szlWindowExt.cx);
128     }
129 
130     /* Reset the flag */
131     pdc->pdcattr->flXform &= ~PAGE_EXTENTS_CHANGED;
132 }
133 
134 VOID
135 FASTCALL
136 DC_vGetPageToDevice(PDC pdc, MATRIX *pmx)
137 {
138     PDC_ATTR pdcattr = pdc->pdcattr;
139     PSIZEL pszlViewPortExt;
140     SIZEL szlWindowExt;
141 
142     /* Get the viewport extension */
143     pszlViewPortExt = DC_pszlViewportExt(pdc);
144 
145     /* Copy the window extension, so no one can mess with it */
146     szlWindowExt = pdcattr->szlWindowExt;
147 
148     /* No shearing / rotation */
149     FLOATOBJ_SetLong(&pmx->efM12, 0);
150     FLOATOBJ_SetLong(&pmx->efM21, 0);
151 
152     /* Calculate scaling */
153     if (szlWindowExt.cx != 0)
154     {
155         FLOATOBJ_SetLong(&pmx->efM11, pszlViewPortExt->cx);
156         FLOATOBJ_DivLong(&pmx->efM11, szlWindowExt.cx);
157     }
158     else
159         FLOATOBJ_SetLong(&pmx->efM11, 1);
160 
161     if (szlWindowExt.cy != 0)
162     {
163         FLOATOBJ_SetLong(&pmx->efM22, pszlViewPortExt->cy);
164         FLOATOBJ_DivLong(&pmx->efM22, szlWindowExt.cy);
165     }
166     else
167         FLOATOBJ_SetLong(&pmx->efM22, 1);
168 
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);
173 
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);
178 }
179 
180 VOID
181 FASTCALL
182 DC_vUpdateWorldToDevice(PDC pdc)
183 {
184     XFORMOBJ xoPageToDevice, xoWorldToPage, xoWorldToDevice;
185     MATRIX mxPageToDevice;
186 
187     // FIXME: make sure world-to-page is valid!
188 
189     /* Construct a transformation to do the page-to-device conversion */
190     DC_vGetPageToDevice(pdc, &mxPageToDevice);
191     XFORMOBJ_vInit(&xoPageToDevice, &mxPageToDevice);
192 
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);
197 
198     /* Reset the flags */
199     pdc->pdcattr->flXform &= ~WORLD_XFORM_CHANGED;
200 }
201 
202 VOID
203 FASTCALL
204 DC_vUpdateDeviceToWorld(PDC pdc)
205 {
206     XFORMOBJ xoWorldToDevice, xoDeviceToWorld;
207     PMATRIX pmxWorldToDevice;
208 
209     /* Get the world-to-device translation */
210     pmxWorldToDevice = DC_pmxWorldToDevice(pdc);
211     XFORMOBJ_vInit(&xoWorldToDevice, pmxWorldToDevice);
212 
213     /* Create inverse of world-to-device transformation */
214     XFORMOBJ_vInit(&xoDeviceToWorld, &pdc->pdcattr->mxDeviceToWorld);
215     if (XFORMOBJ_iInverse(&xoDeviceToWorld, &xoWorldToDevice) == DDI_ERROR)
216     {
217         MX_Set0(&pdc->pdcattr->mxDeviceToWorld);
218         return;
219     }
220 
221     /* Reset the flag */
222     pdc->pdcattr->flXform &= ~DEVICE_TO_WORLD_INVALID;
223 }
224 
225 BOOL
226 NTAPI
227 GreCombineTransform(
228     XFORML *pxformDest,
229     XFORML *pxform1,
230     XFORML *pxform2)
231 {
232     MATRIX mxDest, mx1, mx2;
233     XFORMOBJ xoDest, xo1, xo2;
234 
235     /* Check for illegal parameters */
236     if (!pxformDest || !pxform1 || !pxform2) return FALSE;
237 
238     /* Initialize XFORMOBJs */
239     XFORMOBJ_vInit(&xoDest, &mxDest);
240     XFORMOBJ_vInit(&xo1, &mx1);
241     XFORMOBJ_vInit(&xo2, &mx2);
242 
243     /* Convert the XFORMLs into XFORMOBJs */
244     XFORMOBJ_iSetXform(&xo1, pxform1);
245     XFORMOBJ_iSetXform(&xo2, pxform2);
246 
247     /* Combine them */
248     XFORMOBJ_iCombine(&xoDest, &xo1, &xo2);
249 
250     /* Translate back into XFORML */
251     XFORMOBJ_iGetXform(&xoDest, pxformDest);
252 
253     return TRUE;
254 }
255 
256 BOOL
257 APIENTRY
258 NtGdiCombineTransform(
259     LPXFORM UnsafeXFormResult,
260     LPXFORM Unsafexform1,
261     LPXFORM Unsafexform2)
262 {
263     BOOL Ret;
264 
265     _SEH2_TRY
266     {
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);
273     }
274     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
275     {
276         Ret = FALSE;
277     }
278     _SEH2_END;
279 
280     return Ret;
281 }
282 
283 // FIXME: Should be XFORML and use XFORMOBJ functions directly
284 BOOL
285 APIENTRY
286 NtGdiGetTransform(
287     HDC hdc,
288     DWORD iXform,
289     LPXFORM pXForm)
290 {
291     PDC pdc;
292     BOOL ret = TRUE;
293     MATRIX mxPageToDevice;
294     XFORMOBJ xo;
295     PMATRIX pmx;
296 
297     if (!pXForm)
298     {
299         EngSetLastError(ERROR_INVALID_PARAMETER);
300         return FALSE;
301     }
302 
303     pdc = DC_LockDc(hdc);
304     if (!pdc)
305     {
306         EngSetLastError(ERROR_INVALID_HANDLE);
307         return FALSE;
308     }
309 
310     switch (iXform)
311     {
312         case GdiWorldSpaceToPageSpace:
313             pmx = DC_pmxWorldToPage(pdc);
314             break;
315 
316         case GdiWorldSpaceToDeviceSpace:
317             pmx = DC_pmxWorldToDevice(pdc);
318             break;
319 
320         case GdiDeviceSpaceToWorldSpace:
321             pmx = DC_pmxDeviceToWorld(pdc);
322             break;
323 
324         case GdiPageSpaceToDeviceSpace:
325             DC_vGetPageToDevice(pdc, &mxPageToDevice);
326             pmx = &mxPageToDevice;
327             break;
328 
329         default:
330             DPRINT1("Unknown transform %lu\n", iXform);
331             ret = FALSE;
332             goto leave;
333     }
334 
335     /* Initialize an XFORMOBJ */
336     XFORMOBJ_vInit(&xo, pmx);
337 
338     _SEH2_TRY
339     {
340         ProbeForWrite(pXForm, sizeof(XFORML), 1);
341         XFORMOBJ_iGetXform(&xo, (XFORML*)pXForm);
342     }
343     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
344     {
345         ret = FALSE;
346     }
347     _SEH2_END;
348 
349 leave:
350     DC_UnlockDc(pdc);
351     return ret;
352 }
353 
354 
355 /*!
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.
363 */
364 BOOL
365 APIENTRY
366 NtGdiTransformPoints(
367     HDC hDC,
368     PPOINT UnsafePtsIn,
369     PPOINT UnsafePtOut,
370     INT Count,
371     INT iMode)
372 {
373     PDC pdc;
374     LPPOINT Points;
375     ULONG Size;
376     BOOL ret = TRUE;
377 
378     if (Count <= 0)
379         return TRUE;
380 
381     if (!UnsafePtsIn || !UnsafePtOut)
382     {
383         return FALSE;
384     }
385 
386     pdc = DC_LockDc(hDC);
387     if (!pdc)
388     {
389         return FALSE;
390     }
391 
392     Size = Count * sizeof(POINT);
393 
394     // FIXME: It would be wise to have a small stack buffer as optimization
395     Points = ExAllocatePoolWithTag(PagedPool, Size, GDITAG_TEMP);
396     if (!Points)
397     {
398         DC_UnlockDc(pdc);
399         EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
400         return FALSE;
401     }
402 
403     _SEH2_TRY
404     {
405         ProbeForWrite(UnsafePtOut, Size, 1);
406         ProbeForRead(UnsafePtsIn, Size, 1);
407         RtlCopyMemory(Points, UnsafePtsIn, Size);
408     }
409     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
410     {
411         /* Do not set last error */
412         _SEH2_YIELD(goto leave;)
413     }
414     _SEH2_END;
415 
416     switch (iMode)
417     {
418         case GdiDpToLp:
419             DC_vXformDeviceToWorld(pdc, Count, Points, Points);
420             break;
421 
422         case GdiLpToDp:
423             DC_vXformWorldToDevice(pdc, Count, Points, Points);
424             break;
425 
426         case 2: // Not supported yet. Need testing.
427         default:
428         {
429             EngSetLastError(ERROR_INVALID_PARAMETER);
430             ret = FALSE;
431             goto leave;
432         }
433     }
434 
435     _SEH2_TRY
436     {
437         /* Pointer was already probed! */
438         RtlCopyMemory(UnsafePtOut, Points, Size);
439     }
440     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
441     {
442         /* Do not set last error */
443         ret = 0;
444     }
445     _SEH2_END;
446 
447 //
448 // If we are getting called that means User XForms is a mess!
449 //
450 leave:
451     DC_UnlockDc(pdc);
452     ExFreePoolWithTag(Points, GDITAG_TEMP);
453     return ret;
454 }
455 
456 BOOL
457 NTAPI
458 GreModifyWorldTransform(
459     PDC pdc,
460     const XFORML *pxform,
461     DWORD dwMode)
462 {
463     MATRIX mxSrc;
464     XFORMOBJ xoSrc, xoDC;
465 
466     switch (dwMode)
467     {
468         case MWT_IDENTITY:
469             pdc->pdcattr->mxWorldToPage = gmxIdentity;
470             break;
471 
472         case MWT_LEFTMULTIPLY:
473             XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage);
474             XFORMOBJ_vInit(&xoSrc, &mxSrc);
475             if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR)
476                 return FALSE;
477             XFORMOBJ_iCombine(&xoDC, &xoSrc, &xoDC);
478             break;
479 
480         case MWT_RIGHTMULTIPLY:
481             XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage);
482             XFORMOBJ_vInit(&xoSrc, &mxSrc);
483             if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR)
484                 return FALSE;
485             XFORMOBJ_iCombine(&xoDC, &xoDC, &xoSrc);
486             break;
487 
488         case MWT_SET:
489             XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage);
490             if (XFORMOBJ_iSetXform(&xoDC, pxform) == DDI_ERROR)
491                 return FALSE;
492             break;
493 
494         default:
495             return FALSE;
496     }
497 
498     /*Set invalidation flags */
499     pdc->pdcattr->flXform |= WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID;
500 
501     return TRUE;
502 }
503 
504 BOOL
505 APIENTRY
506 NtGdiModifyWorldTransform(
507     HDC hdc,
508     LPXFORM pxformUnsafe,
509     DWORD dwMode)
510 {
511     PDC pdc;
512     XFORML xformSafe;
513     BOOL Ret = TRUE;
514 
515     pdc = DC_LockDc(hdc);
516     if (!pdc)
517     {
518         EngSetLastError(ERROR_INVALID_HANDLE);
519         return FALSE;
520     }
521 
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))
526     {
527         DC_UnlockDc(pdc);
528         return FALSE;
529     }
530 
531     if (pxformUnsafe != NULL)
532     {
533         _SEH2_TRY
534         {
535             ProbeForRead(pxformUnsafe, sizeof(XFORML), 1);
536             RtlCopyMemory(&xformSafe, pxformUnsafe, sizeof(XFORML));
537         }
538         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
539         {
540             Ret = FALSE;
541         }
542         _SEH2_END;
543     }
544 
545     /* Safe to handle kernel mode data. */
546     if (Ret) Ret = GreModifyWorldTransform(pdc, &xformSafe, dwMode);
547     DC_UnlockDc(pdc);
548     return Ret;
549 }
550 
551 BOOL
552 APIENTRY
553 NtGdiOffsetViewportOrgEx(
554     HDC hDC,
555     int XOffset,
556     int YOffset,
557     LPPOINT UnsafePoint)
558 {
559     PDC      dc;
560     PDC_ATTR pdcattr;
561     NTSTATUS Status = STATUS_SUCCESS;
562 
563     dc = DC_LockDc(hDC);
564     if (!dc)
565     {
566         EngSetLastError(ERROR_INVALID_HANDLE);
567         return FALSE;
568     }
569     pdcattr = dc->pdcattr;
570 
571     if (UnsafePoint)
572     {
573         _SEH2_TRY
574         {
575             ProbeForWrite(UnsafePoint, sizeof(POINT), 1);
576             UnsafePoint->x = pdcattr->ptlViewportOrg.x;
577             UnsafePoint->y = pdcattr->ptlViewportOrg.y;
578             if (pdcattr->dwLayout & LAYOUT_RTL)
579             {
580                 UnsafePoint->x = -UnsafePoint->x;
581             }
582         }
583         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
584         {
585             Status = _SEH2_GetExceptionCode();
586         }
587         _SEH2_END;
588 
589         if (!NT_SUCCESS(Status))
590         {
591             SetLastNtError(Status);
592             DC_UnlockDc(dc);
593             return FALSE;
594         }
595     }
596 
597     if (pdcattr->dwLayout & LAYOUT_RTL)
598     {
599         XOffset = -XOffset;
600     }
601     pdcattr->ptlViewportOrg.x += XOffset;
602     pdcattr->ptlViewportOrg.y += YOffset;
603     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
604 
605     DC_UnlockDc(dc);
606 
607     return TRUE;
608 }
609 
610 BOOL
611 APIENTRY
612 NtGdiOffsetWindowOrgEx(
613     HDC hDC,
614     int XOffset,
615     int YOffset,
616     LPPOINT Point)
617 {
618     PDC dc;
619     PDC_ATTR pdcattr;
620 
621     dc = DC_LockDc(hDC);
622     if (!dc)
623     {
624         EngSetLastError(ERROR_INVALID_HANDLE);
625         return FALSE;
626     }
627     pdcattr = dc->pdcattr;
628 
629     if (Point)
630     {
631         NTSTATUS Status = STATUS_SUCCESS;
632 
633         _SEH2_TRY
634         {
635             ProbeForWrite(Point, sizeof(POINT), 1);
636             Point->x = pdcattr->ptlWindowOrg.x;
637             Point->y = pdcattr->ptlWindowOrg.y;
638         }
639         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
640         {
641             Status = _SEH2_GetExceptionCode();
642         }
643         _SEH2_END;
644 
645         if (!NT_SUCCESS(Status))
646         {
647             SetLastNtError(Status);
648             DC_UnlockDc(dc);
649             return FALSE;
650         }
651     }
652 
653     pdcattr->ptlWindowOrg.x += XOffset;
654     pdcattr->ptlWindowOrg.y += YOffset;
655     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
656 
657     DC_UnlockDc(dc);
658 
659     return TRUE;
660 }
661 
662 BOOL
663 APIENTRY
664 NtGdiScaleViewportExtEx(
665     HDC hDC,
666     int Xnum,
667     int Xdenom,
668     int Ynum,
669     int Ydenom,
670     LPSIZE pSize)
671 {
672     PDC pDC;
673     PDC_ATTR pdcattr;
674     BOOL Ret = FALSE;
675     LONG X, Y;
676 
677     pDC = DC_LockDc(hDC);
678     if (!pDC)
679     {
680         EngSetLastError(ERROR_INVALID_HANDLE);
681         return FALSE;
682     }
683     pdcattr = pDC->pdcattr;
684 
685     if (pdcattr->iMapMode > MM_TWIPS)
686     {
687         if (Xdenom && Ydenom)
688         {
689             DC_pszlViewportExt(pDC);
690             X = Xnum * pdcattr->szlViewportExt.cx / Xdenom;
691             if (X)
692             {
693                 Y = Ynum * pdcattr->szlViewportExt.cy / Ydenom;
694                 if (Y)
695                 {
696                     pdcattr->szlViewportExt.cx = X;
697                     pdcattr->szlViewportExt.cy = Y;
698                     pdcattr->flXform |= PAGE_XLATE_CHANGED;
699 
700                     IntMirrorWindowOrg(pDC);
701 
702                     pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
703                                          INVALIDATE_ATTRIBUTES |
704                                          WORLD_XFORM_CHANGED |
705                                          DEVICE_TO_WORLD_INVALID);
706 
707                     if (pdcattr->iMapMode == MM_ISOTROPIC)
708                     {
709                         DC_vFixIsotropicMapping(pDC);
710                     }
711 
712                     Ret = TRUE;
713                 }
714             }
715         }
716     }
717     else
718         Ret = TRUE;
719 
720     if (pSize)
721     {
722         _SEH2_TRY
723         {
724             ProbeForWrite(pSize, sizeof(SIZE), 1);
725 
726             pSize->cx = pdcattr->szlViewportExt.cx;
727             pSize->cy = pdcattr->szlViewportExt.cy;
728         }
729         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
730         {
731             SetLastNtError(_SEH2_GetExceptionCode());
732             Ret = FALSE;
733         }
734         _SEH2_END;
735     }
736 
737     DC_UnlockDc(pDC);
738     return Ret;
739 }
740 
741 BOOL
742 APIENTRY
743 NtGdiScaleWindowExtEx(
744     HDC hDC,
745     int Xnum,
746     int Xdenom,
747     int Ynum,
748     int Ydenom,
749     LPSIZE pSize)
750 {
751     PDC pDC;
752     PDC_ATTR pdcattr;
753     BOOL Ret = FALSE;
754     LONG X, Y;
755 
756     pDC = DC_LockDc(hDC);
757     if (!pDC)
758     {
759         EngSetLastError(ERROR_INVALID_HANDLE);
760         return FALSE;
761     }
762     pdcattr = pDC->pdcattr;
763 
764     if (pSize)
765     {
766         NTSTATUS Status = STATUS_SUCCESS;
767 
768         _SEH2_TRY
769         {
770             ProbeForWrite(pSize, sizeof(SIZE), 1);
771 
772             X = pdcattr->szlWindowExt.cx;
773             if (pdcattr->dwLayout & LAYOUT_RTL) X = -X;
774             pSize->cx = X;
775             pSize->cy = pdcattr->szlWindowExt.cy;
776         }
777         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
778         {
779             Status = _SEH2_GetExceptionCode();
780         }
781         _SEH2_END;
782 
783         if (!NT_SUCCESS(Status))
784         {
785             SetLastNtError(Status);
786             DC_UnlockDc(pDC);
787             return FALSE;
788         }
789     }
790 
791     if (pdcattr->iMapMode > MM_TWIPS)
792     {
793         if (Xdenom && Ydenom)
794         {
795             X = Xnum * pdcattr->szlWindowExt.cx / Xdenom;
796             if (X)
797             {
798                 Y = Ynum * pdcattr->szlWindowExt.cy / Ydenom;
799                 if (Y)
800                 {
801                     pdcattr->szlWindowExt.cx = X;
802                     pdcattr->szlWindowExt.cy = Y;
803 
804                     IntMirrorWindowOrg(pDC);
805 
806                     pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
807                                          INVALIDATE_ATTRIBUTES |
808                                          WORLD_XFORM_CHANGED |
809                                          DEVICE_TO_WORLD_INVALID);
810 
811                     Ret = TRUE;
812                 }
813             }
814         }
815     }
816     else
817         Ret = TRUE;
818 
819     DC_UnlockDc(pDC);
820     return Ret;
821 }
822 
823 int
824 APIENTRY
825 IntGdiSetMapMode(
826     PDC dc,
827     int MapMode)
828 {
829     INT iPrevMapMode;
830     FLONG flXform;
831     PDC_ATTR pdcattr = dc->pdcattr;
832 
833     if (MapMode == pdcattr->iMapMode)
834         return MapMode;
835 
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);
839 
840     switch (MapMode)
841     {
842         case MM_TEXT:
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;
848             break;
849 
850         case MM_ISOTROPIC:
851             flXform |= ISO_OR_ANISO_MAP_MODE;
852             /* Fall through */
853 
854         case MM_LOMETRIC:
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;
859             break;
860 
861         case MM_HIMETRIC:
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;
866             break;
867 
868         case MM_LOENGLISH:
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;
873             break;
874 
875         case MM_HIENGLISH:
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;
880             break;
881 
882         case MM_TWIPS:
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;
887             break;
888 
889         case MM_ANISOTROPIC:
890             flXform &= ~(PAGE_TO_DEVICE_IDENTITY|POSITIVE_Y_IS_UP);
891             flXform |= ISO_OR_ANISO_MAP_MODE;
892             break;
893 
894         default:
895             return 0;
896     }
897 
898     /* Save the old map mode and set the new one */
899     iPrevMapMode = pdcattr->iMapMode;
900     pdcattr->iMapMode = MapMode;
901 
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);
906 
907     return iPrevMapMode;
908 }
909 
910 BOOL
911 FASTCALL
912 GreSetViewportOrgEx(
913     HDC hDC,
914     int X,
915     int Y,
916     LPPOINT Point)
917 {
918     PDC dc;
919     PDC_ATTR pdcattr;
920 
921     dc = DC_LockDc(hDC);
922     if (!dc)
923     {
924         EngSetLastError(ERROR_INVALID_HANDLE);
925         return FALSE;
926     }
927     pdcattr = dc->pdcattr;
928 
929     if (Point)
930     {
931        Point->x = pdcattr->ptlViewportOrg.x;
932        Point->y = pdcattr->ptlViewportOrg.y;
933     }
934 
935     pdcattr->ptlViewportOrg.x = X;
936     pdcattr->ptlViewportOrg.y = Y;
937     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
938 
939     DC_UnlockDc(dc);
940     return TRUE;
941 }
942 
943 BOOL
944 APIENTRY
945 NtGdiSetViewportOrgEx(
946     HDC hDC,
947     int X,
948     int Y,
949     LPPOINT Point)
950 {
951     PDC dc;
952     PDC_ATTR pdcattr;
953 
954     dc = DC_LockDc(hDC);
955     if (!dc)
956     {
957         EngSetLastError(ERROR_INVALID_HANDLE);
958         return FALSE;
959     }
960     pdcattr = dc->pdcattr;
961 
962     if (Point)
963     {
964         NTSTATUS Status = STATUS_SUCCESS;
965 
966         _SEH2_TRY
967         {
968             ProbeForWrite(Point, sizeof(POINT), 1);
969             Point->x = pdcattr->ptlViewportOrg.x;
970             Point->y = pdcattr->ptlViewportOrg.y;
971         }
972         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
973         {
974             Status = _SEH2_GetExceptionCode();
975         }
976         _SEH2_END;
977 
978         if (!NT_SUCCESS(Status))
979         {
980             SetLastNtError(Status);
981             DC_UnlockDc(dc);
982             return FALSE;
983         }
984     }
985 
986     pdcattr->ptlViewportOrg.x = X;
987     pdcattr->ptlViewportOrg.y = Y;
988     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
989 
990     DC_UnlockDc(dc);
991 
992     return TRUE;
993 }
994 
995 BOOL
996 APIENTRY
997 NtGdiSetWindowOrgEx(
998     HDC hDC,
999     int X,
1000     int Y,
1001     LPPOINT Point)
1002 {
1003     PDC dc;
1004     PDC_ATTR pdcattr;
1005 
1006     dc = DC_LockDc(hDC);
1007     if (!dc)
1008     {
1009         EngSetLastError(ERROR_INVALID_HANDLE);
1010         return FALSE;
1011     }
1012     pdcattr = dc->pdcattr;
1013 
1014     if (Point)
1015     {
1016         NTSTATUS Status = STATUS_SUCCESS;
1017 
1018         _SEH2_TRY
1019         {
1020             ProbeForWrite(Point, sizeof(POINT), 1);
1021             Point->x = pdcattr->ptlWindowOrg.x;
1022             Point->y = pdcattr->ptlWindowOrg.y;
1023         }
1024         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1025         {
1026             Status = _SEH2_GetExceptionCode();
1027         }
1028         _SEH2_END;
1029 
1030         if (!NT_SUCCESS(Status))
1031         {
1032             SetLastNtError(Status);
1033             DC_UnlockDc(dc);
1034             return FALSE;
1035         }
1036     }
1037 
1038     pdcattr->ptlWindowOrg.x = X;
1039     pdcattr->ptlWindowOrg.y = Y;
1040     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
1041 
1042     DC_UnlockDc(dc);
1043 
1044     return TRUE;
1045 }
1046 
1047 //
1048 // Mirror Window function.
1049 //
1050 VOID
1051 FASTCALL
1052 IntMirrorWindowOrg(PDC dc)
1053 {
1054     PDC_ATTR pdcattr;
1055     LONG X, cx;
1056 
1057     pdcattr = dc->pdcattr;
1058 
1059     if (!(pdcattr->dwLayout & LAYOUT_RTL))
1060     {
1061         pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx; // Flip it back.
1062         return;
1063     }
1064 
1065     /* Copy the window extension, so no one can mess with it */
1066     cx = pdcattr->szlViewportExt.cx;
1067     if (cx == 0) return;
1068     //
1069     // WOrgx = wox - (Width - 1) * WExtx / VExtx
1070     //
1071     X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1
1072 
1073     X = (X * pdcattr->szlWindowExt.cx) / cx;
1074 
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;
1077 
1078     return;
1079 }
1080 
1081 VOID
1082 NTAPI
1083 DC_vSetLayout(
1084     IN PDC pdc,
1085     IN LONG wox,
1086     IN DWORD dwLayout)
1087 {
1088     PDC_ATTR pdcattr = pdc->pdcattr;
1089 
1090     pdcattr->dwLayout = dwLayout;
1091 
1092     if (!(dwLayout & LAYOUT_ORIENTATIONMASK)) return;
1093 
1094     if (dwLayout & LAYOUT_RTL)
1095     {
1096         pdcattr->iMapMode = MM_ANISOTROPIC;
1097     }
1098 
1099     //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
1100     //pdcattr->ptlWindowOrg.x  = -pdcattr->ptlWindowOrg.x;
1101 
1102     //if (wox == -1)
1103     //    IntMirrorWindowOrg(pdc);
1104     //else
1105     //    pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
1106 
1107     if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT;
1108 
1109     if (pdc->dclevel.flPath & DCPATH_CLOCKWISE)
1110         pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
1111     else
1112         pdc->dclevel.flPath |= DCPATH_CLOCKWISE;
1113 
1114     pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
1115                          INVALIDATE_ATTRIBUTES |
1116                          WORLD_XFORM_CHANGED |
1117                          DEVICE_TO_WORLD_INVALID);
1118 }
1119 
1120 // NtGdiSetLayout
1121 //
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.
1124 //
1125 /*
1126  * @implemented
1127  */
1128 DWORD
1129 APIENTRY
1130 NtGdiSetLayout(
1131     IN HDC hdc,
1132     IN LONG wox,
1133     IN DWORD dwLayout)
1134 {
1135     PDC pdc;
1136     DWORD dwOldLayout;
1137 
1138     pdc = DC_LockDc(hdc);
1139     if (!pdc)
1140     {
1141         EngSetLastError(ERROR_INVALID_HANDLE);
1142         return GDI_ERROR;
1143     }
1144 
1145     dwOldLayout = pdc->pdcattr->dwLayout;
1146     DC_vSetLayout(pdc, wox, dwLayout);
1147 
1148     DC_UnlockDc(pdc);
1149     return dwOldLayout;
1150 }
1151 
1152 /*
1153  * @implemented
1154  */
1155 LONG
1156 APIENTRY
1157 NtGdiGetDeviceWidth(
1158     IN HDC hdc)
1159 {
1160     PDC dc;
1161     LONG Ret;
1162     dc = DC_LockDc(hdc);
1163     if (!dc)
1164     {
1165         EngSetLastError(ERROR_INVALID_HANDLE);
1166         return 0;
1167     }
1168     Ret = dc->erclWindow.right - dc->erclWindow.left;
1169     DC_UnlockDc(dc);
1170     return Ret;
1171 }
1172 
1173 /*
1174  * @implemented
1175  */
1176 BOOL
1177 APIENTRY
1178 NtGdiMirrorWindowOrg(
1179     IN HDC hdc)
1180 {
1181     PDC dc;
1182     dc = DC_LockDc(hdc);
1183     if (!dc)
1184     {
1185         EngSetLastError(ERROR_INVALID_HANDLE);
1186         return FALSE;
1187     }
1188     IntMirrorWindowOrg(dc);
1189     DC_UnlockDc(dc);
1190     return TRUE;
1191 }
1192 
1193 /*
1194  * @implemented
1195  */
1196 BOOL
1197 APIENTRY
1198 NtGdiSetSizeDevice(
1199     IN HDC hdc,
1200     IN INT cxVirtualDevice,
1201     IN INT cyVirtualDevice)
1202 {
1203     PDC dc;
1204     PDC_ATTR pdcattr;
1205 
1206     if (!cxVirtualDevice || !cyVirtualDevice)
1207     {
1208         return FALSE;
1209     }
1210 
1211     dc = DC_LockDc(hdc);
1212     if (!dc) return FALSE;
1213 
1214     pdcattr = dc->pdcattr;
1215 
1216     pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice;
1217     pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice;
1218 
1219     DC_UnlockDc(dc);
1220 
1221     return TRUE;
1222 }
1223 
1224 /*
1225  * @implemented
1226  */
1227 BOOL
1228 APIENTRY
1229 NtGdiSetVirtualResolution(
1230     IN HDC hdc,
1231     IN INT cxVirtualDevicePixel,
1232     IN INT cyVirtualDevicePixel,
1233     IN INT cxVirtualDeviceMm,
1234     IN INT cyVirtualDeviceMm)
1235 {
1236     PDC dc;
1237     PDC_ATTR pdcattr;
1238 
1239     /* Check parameters (all zeroes resets to real resolution) */
1240     if (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 &&
1241         cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0)
1242     {
1243         cxVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, HORZRES);
1244         cyVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, VERTRES);
1245         cxVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, HORZSIZE);
1246         cyVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, VERTSIZE);
1247     }
1248     else if (cxVirtualDevicePixel == 0 || cyVirtualDevicePixel == 0 ||
1249              cxVirtualDeviceMm == 0 || cyVirtualDeviceMm == 0)
1250     {
1251         return FALSE;
1252     }
1253 
1254     dc = DC_LockDc(hdc);
1255     if (!dc) return FALSE;
1256 
1257     pdcattr = dc->pdcattr;
1258 
1259     pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel;
1260     pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel;
1261     pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm;
1262     pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm;
1263 
1264 //    DC_vUpdateXforms(dc);
1265     DC_UnlockDc(dc);
1266     return TRUE;
1267 }
1268 
1269 static
1270 VOID FASTCALL
1271 DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio)
1272 {
1273     if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1.
1274     {
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;
1279     }
1280     else
1281     {
1282         AspectRatio->cx = 0;
1283         AspectRatio->cy = 0;
1284     }
1285 }
1286 
1287 BOOL APIENTRY
1288 GreGetDCPoint(
1289     HDC hDC,
1290     UINT iPoint,
1291     PPOINTL Point)
1292 {
1293     BOOL Ret = TRUE;
1294     DC *pdc;
1295     SIZE Size;
1296     PSIZEL pszlViewportExt;
1297 
1298     if (!Point)
1299     {
1300         EngSetLastError(ERROR_INVALID_PARAMETER);
1301         return FALSE;
1302     }
1303 
1304     pdc = DC_LockDc(hDC);
1305     if (!pdc)
1306     {
1307         EngSetLastError(ERROR_INVALID_HANDLE);
1308         return FALSE;
1309     }
1310 
1311     switch (iPoint)
1312     {
1313         case GdiGetViewPortExt:
1314             pszlViewportExt = DC_pszlViewportExt(pdc);
1315             Point->x = pszlViewportExt->cx;
1316             Point->y = pszlViewportExt->cy;
1317             break;
1318 
1319         case GdiGetWindowExt:
1320             Point->x = pdc->pdcattr->szlWindowExt.cx;
1321             Point->y = pdc->pdcattr->szlWindowExt.cy;
1322             break;
1323 
1324         case GdiGetViewPortOrg:
1325             *Point = pdc->pdcattr->ptlViewportOrg;
1326             break;
1327 
1328         case GdiGetWindowOrg:
1329             *Point = pdc->pdcattr->ptlWindowOrg;
1330             break;
1331 
1332         case GdiGetDCOrg:
1333             *Point = pdc->ptlDCOrig;
1334             break;
1335 
1336         case GdiGetAspectRatioFilter:
1337             DC_vGetAspectRatioFilter(pdc, &Size);
1338             Point->x = Size.cx;
1339             Point->y = Size.cy;
1340             break;
1341 
1342         default:
1343             EngSetLastError(ERROR_INVALID_PARAMETER);
1344             Ret = FALSE;
1345             break;
1346     }
1347 
1348     DC_UnlockDc(pdc);
1349     return Ret;
1350 }
1351 
1352 BOOL
1353 WINAPI
1354 GreSetDCOrg(
1355     _In_ HDC hdc,
1356     _In_ LONG x,
1357     _In_ LONG y,
1358     _In_opt_ PRECTL Rect)
1359 {
1360     PDC dc;
1361 
1362     dc = DC_LockDc(hdc);
1363     if (!dc) return FALSE;
1364 
1365     /* Set DC Origin */
1366     dc->ptlDCOrig.x = x;
1367     dc->ptlDCOrig.y = y;
1368 
1369     /* Recalculate Fill Origin */
1370     dc->ptlFillOrigin.x = dc->dclevel.ptlBrushOrigin.x + x;
1371     dc->ptlFillOrigin.y = dc->dclevel.ptlBrushOrigin.y + y;
1372 
1373     /* Set DC Window Rectangle */
1374     if (Rect)
1375         dc->erclWindow = *Rect;
1376 
1377     DC_UnlockDc(dc);
1378     return TRUE;
1379 }
1380 
1381 BOOL
1382 WINAPI
1383 GreGetDCOrgEx(
1384     _In_ HDC hdc,
1385     _Out_ PPOINTL Point,
1386     _Out_ PRECTL Rect)
1387 {
1388     PDC dc;
1389 
1390     dc = DC_LockDc(hdc);
1391     if (!dc) return FALSE;
1392 
1393     /* Retrieve DC Window Rectangle without a check */
1394     *Rect = dc->erclWindow;
1395 
1396     DC_UnlockDc(dc);
1397 
1398     /* Use default call for DC Origin and parameter checking */
1399     return GreGetDCPoint( hdc, GdiGetDCOrg, Point);
1400 }
1401 
1402 BOOL
1403 WINAPI
1404 GreGetWindowExtEx(
1405     _In_ HDC hdc,
1406     _Out_ LPSIZE lpSize)
1407 {
1408     return GreGetDCPoint(hdc, GdiGetWindowExt, (PPOINTL)lpSize);
1409 }
1410 
1411 BOOL
1412 WINAPI
1413 GreGetViewportExtEx(
1414     _In_ HDC hdc,
1415     _Out_ LPSIZE lpSize)
1416 {
1417     return GreGetDCPoint(hdc, GdiGetViewPortExt, (PPOINTL)lpSize);
1418 }
1419 
1420 BOOL APIENTRY
1421 NtGdiGetDCPoint(
1422     HDC hDC,
1423     UINT iPoint,
1424     PPOINTL Point)
1425 {
1426     BOOL Ret;
1427     POINTL SafePoint;
1428 
1429     if (!Point)
1430     {
1431         EngSetLastError(ERROR_INVALID_PARAMETER);
1432         return FALSE;
1433     }
1434 
1435     Ret = GreGetDCPoint(hDC, iPoint, &SafePoint);
1436     if (Ret)
1437     {
1438         _SEH2_TRY
1439         {
1440             ProbeForWrite(Point, sizeof(POINT), 1);
1441             *Point = SafePoint;
1442         }
1443         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1444         {
1445             Ret = FALSE;
1446         }
1447         _SEH2_END;
1448     }
1449 
1450     return Ret;
1451 }
1452 
1453 /* EOF */
1454