xref: /reactos/win32ss/gdi/ntgdi/coord.c (revision 405ce532)
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
DC_vFixIsotropicMapping(PDC pdc)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
DC_vGetPageToDevice(PDC pdc,MATRIX * pmx)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
DC_vUpdateWorldToDevice(PDC pdc)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
DC_vUpdateDeviceToWorld(PDC pdc)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
GreCombineTransform(XFORML * pxformDest,XFORML * pxform1,XFORML * pxform2)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
NtGdiCombineTransform(LPXFORM UnsafeXFormResult,LPXFORM Unsafexform1,LPXFORM Unsafexform2)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
NtGdiGetTransform(HDC hdc,DWORD iXform,LPXFORM pXForm)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
NtGdiTransformPoints(HDC hDC,PPOINT UnsafePtsIn,PPOINT UnsafePtOut,INT Count,INT iMode)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
GreModifyWorldTransform(PDC pdc,const XFORML * pxform,DWORD dwMode)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
NtGdiModifyWorldTransform(HDC hdc,LPXFORM pxformUnsafe,DWORD dwMode)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
NtGdiOffsetViewportOrgEx(HDC hDC,int XOffset,int YOffset,LPPOINT UnsafePoint)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
NtGdiOffsetWindowOrgEx(HDC hDC,int XOffset,int YOffset,LPPOINT Point)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
NtGdiScaleViewportExtEx(HDC hDC,int Xnum,int Xdenom,int Ynum,int Ydenom,LPSIZE pSize)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
NtGdiScaleWindowExtEx(HDC hDC,int Xnum,int Xdenom,int Ynum,int Ydenom,LPSIZE pSize)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
IntGdiSetMapMode(PDC dc,int MapMode)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
GreSetViewportOrgEx(HDC hDC,int X,int Y,LPPOINT Point)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
NtGdiSetViewportOrgEx(HDC hDC,int X,int Y,LPPOINT Point)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
NtGdiSetWindowOrgEx(HDC hDC,int X,int Y,LPPOINT Point)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
IntMirrorWindowOrg(PDC dc)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
DC_vSetLayout(IN PDC pdc,IN LONG wox,IN DWORD dwLayout)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
NtGdiSetLayout(IN HDC hdc,IN LONG wox,IN DWORD dwLayout)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
NtGdiGetDeviceWidth(IN HDC hdc)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
NtGdiMirrorWindowOrg(IN HDC hdc)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
NtGdiSetSizeDevice(IN HDC hdc,IN INT cxVirtualDevice,IN INT cyVirtualDevice)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
NtGdiSetVirtualResolution(IN HDC hdc,IN INT cxVirtualDevicePixel,IN INT cyVirtualDevicePixel,IN INT cxVirtualDeviceMm,IN INT cyVirtualDeviceMm)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
DC_vGetAspectRatioFilter(PDC pDC,LPSIZE AspectRatio)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
GreGetDCPoint(HDC hDC,UINT iPoint,PPOINTL Point)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
GreSetDCOrg(_In_ HDC hdc,_In_ LONG x,_In_ LONG y,_In_opt_ PRECTL Rect)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
GreGetDCOrgEx(_In_ HDC hdc,_Out_ PPOINTL Point,_Out_ PRECTL Rect)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
GreGetWindowExtEx(_In_ HDC hdc,_Out_ LPSIZE lpSize)1407 GreGetWindowExtEx(
1408     _In_ HDC hdc,
1409     _Out_ LPSIZE lpSize)
1410 {
1411     return GreGetDCPoint(hdc, GdiGetWindowExt, (PPOINTL)lpSize);
1412 }
1413 
1414 BOOL
1415 WINAPI
GreGetViewportExtEx(_In_ HDC hdc,_Out_ LPSIZE lpSize)1416 GreGetViewportExtEx(
1417     _In_ HDC hdc,
1418     _Out_ LPSIZE lpSize)
1419 {
1420     return GreGetDCPoint(hdc, GdiGetViewPortExt, (PPOINTL)lpSize);
1421 }
1422 
1423 BOOL APIENTRY
NtGdiGetDCPoint(HDC hDC,UINT iPoint,PPOINTL Point)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