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