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