d85238a13f585ab623c1b559f2b9dea7946fe2ff
[reactos.git] / reactos / subsystems / win32 / win32k / objects / coord.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: Coordinate systems
24 * FILE: subsys/win32k/objects/coord.c
25 * PROGRAMER: Unknown
26 */
27
28 /* INCLUDES ******************************************************************/
29
30 #include <w32k.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* FUNCTIONS *****************************************************************/
36
37 void FASTCALL
38 IntFixIsotropicMapping(PDC dc)
39 {
40 PDC_ATTR pdcattr;
41 LONG fx, fy, s;
42
43 /* Get a pointer to the DC_ATTR */
44 pdcattr = dc->pdcattr;
45
46 /* Check if all values are valid */
47 if (pdcattr->szlWindowExt.cx == 0 || pdcattr->szlWindowExt.cy == 0 ||
48 pdcattr->szlViewportExt.cx == 0 || pdcattr->szlViewportExt.cy == 0)
49 {
50 /* Don't recalculate */
51 return;
52 }
53
54 fx = abs(pdcattr->szlWindowExt.cx * pdcattr->szlViewportExt.cy);
55 fy = abs(pdcattr->szlWindowExt.cy * pdcattr->szlViewportExt.cx);
56
57 if (fy > fx)
58 {
59 s = pdcattr->szlWindowExt.cy * pdcattr->szlViewportExt.cx > 0 ? 1 : -1;
60 pdcattr->szlViewportExt.cx = s * fx / pdcattr->szlWindowExt.cy;
61 }
62 else if (fx > fy)
63 {
64 s = pdcattr->szlWindowExt.cx * pdcattr->szlViewportExt.cy > 0 ? 1 : -1;
65 pdcattr->szlViewportExt.cy = s * fy / pdcattr->szlWindowExt.cx;
66 }
67 }
68
69 // FIXME: don't use floating point in the kernel! use XFORMOBJ function
70 BOOL FASTCALL
71 IntGdiCombineTransform(
72 LPXFORM XFormResult,
73 LPXFORM xform1,
74 LPXFORM xform2)
75 {
76 XFORM xformTemp;
77 /* Check for illegal parameters */
78 if (!XFormResult || !xform1 || !xform2)
79 {
80 return FALSE;
81 }
82
83 /* Create the result in a temporary XFORM, since xformResult may be
84 * equal to xform1 or xform2 */
85 xformTemp.eM11 = xform1->eM11 * xform2->eM11 + xform1->eM12 * xform2->eM21;
86 xformTemp.eM12 = xform1->eM11 * xform2->eM12 + xform1->eM12 * xform2->eM22;
87 xformTemp.eM21 = xform1->eM21 * xform2->eM11 + xform1->eM22 * xform2->eM21;
88 xformTemp.eM22 = xform1->eM21 * xform2->eM12 + xform1->eM22 * xform2->eM22;
89 xformTemp.eDx = xform1->eDx * xform2->eM11 + xform1->eDy * xform2->eM21 + xform2->eDx;
90 xformTemp.eDy = xform1->eDx * xform2->eM12 + xform1->eDy * xform2->eM22 + xform2->eDy;
91 *XFormResult = xformTemp;
92
93 return TRUE;
94 }
95
96 // FIXME: should be XFORML and use XFORMOBJ functions
97 BOOL APIENTRY NtGdiCombineTransform(
98 LPXFORM UnsafeXFormResult,
99 LPXFORM Unsafexform1,
100 LPXFORM Unsafexform2)
101 {
102 BOOL Ret;
103
104 _SEH2_TRY
105 {
106 ProbeForWrite(UnsafeXFormResult, sizeof(XFORM), 1);
107 ProbeForRead(Unsafexform1, sizeof(XFORM), 1);
108 ProbeForRead(Unsafexform2, sizeof(XFORM), 1);
109 Ret = IntGdiCombineTransform(UnsafeXFormResult,
110 Unsafexform1,
111 Unsafexform2);
112 }
113 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
114 {
115 Ret = FALSE;
116 }
117 _SEH2_END;
118
119 return Ret;
120 }
121
122 // FIXME: Don't use floating point in the kernel
123 BOOL
124 FASTCALL
125 IntGdiModifyWorldTransform(
126 PDC pDc,
127 CONST LPXFORM lpXForm,
128 DWORD Mode)
129 {
130 XFORM xformWorld2Wnd;
131 ASSERT(pDc);
132
133 switch (Mode)
134 {
135 case MWT_IDENTITY:
136 xformWorld2Wnd.eM11 = 1.0f;
137 xformWorld2Wnd.eM12 = 0.0f;
138 xformWorld2Wnd.eM21 = 0.0f;
139 xformWorld2Wnd.eM22 = 1.0f;
140 xformWorld2Wnd.eDx = 0.0f;
141 xformWorld2Wnd.eDy = 0.0f;
142 XForm2MatrixS(&pDc->dclevel.mxWorldToPage, &xformWorld2Wnd);
143 break;
144
145 case MWT_LEFTMULTIPLY:
146 MatrixS2XForm(&xformWorld2Wnd, &pDc->dclevel.mxWorldToPage);
147 IntGdiCombineTransform(&xformWorld2Wnd, lpXForm, &xformWorld2Wnd);
148 XForm2MatrixS(&pDc->dclevel.mxWorldToPage, &xformWorld2Wnd);
149 break;
150
151 case MWT_RIGHTMULTIPLY:
152 MatrixS2XForm(&xformWorld2Wnd, &pDc->dclevel.mxWorldToPage);
153 IntGdiCombineTransform(&xformWorld2Wnd, &xformWorld2Wnd, lpXForm);
154 XForm2MatrixS(&pDc->dclevel.mxWorldToPage, &xformWorld2Wnd);
155 break;
156
157 case MWT_MAX+1: // Must be MWT_SET????
158 XForm2MatrixS(&pDc->dclevel.mxWorldToPage, lpXForm); // Do it like Wine.
159 break;
160
161 default:
162 return FALSE;
163 }
164 DC_UpdateXforms(pDc);
165 return TRUE;
166 }
167
168 // FIXME: Should be XFORML and use XFORMOBJ functions directly
169 BOOL
170 APIENTRY
171 NtGdiGetTransform(
172 HDC hDC,
173 DWORD iXform,
174 LPXFORM XForm)
175 {
176 PDC dc;
177 NTSTATUS Status = STATUS_SUCCESS;
178
179 dc = DC_LockDc(hDC);
180 if (!dc)
181 {
182 SetLastWin32Error(ERROR_INVALID_HANDLE);
183 return FALSE;
184 }
185 if (!XForm)
186 {
187 DC_UnlockDc(dc);
188 SetLastWin32Error(ERROR_INVALID_PARAMETER);
189 return FALSE;
190 }
191
192 _SEH2_TRY
193 {
194 ProbeForWrite(XForm, sizeof(XFORM), 1);
195 switch (iXform)
196 {
197 case GdiWorldSpaceToPageSpace:
198 MatrixS2XForm(XForm, &dc->dclevel.mxWorldToPage);
199 break;
200
201 case GdiWorldSpaceToDeviceSpace:
202 MatrixS2XForm(XForm, &dc->dclevel.mxWorldToDevice);
203 break;
204
205 case GdiPageSpaceToDeviceSpace:
206 DPRINT1("Page space -> device space is unsupported!\n");
207 break;
208
209 case GdiDeviceSpaceToWorldSpace:
210 MatrixS2XForm(XForm, &dc->dclevel.mxDeviceToWorld);
211 break;
212
213 default:
214 DPRINT1("Unknown transform %lu\n", iXform);
215 Status = STATUS_INVALID_PARAMETER;
216 break;
217 }
218 }
219 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
220 {
221 Status = _SEH2_GetExceptionCode();
222 }
223 _SEH2_END;
224
225 DC_UnlockDc(dc);
226 return NT_SUCCESS(Status);
227 }
228
229
230 /*!
231 * Converts points from logical coordinates into device coordinates. Conversion depends on the mapping mode,
232 * world transfrom, viewport origin settings for the given device context.
233 * \param hDC device context.
234 * \param Points an array of POINT structures (in/out).
235 * \param Count number of elements in the array of POINT structures.
236 * \return TRUE if success.
237 */
238 BOOL
239 APIENTRY
240 NtGdiTransformPoints(
241 HDC hDC,
242 PPOINT UnsafePtsIn,
243 PPOINT UnsafePtOut,
244 INT Count,
245 INT iMode)
246 {
247 PDC dc;
248 NTSTATUS Status = STATUS_SUCCESS;
249 LPPOINT Points;
250 ULONG Size;
251
252 dc = DC_LockDc(hDC);
253 if (!dc)
254 {
255 SetLastWin32Error(ERROR_INVALID_HANDLE);
256 return FALSE;
257 }
258
259 if (!UnsafePtsIn || !UnsafePtOut || Count <= 0)
260 {
261 DC_UnlockDc(dc);
262 SetLastWin32Error(ERROR_INVALID_PARAMETER);
263 return FALSE;
264 }
265
266 Size = Count * sizeof(POINT);
267
268 // FIXME: It would be wise to have a small stack buffer as optimization
269 Points = ExAllocatePoolWithTag(PagedPool, Size, TAG_COORD);
270 if (!Points)
271 {
272 DC_UnlockDc(dc);
273 SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY);
274 return FALSE;
275 }
276
277 _SEH2_TRY
278 {
279 ProbeForWrite(UnsafePtOut, Size, 1);
280 ProbeForRead(UnsafePtsIn, Size, 1);
281 RtlCopyMemory(Points, UnsafePtsIn, Size);
282 }
283 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
284 {
285 Status = _SEH2_GetExceptionCode();
286 }
287 _SEH2_END;
288
289 if (!NT_SUCCESS(Status))
290 {
291 DC_UnlockDc(dc);
292 ExFreePoolWithTag(Points, TAG_COORD);
293 SetLastNtError(Status);
294 return FALSE;
295 }
296
297 switch (iMode)
298 {
299 case GdiDpToLp:
300 IntDPtoLP(dc, Points, Count);
301 break;
302
303 case GdiLpToDp:
304 IntLPtoDP(dc, Points, Count);
305 break;
306
307 case 2: // Not supported yet. Need testing.
308 default:
309 {
310 DC_UnlockDc(dc);
311 ExFreePoolWithTag(Points, TAG_COORD);
312 SetLastWin32Error(ERROR_INVALID_PARAMETER);
313 return FALSE;
314 }
315 }
316
317 _SEH2_TRY
318 {
319 /* pointer was already probed! */
320 RtlCopyMemory(UnsafePtOut, Points, Size);
321 }
322 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
323 {
324 Status = _SEH2_GetExceptionCode();
325 }
326 _SEH2_END;
327
328 if (!NT_SUCCESS(Status))
329 {
330 DC_UnlockDc(dc);
331 ExFreePoolWithTag(Points, TAG_COORD);
332 SetLastNtError(Status);
333 return FALSE;
334 }
335 //
336 // If we are getting called that means User XForms is a mess!
337 //
338 DC_UnlockDc(dc);
339 ExFreePoolWithTag(Points, TAG_COORD);
340 return TRUE;
341 }
342
343 BOOL
344 APIENTRY
345 NtGdiModifyWorldTransform(
346 HDC hDC,
347 LPXFORM UnsafeXForm,
348 DWORD Mode)
349 {
350 PDC dc;
351 XFORM SafeXForm;
352 BOOL Ret = TRUE;
353
354 dc = DC_LockDc(hDC);
355 if (!dc)
356 {
357 SetLastWin32Error(ERROR_INVALID_HANDLE);
358 return FALSE;
359 }
360
361 // The xform is permitted to be NULL for MWT_IDENTITY.
362 // However, if it is not NULL, then it must be valid even though it is not used.
363 if (UnsafeXForm != NULL || Mode != MWT_IDENTITY)
364 {
365 _SEH2_TRY
366 {
367 ProbeForRead(UnsafeXForm, sizeof(XFORM), 1);
368 RtlCopyMemory(&SafeXForm, UnsafeXForm, sizeof(XFORM));
369 }
370 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
371 {
372 Ret = FALSE;
373 }
374 _SEH2_END;
375 }
376
377 // Safe to handle kernel mode data.
378 if (Ret) Ret = IntGdiModifyWorldTransform(dc, &SafeXForm, Mode);
379 DC_UnlockDc(dc);
380 return Ret;
381 }
382
383 BOOL
384 APIENTRY
385 NtGdiOffsetViewportOrgEx(
386 HDC hDC,
387 int XOffset,
388 int YOffset,
389 LPPOINT UnsafePoint)
390 {
391 PDC dc;
392 PDC_ATTR pdcattr;
393 NTSTATUS Status = STATUS_SUCCESS;
394
395 dc = DC_LockDc(hDC);
396 if (!dc)
397 {
398 SetLastWin32Error(ERROR_INVALID_HANDLE);
399 return FALSE;
400 }
401 pdcattr = dc->pdcattr;
402
403 if (UnsafePoint)
404 {
405 _SEH2_TRY
406 {
407 ProbeForWrite(UnsafePoint, sizeof(POINT), 1);
408 UnsafePoint->x = pdcattr->ptlViewportOrg.x;
409 UnsafePoint->y = pdcattr->ptlViewportOrg.y;
410 if (pdcattr->dwLayout & LAYOUT_RTL)
411 {
412 UnsafePoint->x = -UnsafePoint->x;
413 }
414 }
415 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
416 {
417 Status = _SEH2_GetExceptionCode();
418 }
419 _SEH2_END;
420
421 if (!NT_SUCCESS(Status))
422 {
423 SetLastNtError(Status);
424 DC_UnlockDc(dc);
425 return FALSE;
426 }
427 }
428
429 if (pdcattr->dwLayout & LAYOUT_RTL)
430 {
431 XOffset = -XOffset;
432 }
433 pdcattr->ptlViewportOrg.x += XOffset;
434 pdcattr->ptlViewportOrg.y += YOffset;
435 DC_UpdateXforms(dc);
436 DC_UnlockDc(dc);
437
438 return TRUE;
439 }
440
441 BOOL
442 APIENTRY
443 NtGdiOffsetWindowOrgEx(
444 HDC hDC,
445 int XOffset,
446 int YOffset,
447 LPPOINT Point)
448 {
449 PDC dc;
450 PDC_ATTR pdcattr;
451
452 dc = DC_LockDc(hDC);
453 if (!dc)
454 {
455 SetLastWin32Error(ERROR_INVALID_HANDLE);
456 return FALSE;
457 }
458 pdcattr = dc->pdcattr;
459
460 if (Point)
461 {
462 NTSTATUS Status = STATUS_SUCCESS;
463
464 _SEH2_TRY
465 {
466 ProbeForWrite(Point, sizeof(POINT), 1);
467 Point->x = pdcattr->ptlWindowOrg.x;
468 Point->y = pdcattr->ptlWindowOrg.y;
469 }
470 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
471 {
472 Status = _SEH2_GetExceptionCode();
473 }
474 _SEH2_END;
475
476 if (!NT_SUCCESS(Status))
477 {
478 SetLastNtError(Status);
479 DC_UnlockDc(dc);
480 return FALSE;
481 }
482 }
483
484 pdcattr->ptlWindowOrg.x += XOffset;
485 pdcattr->ptlWindowOrg.y += YOffset;
486
487 DC_UpdateXforms(dc);
488 DC_UnlockDc(dc);
489
490 return TRUE;
491 }
492
493 BOOL
494 APIENTRY
495 NtGdiScaleViewportExtEx(
496 HDC hDC,
497 int Xnum,
498 int Xdenom,
499 int Ynum,
500 int Ydenom,
501 LPSIZE pSize)
502 {
503 PDC pDC;
504 PDC_ATTR pdcattr;
505 BOOL Ret = FALSE;
506 LONG X, Y;
507
508 pDC = DC_LockDc(hDC);
509 if (!pDC)
510 {
511 SetLastWin32Error(ERROR_INVALID_HANDLE);
512 return FALSE;
513 }
514 pdcattr = pDC->pdcattr;
515
516 if (pSize)
517 {
518 NTSTATUS Status = STATUS_SUCCESS;
519
520 _SEH2_TRY
521 {
522 ProbeForWrite(pSize, sizeof(LPSIZE), 1);
523
524 pSize->cx = pdcattr->szlViewportExt.cx;
525 pSize->cy = pdcattr->szlViewportExt.cy;
526 }
527 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
528 {
529 Status = _SEH2_GetExceptionCode();
530 }
531 _SEH2_END;
532
533 if (!NT_SUCCESS(Status))
534 {
535 SetLastNtError(Status);
536 DC_UnlockDc(pDC);
537 return FALSE;
538 }
539 }
540
541 if (pdcattr->iMapMode > MM_TWIPS)
542 {
543 if (Xdenom && Ydenom)
544 {
545 X = Xnum * pdcattr->szlViewportExt.cx / Xdenom;
546 if (X)
547 {
548 Y = Ynum * pdcattr->szlViewportExt.cy / Ydenom;
549 if (Y)
550 {
551 pdcattr->szlViewportExt.cx = X;
552 pdcattr->szlViewportExt.cy = Y;
553
554 IntMirrorWindowOrg(pDC);
555
556 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
557 INVALIDATE_ATTRIBUTES |
558 DEVICE_TO_WORLD_INVALID);
559
560 if (pdcattr->iMapMode == MM_ISOTROPIC)
561 {
562 IntFixIsotropicMapping(pDC);
563 }
564 DC_UpdateXforms(pDC);
565
566 Ret = TRUE;
567 }
568 }
569 }
570 }
571 else
572 Ret = TRUE;
573
574 DC_UnlockDc(pDC);
575 return Ret;
576 }
577
578 BOOL
579 APIENTRY
580 NtGdiScaleWindowExtEx(
581 HDC hDC,
582 int Xnum,
583 int Xdenom,
584 int Ynum,
585 int Ydenom,
586 LPSIZE pSize)
587 {
588 PDC pDC;
589 PDC_ATTR pdcattr;
590 BOOL Ret = FALSE;
591 LONG X, Y;
592
593 pDC = DC_LockDc(hDC);
594 if (!pDC)
595 {
596 SetLastWin32Error(ERROR_INVALID_HANDLE);
597 return FALSE;
598 }
599 pdcattr = pDC->pdcattr;
600
601 if (pSize)
602 {
603 NTSTATUS Status = STATUS_SUCCESS;
604
605 _SEH2_TRY
606 {
607 ProbeForWrite(pSize, sizeof(LPSIZE), 1);
608
609 X = pdcattr->szlWindowExt.cx;
610 if (pdcattr->dwLayout & LAYOUT_RTL) X = -X;
611 pSize->cx = X;
612 pSize->cy = pdcattr->szlWindowExt.cy;
613 }
614 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
615 {
616 Status = _SEH2_GetExceptionCode();
617 }
618 _SEH2_END;
619
620 if (!NT_SUCCESS(Status))
621 {
622 SetLastNtError(Status);
623 DC_UnlockDc(pDC);
624 return FALSE;
625 }
626 }
627
628 if (pdcattr->iMapMode > MM_TWIPS)
629 {
630 if (Xdenom && Ydenom)
631 {
632 X = Xnum * pdcattr->szlWindowExt.cx / Xdenom;
633 if (X)
634 {
635 Y = Ynum * pdcattr->szlWindowExt.cy / Ydenom;
636 if (Y)
637 {
638 pdcattr->szlWindowExt.cx = X;
639 pdcattr->szlWindowExt.cy = Y;
640
641 IntMirrorWindowOrg(pDC);
642
643 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED|INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID);
644
645 if (pdcattr->iMapMode == MM_ISOTROPIC) IntFixIsotropicMapping(pDC);
646 DC_UpdateXforms(pDC);
647
648 Ret = TRUE;
649 }
650 }
651 }
652 }
653 else
654 Ret = TRUE;
655
656 DC_UnlockDc(pDC);
657 return Ret;
658 }
659
660 int
661 APIENTRY
662 IntGdiSetMapMode(
663 PDC dc,
664 int MapMode)
665 {
666 int PrevMapMode;
667 PDC_ATTR pdcattr = dc->pdcattr;
668
669 PrevMapMode = pdcattr->iMapMode;
670
671 pdcattr->iMapMode = MapMode;
672
673 switch (MapMode)
674 {
675 case MM_TEXT:
676 pdcattr->szlWindowExt.cx = 1;
677 pdcattr->szlWindowExt.cy = 1;
678 pdcattr->szlViewportExt.cx = 1;
679 pdcattr->szlViewportExt.cy = 1;
680 pdcattr->flXform &= ~(ISO_OR_ANISO_MAP_MODE|PTOD_EFM22_NEGATIVE|
681 PTOD_EFM11_NEGATIVE|POSITIVE_Y_IS_UP);
682 pdcattr->flXform |= (PAGE_XLATE_CHANGED|PAGE_TO_DEVICE_SCALE_IDENTITY|
683 INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID);
684 break;
685
686 case MM_ISOTROPIC:
687 pdcattr->flXform |= ISO_OR_ANISO_MAP_MODE;
688 /* Fall through */
689
690 case MM_LOMETRIC:
691 pdcattr->szlWindowExt.cx = dc->ppdev->gdiinfo.ulHorzSize * 10;
692 pdcattr->szlWindowExt.cy = dc->ppdev->gdiinfo.ulVertSize * 10;
693 pdcattr->szlViewportExt.cx = dc->ppdev->gdiinfo.ulHorzRes;
694 pdcattr->szlViewportExt.cy = -dc->ppdev->gdiinfo.ulVertRes;
695 break;
696
697 case MM_HIMETRIC:
698 pdcattr->szlWindowExt.cx = dc->ppdev->gdiinfo.ulHorzSize * 100;
699 pdcattr->szlWindowExt.cy = dc->ppdev->gdiinfo.ulVertSize * 100;
700 pdcattr->szlViewportExt.cx = dc->ppdev->gdiinfo.ulHorzRes;
701 pdcattr->szlViewportExt.cy = -dc->ppdev->gdiinfo.ulVertRes;
702 break;
703
704 case MM_LOENGLISH:
705 pdcattr->szlWindowExt.cx = MulDiv(1000, dc->ppdev->gdiinfo.ulHorzSize, 254);
706 pdcattr->szlWindowExt.cy = MulDiv(1000, dc->ppdev->gdiinfo.ulVertSize, 254);
707 pdcattr->szlViewportExt.cx = dc->ppdev->gdiinfo.ulHorzRes;
708 pdcattr->szlViewportExt.cy = -dc->ppdev->gdiinfo.ulVertRes;
709 break;
710
711 case MM_HIENGLISH:
712 pdcattr->szlWindowExt.cx = MulDiv(10000, dc->ppdev->gdiinfo.ulHorzSize, 254);
713 pdcattr->szlWindowExt.cy = MulDiv(10000, dc->ppdev->gdiinfo.ulVertSize, 254);
714 pdcattr->szlViewportExt.cx = dc->ppdev->gdiinfo.ulHorzRes;
715 pdcattr->szlViewportExt.cy = -dc->ppdev->gdiinfo.ulVertRes;
716 break;
717
718 case MM_TWIPS:
719 pdcattr->szlWindowExt.cx = MulDiv(14400, dc->ppdev->gdiinfo.ulHorzSize, 254);
720 pdcattr->szlWindowExt.cy = MulDiv(14400, dc->ppdev->gdiinfo.ulVertSize, 254);
721 pdcattr->szlViewportExt.cx = dc->ppdev->gdiinfo.ulHorzRes;
722 pdcattr->szlViewportExt.cy = -dc->ppdev->gdiinfo.ulVertRes;
723 break;
724
725 case MM_ANISOTROPIC:
726 pdcattr->flXform &= ~(PAGE_TO_DEVICE_IDENTITY|POSITIVE_Y_IS_UP);
727 pdcattr->flXform |= ISO_OR_ANISO_MAP_MODE;
728 break;
729
730 default:
731 pdcattr->iMapMode = PrevMapMode;
732 PrevMapMode = 0;
733 }
734 DC_UpdateXforms(dc);
735
736 return PrevMapMode;
737 }
738
739
740 BOOL
741 APIENTRY
742 NtGdiSetViewportOrgEx(
743 HDC hDC,
744 int X,
745 int Y,
746 LPPOINT Point)
747 {
748 PDC dc;
749 PDC_ATTR pdcattr;
750
751 dc = DC_LockDc(hDC);
752 if (!dc)
753 {
754 SetLastWin32Error(ERROR_INVALID_HANDLE);
755 return FALSE;
756 }
757 pdcattr = dc->pdcattr;
758
759 if (Point)
760 {
761 NTSTATUS Status = STATUS_SUCCESS;
762
763 _SEH2_TRY
764 {
765 ProbeForWrite(Point, sizeof(POINT), 1);
766 Point->x = pdcattr->ptlViewportOrg.x;
767 Point->y = pdcattr->ptlViewportOrg.y;
768 }
769 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
770 {
771 Status = _SEH2_GetExceptionCode();
772 }
773 _SEH2_END;
774
775 if (!NT_SUCCESS(Status))
776 {
777 SetLastNtError(Status);
778 DC_UnlockDc(dc);
779 return FALSE;
780 }
781 }
782
783 pdcattr->ptlViewportOrg.x = X;
784 pdcattr->ptlViewportOrg.y = Y;
785
786 DC_UpdateXforms(dc);
787 DC_UnlockDc(dc);
788
789 return TRUE;
790 }
791
792 BOOL
793 APIENTRY
794 NtGdiSetWindowOrgEx(
795 HDC hDC,
796 int X,
797 int Y,
798 LPPOINT Point)
799 {
800 PDC dc;
801 PDC_ATTR pdcattr;
802
803 dc = DC_LockDc(hDC);
804 if (!dc)
805 {
806 SetLastWin32Error(ERROR_INVALID_HANDLE);
807 return FALSE;
808 }
809 pdcattr = dc->pdcattr;
810
811 if (Point)
812 {
813 NTSTATUS Status = STATUS_SUCCESS;
814
815 _SEH2_TRY
816 {
817 ProbeForWrite(Point, sizeof(POINT), 1);
818 Point->x = pdcattr->ptlWindowOrg.x;
819 Point->y = pdcattr->ptlWindowOrg.y;
820 }
821 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
822 {
823 Status = _SEH2_GetExceptionCode();
824 }
825 _SEH2_END;
826
827 if (!NT_SUCCESS(Status))
828 {
829 SetLastNtError(Status);
830 DC_UnlockDc(dc);
831 return FALSE;
832 }
833 }
834
835 pdcattr->ptlWindowOrg.x = X;
836 pdcattr->ptlWindowOrg.y = Y;
837
838 DC_UpdateXforms(dc);
839 DC_UnlockDc(dc);
840
841 return TRUE;
842 }
843
844 //
845 // Mirror Window function.
846 //
847 VOID
848 FASTCALL
849 IntMirrorWindowOrg(PDC dc)
850 {
851 PDC_ATTR pdcattr;
852 LONG X;
853
854 pdcattr = dc->pdcattr;
855
856 if (!(pdcattr->dwLayout & LAYOUT_RTL))
857 {
858 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx; // Flip it back.
859 return;
860 }
861 if (!pdcattr->szlViewportExt.cx) return;
862 //
863 // WOrgx = wox - (Width - 1) * WExtx / VExtx
864 //
865 X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1
866
867 X = (X * pdcattr->szlWindowExt.cx) / pdcattr->szlViewportExt.cx;
868
869 pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx - X; // Now set the inverted win origion.
870
871 return;
872 }
873
874 // NtGdiSetLayout
875 //
876 // The default is left to right. This function changes it to right to left, which
877 // is the standard in Arabic and Hebrew cultures.
878 //
879 /*
880 * @implemented
881 */
882 DWORD
883 APIENTRY
884 NtGdiSetLayout(
885 IN HDC hdc,
886 IN LONG wox,
887 IN DWORD dwLayout)
888 {
889 PDC dc;
890 PDC_ATTR pdcattr;
891 DWORD oLayout;
892
893 dc = DC_LockDc(hdc);
894 if (!dc)
895 {
896 SetLastWin32Error(ERROR_INVALID_HANDLE);
897 return GDI_ERROR;
898 }
899 pdcattr = dc->pdcattr;
900
901 pdcattr->dwLayout = dwLayout;
902 oLayout = pdcattr->dwLayout;
903
904 if (!(dwLayout & LAYOUT_ORIENTATIONMASK))
905 {
906 DC_UnlockDc(dc);
907 return oLayout;
908 }
909
910 if (dwLayout & LAYOUT_RTL)
911 {
912 pdcattr->iMapMode = MM_ANISOTROPIC;
913 }
914
915 pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
916 pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x;
917
918 if (wox == -1)
919 IntMirrorWindowOrg(dc);
920 else
921 pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
922
923 if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT;
924
925 if (dc->dclevel.flPath & DCPATH_CLOCKWISE)
926 dc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
927 else
928 dc->dclevel.flPath |= DCPATH_CLOCKWISE;
929
930 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
931 INVALIDATE_ATTRIBUTES |
932 DEVICE_TO_WORLD_INVALID);
933
934 // DC_UpdateXforms(dc);
935 DC_UnlockDc(dc);
936 return oLayout;
937 }
938
939 /*
940 * @implemented
941 */
942 LONG
943 APIENTRY
944 NtGdiGetDeviceWidth(
945 IN HDC hdc)
946 {
947 PDC dc;
948 LONG Ret;
949 dc = DC_LockDc(hdc);
950 if (!dc)
951 {
952 SetLastWin32Error(ERROR_INVALID_HANDLE);
953 return 0;
954 }
955 Ret = dc->erclWindow.right - dc->erclWindow.left;
956 DC_UnlockDc(dc);
957 return Ret;
958 }
959
960 /*
961 * @implemented
962 */
963 BOOL
964 APIENTRY
965 NtGdiMirrorWindowOrg(
966 IN HDC hdc)
967 {
968 PDC dc;
969 dc = DC_LockDc(hdc);
970 if (!dc)
971 {
972 SetLastWin32Error(ERROR_INVALID_HANDLE);
973 return FALSE;
974 }
975 IntMirrorWindowOrg(dc);
976 DC_UnlockDc(dc);
977 return TRUE;
978 }
979
980 /*
981 * @implemented
982 */
983 BOOL
984 APIENTRY
985 NtGdiSetSizeDevice(
986 IN HDC hdc,
987 IN INT cxVirtualDevice,
988 IN INT cyVirtualDevice)
989 {
990 PDC dc;
991 PDC_ATTR pdcattr;
992
993 if (!cxVirtualDevice || !cyVirtualDevice)
994 {
995 return FALSE;
996 }
997
998 dc = DC_LockDc(hdc);
999 if (!dc) return FALSE;
1000
1001 pdcattr = dc->pdcattr;
1002
1003 pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice;
1004 pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice;
1005
1006 // DC_UpdateXforms(dc);
1007 DC_UnlockDc(dc);
1008
1009 return TRUE;
1010 }
1011
1012 /*
1013 * @implemented
1014 */
1015 BOOL
1016 APIENTRY
1017 NtGdiSetVirtualResolution(
1018 IN HDC hdc,
1019 IN INT cxVirtualDevicePixel,
1020 IN INT cyVirtualDevicePixel,
1021 IN INT cxVirtualDeviceMm,
1022 IN INT cyVirtualDeviceMm)
1023 {
1024 PDC dc;
1025 PDC_ATTR pdcattr;
1026
1027 // Need test types for zeros and non zeros
1028
1029 dc = DC_LockDc(hdc);
1030 if (!dc) return FALSE;
1031
1032 pdcattr = dc->pdcattr;
1033
1034 pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel;
1035 pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel;
1036 pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm;
1037 pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm;
1038
1039 // DC_UpdateXforms(dc);
1040 DC_UnlockDc(dc);
1041 return TRUE;
1042 }
1043
1044
1045 // FIXME: Don't use floating point in the kernel!
1046 BOOL FASTCALL
1047 DC_InvertXform(const XFORM *xformSrc,
1048 XFORM *xformDest)
1049 {
1050 FLOAT determinant;
1051
1052 determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21;
1053 if (determinant > -1e-12 && determinant < 1e-12)
1054 {
1055 return FALSE;
1056 }
1057
1058 xformDest->eM11 = xformSrc->eM22 / determinant;
1059 xformDest->eM12 = -xformSrc->eM12 / determinant;
1060 xformDest->eM21 = -xformSrc->eM21 / determinant;
1061 xformDest->eM22 = xformSrc->eM11 / determinant;
1062 xformDest->eDx = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21;
1063 xformDest->eDy = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22;
1064
1065 return TRUE;
1066 }
1067
1068
1069 // FIXME: Don't use floating point in the kernel!
1070 VOID FASTCALL
1071 DC_UpdateXforms(PDC dc)
1072 {
1073 XFORM xformWnd2Vport;
1074 FLOAT scaleX, scaleY;
1075 PDC_ATTR pdcattr = dc->pdcattr;
1076 XFORM xformWorld2Vport, xformWorld2Wnd, xformVport2World;
1077
1078 /* Construct a transformation to do the window-to-viewport conversion */
1079 scaleX = (pdcattr->szlWindowExt.cx ? (FLOAT)pdcattr->szlViewportExt.cx / (FLOAT)pdcattr->szlWindowExt.cx : 0.0f);
1080 scaleY = (pdcattr->szlWindowExt.cy ? (FLOAT)pdcattr->szlViewportExt.cy / (FLOAT)pdcattr->szlWindowExt.cy : 0.0f);
1081 xformWnd2Vport.eM11 = scaleX;
1082 xformWnd2Vport.eM12 = 0.0;
1083 xformWnd2Vport.eM21 = 0.0;
1084 xformWnd2Vport.eM22 = scaleY;
1085 xformWnd2Vport.eDx = (FLOAT)pdcattr->ptlViewportOrg.x - scaleX * (FLOAT)pdcattr->ptlWindowOrg.x;
1086 xformWnd2Vport.eDy = (FLOAT)pdcattr->ptlViewportOrg.y - scaleY * (FLOAT)pdcattr->ptlWindowOrg.y;
1087
1088 /* Combine with the world transformation */
1089 MatrixS2XForm(&xformWorld2Vport, &dc->dclevel.mxWorldToDevice);
1090 MatrixS2XForm(&xformWorld2Wnd, &dc->dclevel.mxWorldToPage);
1091 IntGdiCombineTransform(&xformWorld2Vport, &xformWorld2Wnd, &xformWnd2Vport);
1092
1093 /* Create inverse of world-to-viewport transformation */
1094 MatrixS2XForm(&xformVport2World, &dc->dclevel.mxDeviceToWorld);
1095 if (DC_InvertXform(&xformWorld2Vport, &xformVport2World))
1096 {
1097 pdcattr->flXform &= ~DEVICE_TO_WORLD_INVALID;
1098 }
1099 else
1100 {
1101 pdcattr->flXform |= DEVICE_TO_WORLD_INVALID;
1102 }
1103
1104 XForm2MatrixS(&dc->dclevel.mxWorldToDevice, &xformWorld2Vport);
1105
1106 }
1107
1108 LONG FASTCALL
1109 IntCalcFillOrigin(PDC pdc)
1110 {
1111 pdc->ptlFillOrigin.x = pdc->dclevel.ptlBrushOrigin.x + pdc->ptlDCOrig.x;
1112 pdc->ptlFillOrigin.y = pdc->dclevel.ptlBrushOrigin.y + pdc->ptlDCOrig.y;
1113
1114 return pdc->ptlFillOrigin.y;
1115 }
1116
1117 VOID
1118 APIENTRY
1119 GdiSetDCOrg(HDC hDC, LONG Left, LONG Top, PRECTL prc)
1120 {
1121 PDC pdc;
1122
1123 pdc = DC_LockDc(hDC);
1124 if (!pdc) return;
1125
1126 pdc->ptlDCOrig.x = Left;
1127 pdc->ptlDCOrig.y = Top;
1128
1129 IntCalcFillOrigin(pdc);
1130
1131 if (prc) pdc->erclWindow = *prc;
1132
1133 DC_UnlockDc(pdc);
1134 }
1135
1136 // FIXME: remove me
1137 BOOL FASTCALL
1138 IntGdiGetDCOrg(PDC pDc, PPOINTL ppt)
1139 {
1140 *ppt = pDc->ptlDCOrig;
1141 return TRUE;
1142 }
1143
1144 // FIXME: remove me
1145 BOOL APIENTRY
1146 GdiGetDCOrgEx(HDC hDC, PPOINTL ppt, PRECTL prc)
1147 {
1148 PDC pdc;
1149
1150 pdc = DC_LockDc(hDC);
1151 if (!pdc) return FALSE;
1152
1153 *prc = pdc->erclWindow;
1154 *ppt = pdc->ptlDCOrig;
1155
1156 DC_UnlockDc(pdc);
1157 return TRUE;
1158 }
1159
1160 static
1161 VOID FASTCALL
1162 DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio)
1163 {
1164 if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1.
1165 {
1166 // "This specifies that Windows should only match fonts that have the
1167 // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1168 AspectRatio->cx = pDC->ppdev->gdiinfo.ulLogPixelsX;
1169 AspectRatio->cy = pDC->ppdev->gdiinfo.ulLogPixelsY;
1170 }
1171 else
1172 {
1173 AspectRatio->cx = 0;
1174 AspectRatio->cy = 0;
1175 }
1176 }
1177
1178 VOID
1179 FASTCALL
1180 DC_vUpdateViewportExt(PDC pdc)
1181 {
1182 PDC_ATTR pdcattr;
1183
1184 /* Get a pointer to the dc attribute */
1185 pdcattr = pdc->pdcattr;
1186
1187 /* Check if we need to recalculate */
1188 if (pdcattr->flXform & PAGE_EXTENTS_CHANGED)
1189 {
1190 /* Check if we need to do isotropic fixup */
1191 if (pdcattr->iMapMode == MM_ISOTROPIC)
1192 {
1193 IntFixIsotropicMapping(pdc);
1194 }
1195
1196 /* Update xforms, CHECKME: really done here? */
1197 DC_UpdateXforms(pdc);
1198 }
1199 }
1200
1201 BOOL APIENTRY
1202 NtGdiGetDCPoint(
1203 HDC hDC,
1204 UINT iPoint,
1205 PPOINTL Point)
1206 {
1207 BOOL Ret = TRUE;
1208 DC *pdc;
1209 POINTL SafePoint;
1210 SIZE Size;
1211 NTSTATUS Status = STATUS_SUCCESS;
1212
1213 if (!Point)
1214 {
1215 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1216 return FALSE;
1217 }
1218
1219 pdc = DC_LockDc(hDC);
1220 if (!pdc)
1221 {
1222 SetLastWin32Error(ERROR_INVALID_HANDLE);
1223 return FALSE;
1224 }
1225
1226 switch (iPoint)
1227 {
1228 case GdiGetViewPortExt:
1229 DC_vUpdateViewportExt(pdc);
1230 SafePoint.x = pdc->pdcattr->szlViewportExt.cx;
1231 SafePoint.y = pdc->pdcattr->szlViewportExt.cy;
1232 break;
1233
1234 case GdiGetWindowExt:
1235 SafePoint.x = pdc->pdcattr->szlWindowExt.cx;
1236 SafePoint.y = pdc->pdcattr->szlWindowExt.cy;
1237 break;
1238
1239 case GdiGetViewPortOrg:
1240 SafePoint = pdc->pdcattr->ptlViewportOrg;
1241 break;
1242
1243 case GdiGetWindowOrg:
1244 SafePoint = pdc->pdcattr->ptlWindowOrg;
1245 break;
1246
1247 case GdiGetDCOrg:
1248 SafePoint = pdc->ptlDCOrig;
1249 break;
1250
1251 case GdiGetAspectRatioFilter:
1252 DC_vGetAspectRatioFilter(pdc, &Size);
1253 SafePoint.x = Size.cx;
1254 SafePoint.y = Size.cy;
1255 break;
1256
1257 default:
1258 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1259 Ret = FALSE;
1260 break;
1261 }
1262
1263 if (Ret)
1264 {
1265 _SEH2_TRY
1266 {
1267 ProbeForWrite(Point, sizeof(POINT), 1);
1268 *Point = SafePoint;
1269 }
1270 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1271 {
1272 Status = _SEH2_GetExceptionCode();
1273 }
1274 _SEH2_END;
1275
1276 if (!NT_SUCCESS(Status))
1277 {
1278 SetLastNtError(Status);
1279 Ret = FALSE;
1280 }
1281 }
1282
1283 DC_UnlockDc(pdc);
1284 return Ret;
1285 }
1286
1287
1288 DWORD
1289 APIENTRY
1290 NtGdiGetBoundsRect(
1291 IN HDC hdc,
1292 OUT LPRECT prc,
1293 IN DWORD f)
1294 {
1295 DPRINT1("stub\n");
1296 return DCB_RESET; /* bounding rectangle always empty */
1297 }
1298
1299 DWORD
1300 APIENTRY
1301 NtGdiSetBoundsRect(
1302 IN HDC hdc,
1303 IN LPRECT prc,
1304 IN DWORD f)
1305 {
1306 DPRINT1("stub\n");
1307 return DCB_DISABLE; /* bounding rectangle always empty */
1308 }
1309
1310
1311 /* EOF */