[GDI32] Update Gdi Driver Header.
[reactos.git] / win32ss / gdi / ntgdi / coord.c
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 */