xref: /reactos/win32ss/gdi/ntgdi/coord.c (revision cdf90707)
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             ret = INTERNAL_APPLY_MATRIX(DC_pmxDeviceToWorld(pdc), Points, Count);
420             break;
421 
422         case GdiLpToDp:
423             ret = INTERNAL_APPLY_MATRIX(DC_pmxWorldToDevice(pdc), Points, Count);
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     if (ret)
436     {
437         _SEH2_TRY
438         {
439             /* Pointer was already probed! */
440             RtlCopyMemory(UnsafePtOut, Points, Size);
441         }
442         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
443         {
444             /* Do not set last error */
445             ret = FALSE;
446         }
447         _SEH2_END;
448     }
449 
450 //
451 // If we are getting called that means User XForms is a mess!
452 //
453 leave:
454     DC_UnlockDc(pdc);
455     ExFreePoolWithTag(Points, GDITAG_TEMP);
456     return ret;
457 }
458 
459 BOOL
460 NTAPI
461 GreModifyWorldTransform(
462     PDC pdc,
463     const XFORML *pxform,
464     DWORD dwMode)
465 {
466     MATRIX mxSrc;
467     XFORMOBJ xoSrc, xoDC;
468 
469     switch (dwMode)
470     {
471         case MWT_IDENTITY:
472             pdc->pdcattr->mxWorldToPage = gmxIdentity;
473             break;
474 
475         case MWT_LEFTMULTIPLY:
476             XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage);
477             XFORMOBJ_vInit(&xoSrc, &mxSrc);
478             if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR)
479                 return FALSE;
480             XFORMOBJ_iCombine(&xoDC, &xoSrc, &xoDC);
481             break;
482 
483         case MWT_RIGHTMULTIPLY:
484             XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage);
485             XFORMOBJ_vInit(&xoSrc, &mxSrc);
486             if (XFORMOBJ_iSetXform(&xoSrc, pxform) == DDI_ERROR)
487                 return FALSE;
488             XFORMOBJ_iCombine(&xoDC, &xoDC, &xoSrc);
489             break;
490 
491         case MWT_SET:
492             XFORMOBJ_vInit(&xoDC, &pdc->pdcattr->mxWorldToPage);
493             if (XFORMOBJ_iSetXform(&xoDC, pxform) == DDI_ERROR)
494                 return FALSE;
495             break;
496 
497         default:
498             return FALSE;
499     }
500 
501     /*Set invalidation flags */
502     pdc->pdcattr->flXform |= WORLD_XFORM_CHANGED|DEVICE_TO_WORLD_INVALID;
503 
504     return TRUE;
505 }
506 
507 BOOL
508 APIENTRY
509 NtGdiModifyWorldTransform(
510     HDC hdc,
511     LPXFORM pxformUnsafe,
512     DWORD dwMode)
513 {
514     PDC pdc;
515     XFORML xformSafe;
516     BOOL Ret = TRUE;
517 
518     pdc = DC_LockDc(hdc);
519     if (!pdc)
520     {
521         EngSetLastError(ERROR_INVALID_HANDLE);
522         return FALSE;
523     }
524 
525     /* The xform is permitted to be NULL for MWT_IDENTITY.
526      * However, if it is not NULL, then it must be valid even
527      * though it is not used. */
528     if ((dwMode != MWT_IDENTITY) && (pxformUnsafe == NULL))
529     {
530         DC_UnlockDc(pdc);
531         return FALSE;
532     }
533 
534     if (pxformUnsafe != NULL)
535     {
536         _SEH2_TRY
537         {
538             ProbeForRead(pxformUnsafe, sizeof(XFORML), 1);
539             RtlCopyMemory(&xformSafe, pxformUnsafe, sizeof(XFORML));
540         }
541         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
542         {
543             Ret = FALSE;
544         }
545         _SEH2_END;
546     }
547 
548     /* Safe to handle kernel mode data. */
549     if (Ret) Ret = GreModifyWorldTransform(pdc, &xformSafe, dwMode);
550     DC_UnlockDc(pdc);
551     return Ret;
552 }
553 
554 BOOL
555 APIENTRY
556 NtGdiOffsetViewportOrgEx(
557     HDC hDC,
558     int XOffset,
559     int YOffset,
560     LPPOINT UnsafePoint)
561 {
562     PDC      dc;
563     PDC_ATTR pdcattr;
564     NTSTATUS Status = STATUS_SUCCESS;
565 
566     dc = DC_LockDc(hDC);
567     if (!dc)
568     {
569         EngSetLastError(ERROR_INVALID_HANDLE);
570         return FALSE;
571     }
572     pdcattr = dc->pdcattr;
573 
574     if (UnsafePoint)
575     {
576         _SEH2_TRY
577         {
578             ProbeForWrite(UnsafePoint, sizeof(POINT), 1);
579             UnsafePoint->x = pdcattr->ptlViewportOrg.x;
580             UnsafePoint->y = pdcattr->ptlViewportOrg.y;
581             if (pdcattr->dwLayout & LAYOUT_RTL)
582             {
583                 UnsafePoint->x = -UnsafePoint->x;
584             }
585         }
586         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
587         {
588             Status = _SEH2_GetExceptionCode();
589         }
590         _SEH2_END;
591 
592         if (!NT_SUCCESS(Status))
593         {
594             SetLastNtError(Status);
595             DC_UnlockDc(dc);
596             return FALSE;
597         }
598     }
599 
600     if (pdcattr->dwLayout & LAYOUT_RTL)
601     {
602         XOffset = -XOffset;
603     }
604     pdcattr->ptlViewportOrg.x += XOffset;
605     pdcattr->ptlViewportOrg.y += YOffset;
606     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
607 
608     DC_UnlockDc(dc);
609 
610     return TRUE;
611 }
612 
613 BOOL
614 APIENTRY
615 NtGdiOffsetWindowOrgEx(
616     HDC hDC,
617     int XOffset,
618     int YOffset,
619     LPPOINT Point)
620 {
621     PDC dc;
622     PDC_ATTR pdcattr;
623 
624     dc = DC_LockDc(hDC);
625     if (!dc)
626     {
627         EngSetLastError(ERROR_INVALID_HANDLE);
628         return FALSE;
629     }
630     pdcattr = dc->pdcattr;
631 
632     if (Point)
633     {
634         NTSTATUS Status = STATUS_SUCCESS;
635 
636         _SEH2_TRY
637         {
638             ProbeForWrite(Point, sizeof(POINT), 1);
639             Point->x = pdcattr->ptlWindowOrg.x;
640             Point->y = pdcattr->ptlWindowOrg.y;
641         }
642         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
643         {
644             Status = _SEH2_GetExceptionCode();
645         }
646         _SEH2_END;
647 
648         if (!NT_SUCCESS(Status))
649         {
650             SetLastNtError(Status);
651             DC_UnlockDc(dc);
652             return FALSE;
653         }
654     }
655 
656     pdcattr->ptlWindowOrg.x += XOffset;
657     pdcattr->ptlWindowOrg.y += YOffset;
658     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
659 
660     DC_UnlockDc(dc);
661 
662     return TRUE;
663 }
664 
665 BOOL
666 APIENTRY
667 NtGdiScaleViewportExtEx(
668     HDC hDC,
669     int Xnum,
670     int Xdenom,
671     int Ynum,
672     int Ydenom,
673     LPSIZE pSize)
674 {
675     PDC pDC;
676     PDC_ATTR pdcattr;
677     BOOL Ret = FALSE;
678     LONG X, Y;
679 
680     pDC = DC_LockDc(hDC);
681     if (!pDC)
682     {
683         EngSetLastError(ERROR_INVALID_HANDLE);
684         return FALSE;
685     }
686     pdcattr = pDC->pdcattr;
687 
688     if (pdcattr->iMapMode > MM_TWIPS)
689     {
690         if (Xdenom && Ydenom)
691         {
692             DC_pszlViewportExt(pDC);
693             X = Xnum * pdcattr->szlViewportExt.cx / Xdenom;
694             if (X)
695             {
696                 Y = Ynum * pdcattr->szlViewportExt.cy / Ydenom;
697                 if (Y)
698                 {
699                     pdcattr->szlViewportExt.cx = X;
700                     pdcattr->szlViewportExt.cy = Y;
701                     pdcattr->flXform |= PAGE_XLATE_CHANGED;
702 
703                     IntMirrorWindowOrg(pDC);
704 
705                     pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
706                                          INVALIDATE_ATTRIBUTES |
707                                          WORLD_XFORM_CHANGED |
708                                          DEVICE_TO_WORLD_INVALID);
709 
710                     if (pdcattr->iMapMode == MM_ISOTROPIC)
711                     {
712                         DC_vFixIsotropicMapping(pDC);
713                     }
714 
715                     Ret = TRUE;
716                 }
717             }
718         }
719     }
720     else
721         Ret = TRUE;
722 
723     if (pSize)
724     {
725         _SEH2_TRY
726         {
727             ProbeForWrite(pSize, sizeof(SIZE), 1);
728 
729             pSize->cx = pdcattr->szlViewportExt.cx;
730             pSize->cy = pdcattr->szlViewportExt.cy;
731         }
732         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
733         {
734             SetLastNtError(_SEH2_GetExceptionCode());
735             Ret = FALSE;
736         }
737         _SEH2_END;
738     }
739 
740     DC_UnlockDc(pDC);
741     return Ret;
742 }
743 
744 BOOL
745 APIENTRY
746 NtGdiScaleWindowExtEx(
747     HDC hDC,
748     int Xnum,
749     int Xdenom,
750     int Ynum,
751     int Ydenom,
752     LPSIZE pSize)
753 {
754     PDC pDC;
755     PDC_ATTR pdcattr;
756     BOOL Ret = FALSE;
757     LONG X, Y;
758 
759     pDC = DC_LockDc(hDC);
760     if (!pDC)
761     {
762         EngSetLastError(ERROR_INVALID_HANDLE);
763         return FALSE;
764     }
765     pdcattr = pDC->pdcattr;
766 
767     if (pSize)
768     {
769         NTSTATUS Status = STATUS_SUCCESS;
770 
771         _SEH2_TRY
772         {
773             ProbeForWrite(pSize, sizeof(SIZE), 1);
774 
775             X = pdcattr->szlWindowExt.cx;
776             if (pdcattr->dwLayout & LAYOUT_RTL) X = -X;
777             pSize->cx = X;
778             pSize->cy = pdcattr->szlWindowExt.cy;
779         }
780         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
781         {
782             Status = _SEH2_GetExceptionCode();
783         }
784         _SEH2_END;
785 
786         if (!NT_SUCCESS(Status))
787         {
788             SetLastNtError(Status);
789             DC_UnlockDc(pDC);
790             return FALSE;
791         }
792     }
793 
794     if (pdcattr->iMapMode > MM_TWIPS)
795     {
796         if (Xdenom && Ydenom)
797         {
798             X = Xnum * pdcattr->szlWindowExt.cx / Xdenom;
799             if (X)
800             {
801                 Y = Ynum * pdcattr->szlWindowExt.cy / Ydenom;
802                 if (Y)
803                 {
804                     pdcattr->szlWindowExt.cx = X;
805                     pdcattr->szlWindowExt.cy = Y;
806 
807                     IntMirrorWindowOrg(pDC);
808 
809                     pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
810                                          INVALIDATE_ATTRIBUTES |
811                                          WORLD_XFORM_CHANGED |
812                                          DEVICE_TO_WORLD_INVALID);
813 
814                     Ret = TRUE;
815                 }
816             }
817         }
818     }
819     else
820         Ret = TRUE;
821 
822     DC_UnlockDc(pDC);
823     return Ret;
824 }
825 
826 int
827 APIENTRY
828 IntGdiSetMapMode(
829     PDC dc,
830     int MapMode)
831 {
832     INT iPrevMapMode;
833     FLONG flXform;
834     PDC_ATTR pdcattr = dc->pdcattr;
835 
836     if (MapMode == pdcattr->iMapMode)
837         return MapMode;
838 
839     flXform = pdcattr->flXform & ~(ISO_OR_ANISO_MAP_MODE|PTOD_EFM22_NEGATIVE|
840         PTOD_EFM11_NEGATIVE|POSITIVE_Y_IS_UP|PAGE_TO_DEVICE_SCALE_IDENTITY|
841         PAGE_TO_DEVICE_IDENTITY);
842 
843     switch (MapMode)
844     {
845         case MM_TEXT:
846             pdcattr->szlWindowExt.cx = 1;
847             pdcattr->szlWindowExt.cy = 1;
848             pdcattr->szlViewportExt.cx = 1;
849             pdcattr->szlViewportExt.cy = 1;
850             flXform |= PAGE_TO_DEVICE_SCALE_IDENTITY;
851             break;
852 
853         case MM_ISOTROPIC:
854             flXform |= ISO_OR_ANISO_MAP_MODE;
855             /* Fall through */
856 
857         case MM_LOMETRIC:
858             pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 10;
859             pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 10;
860             pdcattr->szlViewportExt.cx =  pdcattr->szlVirtualDevicePixel.cx;
861             pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy;
862             break;
863 
864         case MM_HIMETRIC:
865             pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 100;
866             pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 100;
867             pdcattr->szlViewportExt.cx =  pdcattr->szlVirtualDevicePixel.cx;
868             pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy;
869             break;
870 
871         case MM_LOENGLISH:
872             pdcattr->szlWindowExt.cx = EngMulDiv(1000, pdcattr->szlVirtualDeviceMm.cx, 254);
873             pdcattr->szlWindowExt.cy = EngMulDiv(1000, pdcattr->szlVirtualDeviceMm.cy, 254);
874             pdcattr->szlViewportExt.cx =  pdcattr->szlVirtualDevicePixel.cx;
875             pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy;
876             break;
877 
878         case MM_HIENGLISH:
879             pdcattr->szlWindowExt.cx = EngMulDiv(10000, pdcattr->szlVirtualDeviceMm.cx, 254);
880             pdcattr->szlWindowExt.cy = EngMulDiv(10000, pdcattr->szlVirtualDeviceMm.cy, 254);
881             pdcattr->szlViewportExt.cx =  pdcattr->szlVirtualDevicePixel.cx;
882             pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy;
883             break;
884 
885         case MM_TWIPS:
886             pdcattr->szlWindowExt.cx = EngMulDiv(14400, pdcattr->szlVirtualDeviceMm.cx, 254);
887             pdcattr->szlWindowExt.cy = EngMulDiv(14400, pdcattr->szlVirtualDeviceMm.cy, 254);
888             pdcattr->szlViewportExt.cx =  pdcattr->szlVirtualDevicePixel.cx;
889             pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy;
890             break;
891 
892         case MM_ANISOTROPIC:
893             flXform &= ~(PAGE_TO_DEVICE_IDENTITY|POSITIVE_Y_IS_UP);
894             flXform |= ISO_OR_ANISO_MAP_MODE;
895             break;
896 
897         default:
898             return 0;
899     }
900 
901     /* Save the old map mode and set the new one */
902     iPrevMapMode = pdcattr->iMapMode;
903     pdcattr->iMapMode = MapMode;
904 
905     /* Update xform flags */
906     pdcattr->flXform = flXform | (PAGE_XLATE_CHANGED | PAGE_EXTENTS_CHANGED |
907                                   INVALIDATE_ATTRIBUTES | DEVICE_TO_PAGE_INVALID |
908                                   WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID);
909 
910     return iPrevMapMode;
911 }
912 
913 BOOL
914 FASTCALL
915 GreSetViewportOrgEx(
916     HDC hDC,
917     int X,
918     int Y,
919     LPPOINT Point)
920 {
921     PDC dc;
922     PDC_ATTR pdcattr;
923 
924     dc = DC_LockDc(hDC);
925     if (!dc)
926     {
927         EngSetLastError(ERROR_INVALID_HANDLE);
928         return FALSE;
929     }
930     pdcattr = dc->pdcattr;
931 
932     if (Point)
933     {
934        Point->x = pdcattr->ptlViewportOrg.x;
935        Point->y = pdcattr->ptlViewportOrg.y;
936     }
937 
938     pdcattr->ptlViewportOrg.x = X;
939     pdcattr->ptlViewportOrg.y = Y;
940     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
941 
942     DC_UnlockDc(dc);
943     return TRUE;
944 }
945 
946 BOOL
947 APIENTRY
948 NtGdiSetViewportOrgEx(
949     HDC hDC,
950     int X,
951     int Y,
952     LPPOINT Point)
953 {
954     PDC dc;
955     PDC_ATTR pdcattr;
956 
957     dc = DC_LockDc(hDC);
958     if (!dc)
959     {
960         EngSetLastError(ERROR_INVALID_HANDLE);
961         return FALSE;
962     }
963     pdcattr = dc->pdcattr;
964 
965     if (Point)
966     {
967         NTSTATUS Status = STATUS_SUCCESS;
968 
969         _SEH2_TRY
970         {
971             ProbeForWrite(Point, sizeof(POINT), 1);
972             Point->x = pdcattr->ptlViewportOrg.x;
973             Point->y = pdcattr->ptlViewportOrg.y;
974         }
975         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
976         {
977             Status = _SEH2_GetExceptionCode();
978         }
979         _SEH2_END;
980 
981         if (!NT_SUCCESS(Status))
982         {
983             SetLastNtError(Status);
984             DC_UnlockDc(dc);
985             return FALSE;
986         }
987     }
988 
989     pdcattr->ptlViewportOrg.x = X;
990     pdcattr->ptlViewportOrg.y = Y;
991     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
992 
993     DC_UnlockDc(dc);
994 
995     return TRUE;
996 }
997 
998 BOOL
999 APIENTRY
1000 NtGdiSetWindowOrgEx(
1001     HDC hDC,
1002     int X,
1003     int Y,
1004     LPPOINT Point)
1005 {
1006     PDC dc;
1007     PDC_ATTR pdcattr;
1008 
1009     dc = DC_LockDc(hDC);
1010     if (!dc)
1011     {
1012         EngSetLastError(ERROR_INVALID_HANDLE);
1013         return FALSE;
1014     }
1015     pdcattr = dc->pdcattr;
1016 
1017     if (Point)
1018     {
1019         NTSTATUS Status = STATUS_SUCCESS;
1020 
1021         _SEH2_TRY
1022         {
1023             ProbeForWrite(Point, sizeof(POINT), 1);
1024             Point->x = pdcattr->ptlWindowOrg.x;
1025             Point->y = pdcattr->ptlWindowOrg.y;
1026         }
1027         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1028         {
1029             Status = _SEH2_GetExceptionCode();
1030         }
1031         _SEH2_END;
1032 
1033         if (!NT_SUCCESS(Status))
1034         {
1035             SetLastNtError(Status);
1036             DC_UnlockDc(dc);
1037             return FALSE;
1038         }
1039     }
1040 
1041     pdcattr->ptlWindowOrg.x = X;
1042     pdcattr->ptlWindowOrg.y = Y;
1043     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
1044 
1045     DC_UnlockDc(dc);
1046 
1047     return TRUE;
1048 }
1049 
1050 //
1051 // Mirror Window function.
1052 //
1053 VOID
1054 FASTCALL
1055 IntMirrorWindowOrg(PDC dc)
1056 {
1057     PDC_ATTR pdcattr;
1058     LONG X, cx;
1059 
1060     pdcattr = dc->pdcattr;
1061 
1062     if (!(pdcattr->dwLayout & LAYOUT_RTL))
1063     {
1064         pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx; // Flip it back.
1065         return;
1066     }
1067 
1068     /* Copy the window extension, so no one can mess with it */
1069     cx = pdcattr->szlViewportExt.cx;
1070     if (cx == 0) return;
1071     //
1072     // WOrgx = wox - (Width - 1) * WExtx / VExtx
1073     //
1074     X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1
1075 
1076     X = (X * pdcattr->szlWindowExt.cx) / cx;
1077 
1078     pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx - X; // Now set the inverted win origion.
1079     pdcattr->flXform |= PAGE_XLATE_CHANGED | WORLD_XFORM_CHANGED | DEVICE_TO_WORLD_INVALID;
1080 
1081     return;
1082 }
1083 
1084 VOID
1085 NTAPI
1086 DC_vSetLayout(
1087     IN PDC pdc,
1088     IN LONG wox,
1089     IN DWORD dwLayout)
1090 {
1091     PDC_ATTR pdcattr = pdc->pdcattr;
1092 
1093     pdcattr->dwLayout = dwLayout;
1094 
1095     if (!(dwLayout & LAYOUT_ORIENTATIONMASK)) return;
1096 
1097     if (dwLayout & LAYOUT_RTL)
1098     {
1099         pdcattr->iMapMode = MM_ANISOTROPIC;
1100     }
1101 
1102     //pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
1103     //pdcattr->ptlWindowOrg.x  = -pdcattr->ptlWindowOrg.x;
1104 
1105     //if (wox == -1)
1106     //    IntMirrorWindowOrg(pdc);
1107     //else
1108     //    pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
1109 
1110     if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT;
1111 
1112     if (pdc->dclevel.flPath & DCPATH_CLOCKWISE)
1113         pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
1114     else
1115         pdc->dclevel.flPath |= DCPATH_CLOCKWISE;
1116 
1117     pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
1118                          INVALIDATE_ATTRIBUTES |
1119                          WORLD_XFORM_CHANGED |
1120                          DEVICE_TO_WORLD_INVALID);
1121 }
1122 
1123 // NtGdiSetLayout
1124 //
1125 // The default is left to right. This function changes it to right to left, which
1126 // is the standard in Arabic and Hebrew cultures.
1127 //
1128 /*
1129  * @implemented
1130  */
1131 DWORD
1132 APIENTRY
1133 NtGdiSetLayout(
1134     IN HDC hdc,
1135     IN LONG wox,
1136     IN DWORD dwLayout)
1137 {
1138     PDC pdc;
1139     DWORD dwOldLayout;
1140 
1141     pdc = DC_LockDc(hdc);
1142     if (!pdc)
1143     {
1144         EngSetLastError(ERROR_INVALID_HANDLE);
1145         return GDI_ERROR;
1146     }
1147 
1148     dwOldLayout = pdc->pdcattr->dwLayout;
1149     DC_vSetLayout(pdc, wox, dwLayout);
1150 
1151     DC_UnlockDc(pdc);
1152     return dwOldLayout;
1153 }
1154 
1155 /*
1156  * @implemented
1157  */
1158 LONG
1159 APIENTRY
1160 NtGdiGetDeviceWidth(
1161     IN HDC hdc)
1162 {
1163     PDC dc;
1164     LONG Ret;
1165     dc = DC_LockDc(hdc);
1166     if (!dc)
1167     {
1168         EngSetLastError(ERROR_INVALID_HANDLE);
1169         return 0;
1170     }
1171     Ret = dc->erclWindow.right - dc->erclWindow.left;
1172     DC_UnlockDc(dc);
1173     return Ret;
1174 }
1175 
1176 /*
1177  * @implemented
1178  */
1179 BOOL
1180 APIENTRY
1181 NtGdiMirrorWindowOrg(
1182     IN HDC hdc)
1183 {
1184     PDC dc;
1185     dc = DC_LockDc(hdc);
1186     if (!dc)
1187     {
1188         EngSetLastError(ERROR_INVALID_HANDLE);
1189         return FALSE;
1190     }
1191     IntMirrorWindowOrg(dc);
1192     DC_UnlockDc(dc);
1193     return TRUE;
1194 }
1195 
1196 /*
1197  * @implemented
1198  */
1199 BOOL
1200 APIENTRY
1201 NtGdiSetSizeDevice(
1202     IN HDC hdc,
1203     IN INT cxVirtualDevice,
1204     IN INT cyVirtualDevice)
1205 {
1206     PDC dc;
1207     PDC_ATTR pdcattr;
1208 
1209     if (!cxVirtualDevice || !cyVirtualDevice)
1210     {
1211         return FALSE;
1212     }
1213 
1214     dc = DC_LockDc(hdc);
1215     if (!dc) return FALSE;
1216 
1217     pdcattr = dc->pdcattr;
1218 
1219     pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice;
1220     pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice;
1221 
1222     DC_UnlockDc(dc);
1223 
1224     return TRUE;
1225 }
1226 
1227 /*
1228  * @implemented
1229  */
1230 BOOL
1231 APIENTRY
1232 NtGdiSetVirtualResolution(
1233     IN HDC hdc,
1234     IN INT cxVirtualDevicePixel,
1235     IN INT cyVirtualDevicePixel,
1236     IN INT cxVirtualDeviceMm,
1237     IN INT cyVirtualDeviceMm)
1238 {
1239     PDC dc;
1240     PDC_ATTR pdcattr;
1241 
1242     /* Check parameters (all zeroes resets to real resolution) */
1243     if (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 &&
1244         cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0)
1245     {
1246         cxVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, HORZRES);
1247         cyVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, VERTRES);
1248         cxVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, HORZSIZE);
1249         cyVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, VERTSIZE);
1250     }
1251     else if (cxVirtualDevicePixel == 0 || cyVirtualDevicePixel == 0 ||
1252              cxVirtualDeviceMm == 0 || cyVirtualDeviceMm == 0)
1253     {
1254         return FALSE;
1255     }
1256 
1257     dc = DC_LockDc(hdc);
1258     if (!dc) return FALSE;
1259 
1260     pdcattr = dc->pdcattr;
1261 
1262     pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel;
1263     pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel;
1264     pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm;
1265     pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm;
1266 
1267 //    DC_vUpdateXforms(dc);
1268     DC_UnlockDc(dc);
1269     return TRUE;
1270 }
1271 
1272 static
1273 VOID FASTCALL
1274 DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio)
1275 {
1276     if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1.
1277     {
1278         // "This specifies that Windows should only match fonts that have the
1279         // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1280         AspectRatio->cx = pDC->ppdev->gdiinfo.ulLogPixelsX;
1281         AspectRatio->cy = pDC->ppdev->gdiinfo.ulLogPixelsY;
1282     }
1283     else
1284     {
1285         AspectRatio->cx = 0;
1286         AspectRatio->cy = 0;
1287     }
1288 }
1289 
1290 BOOL APIENTRY
1291 GreGetDCPoint(
1292     HDC hDC,
1293     UINT iPoint,
1294     PPOINTL Point)
1295 {
1296     BOOL Ret = TRUE;
1297     DC *pdc;
1298     SIZE Size;
1299     PSIZEL pszlViewportExt;
1300 
1301     if (!Point)
1302     {
1303         EngSetLastError(ERROR_INVALID_PARAMETER);
1304         return FALSE;
1305     }
1306 
1307     pdc = DC_LockDc(hDC);
1308     if (!pdc)
1309     {
1310         EngSetLastError(ERROR_INVALID_HANDLE);
1311         return FALSE;
1312     }
1313 
1314     switch (iPoint)
1315     {
1316         case GdiGetViewPortExt:
1317             pszlViewportExt = DC_pszlViewportExt(pdc);
1318             Point->x = pszlViewportExt->cx;
1319             Point->y = pszlViewportExt->cy;
1320             break;
1321 
1322         case GdiGetWindowExt:
1323             Point->x = pdc->pdcattr->szlWindowExt.cx;
1324             Point->y = pdc->pdcattr->szlWindowExt.cy;
1325             break;
1326 
1327         case GdiGetViewPortOrg:
1328             *Point = pdc->pdcattr->ptlViewportOrg;
1329             break;
1330 
1331         case GdiGetWindowOrg:
1332             *Point = pdc->pdcattr->ptlWindowOrg;
1333             break;
1334 
1335         case GdiGetDCOrg:
1336             *Point = pdc->ptlDCOrig;
1337             break;
1338 
1339         case GdiGetAspectRatioFilter:
1340             DC_vGetAspectRatioFilter(pdc, &Size);
1341             Point->x = Size.cx;
1342             Point->y = Size.cy;
1343             break;
1344 
1345         default:
1346             EngSetLastError(ERROR_INVALID_PARAMETER);
1347             Ret = FALSE;
1348             break;
1349     }
1350 
1351     DC_UnlockDc(pdc);
1352     return Ret;
1353 }
1354 
1355 BOOL
1356 WINAPI
1357 GreSetDCOrg(
1358     _In_ HDC hdc,
1359     _In_ LONG x,
1360     _In_ LONG y,
1361     _In_opt_ PRECTL Rect)
1362 {
1363     PDC dc;
1364 
1365     dc = DC_LockDc(hdc);
1366     if (!dc) return FALSE;
1367 
1368     /* Set DC Origin */
1369     dc->ptlDCOrig.x = x;
1370     dc->ptlDCOrig.y = y;
1371 
1372     /* Recalculate Fill Origin */
1373     dc->ptlFillOrigin.x = dc->dclevel.ptlBrushOrigin.x + x;
1374     dc->ptlFillOrigin.y = dc->dclevel.ptlBrushOrigin.y + y;
1375 
1376     /* Set DC Window Rectangle */
1377     if (Rect)
1378         dc->erclWindow = *Rect;
1379 
1380     DC_UnlockDc(dc);
1381     return TRUE;
1382 }
1383 
1384 BOOL
1385 WINAPI
1386 GreGetDCOrgEx(
1387     _In_ HDC hdc,
1388     _Out_ PPOINTL Point,
1389     _Out_ PRECTL Rect)
1390 {
1391     PDC dc;
1392 
1393     dc = DC_LockDc(hdc);
1394     if (!dc) return FALSE;
1395 
1396     /* Retrieve DC Window Rectangle without a check */
1397     *Rect = dc->erclWindow;
1398 
1399     DC_UnlockDc(dc);
1400 
1401     /* Use default call for DC Origin and parameter checking */
1402     return GreGetDCPoint( hdc, GdiGetDCOrg, Point);
1403 }
1404 
1405 BOOL
1406 WINAPI
1407 GreGetWindowExtEx(
1408     _In_ HDC hdc,
1409     _Out_ LPSIZE lpSize)
1410 {
1411     return GreGetDCPoint(hdc, GdiGetWindowExt, (PPOINTL)lpSize);
1412 }
1413 
1414 BOOL
1415 WINAPI
1416 GreGetViewportExtEx(
1417     _In_ HDC hdc,
1418     _Out_ LPSIZE lpSize)
1419 {
1420     return GreGetDCPoint(hdc, GdiGetViewPortExt, (PPOINTL)lpSize);
1421 }
1422 
1423 BOOL APIENTRY
1424 NtGdiGetDCPoint(
1425     HDC hDC,
1426     UINT iPoint,
1427     PPOINTL Point)
1428 {
1429     BOOL Ret;
1430     POINTL SafePoint;
1431 
1432     if (!Point)
1433     {
1434         EngSetLastError(ERROR_INVALID_PARAMETER);
1435         return FALSE;
1436     }
1437 
1438     Ret = GreGetDCPoint(hDC, iPoint, &SafePoint);
1439     if (Ret)
1440     {
1441         _SEH2_TRY
1442         {
1443             ProbeForWrite(Point, sizeof(POINT), 1);
1444             *Point = SafePoint;
1445         }
1446         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1447         {
1448             Ret = FALSE;
1449         }
1450         _SEH2_END;
1451     }
1452 
1453     return Ret;
1454 }
1455 
1456 /* EOF */
1457