12cb42a024b272c3ee1de45e0a59969790c7ba2f
[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 <win32k.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 VOID
890 NTAPI
891 DC_vSetLayout(
892 IN PDC pdc,
893 IN LONG wox,
894 IN DWORD dwLayout)
895 {
896 PDC_ATTR pdcattr = pdc->pdcattr;
897
898 pdcattr->dwLayout = dwLayout;
899
900 if (!(dwLayout & LAYOUT_ORIENTATIONMASK)) return;
901
902 if (dwLayout & LAYOUT_RTL)
903 {
904 pdcattr->iMapMode = MM_ANISOTROPIC;
905 }
906
907 pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy;
908 pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x;
909
910 if (wox == -1)
911 IntMirrorWindowOrg(pdc);
912 else
913 pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x;
914
915 if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT;
916
917 if (pdc->dclevel.flPath & DCPATH_CLOCKWISE)
918 pdc->dclevel.flPath &= ~DCPATH_CLOCKWISE;
919 else
920 pdc->dclevel.flPath |= DCPATH_CLOCKWISE;
921
922 pdcattr->flXform |= (PAGE_EXTENTS_CHANGED |
923 INVALIDATE_ATTRIBUTES |
924 DEVICE_TO_WORLD_INVALID);
925
926 // DC_UpdateXforms(pdc);
927 }
928
929 // NtGdiSetLayout
930 //
931 // The default is left to right. This function changes it to right to left, which
932 // is the standard in Arabic and Hebrew cultures.
933 //
934 /*
935 * @implemented
936 */
937 DWORD
938 APIENTRY
939 NtGdiSetLayout(
940 IN HDC hdc,
941 IN LONG wox,
942 IN DWORD dwLayout)
943 {
944 PDC pdc;
945 PDC_ATTR pdcattr;
946 DWORD oLayout;
947
948 pdc = DC_LockDc(hdc);
949 if (!pdc)
950 {
951 SetLastWin32Error(ERROR_INVALID_HANDLE);
952 return GDI_ERROR;
953 }
954 pdcattr = pdc->pdcattr;
955
956 oLayout = pdcattr->dwLayout;
957 DC_vSetLayout(pdc, wox, dwLayout);
958
959 DC_UnlockDc(pdc);
960 return oLayout;
961 }
962
963 /*
964 * @implemented
965 */
966 LONG
967 APIENTRY
968 NtGdiGetDeviceWidth(
969 IN HDC hdc)
970 {
971 PDC dc;
972 LONG Ret;
973 dc = DC_LockDc(hdc);
974 if (!dc)
975 {
976 SetLastWin32Error(ERROR_INVALID_HANDLE);
977 return 0;
978 }
979 Ret = dc->erclWindow.right - dc->erclWindow.left;
980 DC_UnlockDc(dc);
981 return Ret;
982 }
983
984 /*
985 * @implemented
986 */
987 BOOL
988 APIENTRY
989 NtGdiMirrorWindowOrg(
990 IN HDC hdc)
991 {
992 PDC dc;
993 dc = DC_LockDc(hdc);
994 if (!dc)
995 {
996 SetLastWin32Error(ERROR_INVALID_HANDLE);
997 return FALSE;
998 }
999 IntMirrorWindowOrg(dc);
1000 DC_UnlockDc(dc);
1001 return TRUE;
1002 }
1003
1004 /*
1005 * @implemented
1006 */
1007 BOOL
1008 APIENTRY
1009 NtGdiSetSizeDevice(
1010 IN HDC hdc,
1011 IN INT cxVirtualDevice,
1012 IN INT cyVirtualDevice)
1013 {
1014 PDC dc;
1015 PDC_ATTR pdcattr;
1016
1017 if (!cxVirtualDevice || !cyVirtualDevice)
1018 {
1019 return FALSE;
1020 }
1021
1022 dc = DC_LockDc(hdc);
1023 if (!dc) return FALSE;
1024
1025 pdcattr = dc->pdcattr;
1026
1027 pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice;
1028 pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice;
1029
1030 // DC_UpdateXforms(dc);
1031 DC_UnlockDc(dc);
1032
1033 return TRUE;
1034 }
1035
1036 /*
1037 * @implemented
1038 */
1039 BOOL
1040 APIENTRY
1041 NtGdiSetVirtualResolution(
1042 IN HDC hdc,
1043 IN INT cxVirtualDevicePixel,
1044 IN INT cyVirtualDevicePixel,
1045 IN INT cxVirtualDeviceMm,
1046 IN INT cyVirtualDeviceMm)
1047 {
1048 PDC dc;
1049 PDC_ATTR pdcattr;
1050
1051 /* Check parameters (all zeroes resets to real resolution) */
1052 if (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 &&
1053 cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0)
1054 {
1055 cxVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, HORZRES);
1056 cyVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, VERTRES);
1057 cxVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, HORZSIZE);
1058 cyVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, VERTSIZE);
1059 }
1060 else if (cxVirtualDevicePixel == 0 || cyVirtualDevicePixel == 0 ||
1061 cxVirtualDeviceMm == 0 || cyVirtualDeviceMm == 0)
1062 {
1063 return FALSE;
1064 }
1065
1066 dc = DC_LockDc(hdc);
1067 if (!dc) return FALSE;
1068
1069 pdcattr = dc->pdcattr;
1070
1071 pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel;
1072 pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel;
1073 pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm;
1074 pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm;
1075
1076 // DC_UpdateXforms(dc);
1077 DC_UnlockDc(dc);
1078 return TRUE;
1079 }
1080
1081
1082 // FIXME: Don't use floating point in the kernel!
1083 BOOL FASTCALL
1084 DC_InvertXform(const XFORM *xformSrc,
1085 XFORM *xformDest)
1086 {
1087 FLOAT determinant;
1088
1089 determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21;
1090 if (determinant > -1e-12 && determinant < 1e-12)
1091 {
1092 return FALSE;
1093 }
1094
1095 xformDest->eM11 = xformSrc->eM22 / determinant;
1096 xformDest->eM12 = -xformSrc->eM12 / determinant;
1097 xformDest->eM21 = -xformSrc->eM21 / determinant;
1098 xformDest->eM22 = xformSrc->eM11 / determinant;
1099 xformDest->eDx = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21;
1100 xformDest->eDy = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22;
1101
1102 return TRUE;
1103 }
1104
1105 VOID FASTCALL
1106 DC_UpdateXforms(PDC dc)
1107 {
1108 XFORM xformWnd2Vport;
1109 PDC_ATTR pdcattr = dc->pdcattr;
1110 XFORM xformWorld2Vport, xformWorld2Wnd, xformVport2World;
1111
1112 /* Construct a transformation to do the window-to-viewport conversion */
1113 IntWindowToViewPort(pdcattr, &xformWnd2Vport);
1114
1115 /* Combine with the world transformation */
1116 MatrixS2XForm(&xformWorld2Vport, &dc->dclevel.mxWorldToDevice);
1117 MatrixS2XForm(&xformWorld2Wnd, &dc->dclevel.mxWorldToPage);
1118 IntGdiCombineTransform(&xformWorld2Vport, &xformWorld2Wnd, &xformWnd2Vport);
1119
1120 /* Create inverse of world-to-viewport transformation */
1121 MatrixS2XForm(&xformVport2World, &dc->dclevel.mxDeviceToWorld);
1122 if (DC_InvertXform(&xformWorld2Vport, &xformVport2World))
1123 {
1124 pdcattr->flXform &= ~DEVICE_TO_WORLD_INVALID;
1125 }
1126 else
1127 {
1128 pdcattr->flXform |= DEVICE_TO_WORLD_INVALID;
1129 }
1130
1131 /* Update transformation matrices */
1132 XForm2MatrixS(&dc->dclevel.mxWorldToDevice, &xformWorld2Vport);
1133 XForm2MatrixS(&dc->dclevel.mxDeviceToWorld, &xformVport2World);
1134 }
1135
1136 LONG FASTCALL
1137 IntCalcFillOrigin(PDC pdc)
1138 {
1139 pdc->ptlFillOrigin.x = pdc->dclevel.ptlBrushOrigin.x + pdc->ptlDCOrig.x;
1140 pdc->ptlFillOrigin.y = pdc->dclevel.ptlBrushOrigin.y + pdc->ptlDCOrig.y;
1141
1142 return pdc->ptlFillOrigin.y;
1143 }
1144
1145 PPOINTL
1146 FASTCALL
1147 IntptlBrushOrigin(PDC pdc, LONG x, LONG y )
1148 {
1149 pdc->dclevel.ptlBrushOrigin.x = x;
1150 pdc->dclevel.ptlBrushOrigin.y = y;
1151 IntCalcFillOrigin(pdc);
1152 return &pdc->dclevel.ptlBrushOrigin;
1153 }
1154
1155 VOID
1156 APIENTRY
1157 GdiSetDCOrg(HDC hDC, LONG Left, LONG Top, PRECTL prc)
1158 {
1159 PDC pdc;
1160
1161 pdc = DC_LockDc(hDC);
1162 if (!pdc) return;
1163
1164 pdc->ptlDCOrig.x = Left;
1165 pdc->ptlDCOrig.y = Top;
1166
1167 IntCalcFillOrigin(pdc);
1168
1169 if (prc) pdc->erclWindow = *prc;
1170
1171 DC_UnlockDc(pdc);
1172 }
1173
1174 // FIXME: remove me
1175 BOOL FASTCALL
1176 IntGdiGetDCOrg(PDC pDc, PPOINTL ppt)
1177 {
1178 *ppt = pDc->ptlDCOrig;
1179 return TRUE;
1180 }
1181
1182 // FIXME: remove me
1183 BOOL APIENTRY
1184 GdiGetDCOrgEx(HDC hDC, PPOINTL ppt, PRECTL prc)
1185 {
1186 PDC pdc;
1187
1188 pdc = DC_LockDc(hDC);
1189 if (!pdc) return FALSE;
1190
1191 *prc = pdc->erclWindow;
1192 *ppt = pdc->ptlDCOrig;
1193
1194 DC_UnlockDc(pdc);
1195 return TRUE;
1196 }
1197
1198 static
1199 VOID FASTCALL
1200 DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio)
1201 {
1202 if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1.
1203 {
1204 // "This specifies that Windows should only match fonts that have the
1205 // same aspect ratio as the display.", Programming Windows, Fifth Ed.
1206 AspectRatio->cx = pDC->ppdev->gdiinfo.ulLogPixelsX;
1207 AspectRatio->cy = pDC->ppdev->gdiinfo.ulLogPixelsY;
1208 }
1209 else
1210 {
1211 AspectRatio->cx = 0;
1212 AspectRatio->cy = 0;
1213 }
1214 }
1215
1216 VOID
1217 FASTCALL
1218 DC_vUpdateViewportExt(PDC pdc)
1219 {
1220 PDC_ATTR pdcattr;
1221
1222 /* Get a pointer to the dc attribute */
1223 pdcattr = pdc->pdcattr;
1224
1225 /* Check if we need to recalculate */
1226 if (pdcattr->flXform & PAGE_EXTENTS_CHANGED)
1227 {
1228 /* Check if we need to do isotropic fixup */
1229 if (pdcattr->iMapMode == MM_ISOTROPIC)
1230 {
1231 IntFixIsotropicMapping(pdc);
1232 }
1233
1234 /* Update xforms, CHECKME: really done here? */
1235 DC_UpdateXforms(pdc);
1236 }
1237 }
1238
1239 BOOL APIENTRY
1240 NtGdiGetDCPoint(
1241 HDC hDC,
1242 UINT iPoint,
1243 PPOINTL Point)
1244 {
1245 BOOL Ret = TRUE;
1246 DC *pdc;
1247 POINTL SafePoint;
1248 SIZE Size;
1249 NTSTATUS Status = STATUS_SUCCESS;
1250
1251 if (!Point)
1252 {
1253 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1254 return FALSE;
1255 }
1256
1257 pdc = DC_LockDc(hDC);
1258 if (!pdc)
1259 {
1260 SetLastWin32Error(ERROR_INVALID_HANDLE);
1261 return FALSE;
1262 }
1263
1264 switch (iPoint)
1265 {
1266 case GdiGetViewPortExt:
1267 DC_vUpdateViewportExt(pdc);
1268 SafePoint.x = pdc->pdcattr->szlViewportExt.cx;
1269 SafePoint.y = pdc->pdcattr->szlViewportExt.cy;
1270 break;
1271
1272 case GdiGetWindowExt:
1273 SafePoint.x = pdc->pdcattr->szlWindowExt.cx;
1274 SafePoint.y = pdc->pdcattr->szlWindowExt.cy;
1275 break;
1276
1277 case GdiGetViewPortOrg:
1278 SafePoint = pdc->pdcattr->ptlViewportOrg;
1279 break;
1280
1281 case GdiGetWindowOrg:
1282 SafePoint = pdc->pdcattr->ptlWindowOrg;
1283 break;
1284
1285 case GdiGetDCOrg:
1286 SafePoint = pdc->ptlDCOrig;
1287 break;
1288
1289 case GdiGetAspectRatioFilter:
1290 DC_vGetAspectRatioFilter(pdc, &Size);
1291 SafePoint.x = Size.cx;
1292 SafePoint.y = Size.cy;
1293 break;
1294
1295 default:
1296 SetLastWin32Error(ERROR_INVALID_PARAMETER);
1297 Ret = FALSE;
1298 break;
1299 }
1300
1301 if (Ret)
1302 {
1303 _SEH2_TRY
1304 {
1305 ProbeForWrite(Point, sizeof(POINT), 1);
1306 *Point = SafePoint;
1307 }
1308 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1309 {
1310 Status = _SEH2_GetExceptionCode();
1311 }
1312 _SEH2_END;
1313
1314 if (!NT_SUCCESS(Status))
1315 {
1316 SetLastNtError(Status);
1317 Ret = FALSE;
1318 }
1319 }
1320
1321 DC_UnlockDc(pdc);
1322 return Ret;
1323 }
1324
1325
1326 DWORD
1327 APIENTRY
1328 NtGdiGetBoundsRect(
1329 IN HDC hdc,
1330 OUT LPRECT prc,
1331 IN DWORD f)
1332 {
1333 DPRINT1("stub\n");
1334 return DCB_RESET; /* bounding rectangle always empty */
1335 }
1336
1337 DWORD
1338 APIENTRY
1339 NtGdiSetBoundsRect(
1340 IN HDC hdc,
1341 IN LPRECT prc,
1342 IN DWORD f)
1343 {
1344 DPRINT1("stub\n");
1345 return DCB_DISABLE; /* bounding rectangle always empty */
1346 }
1347
1348
1349 /* EOF */