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