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