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