/* * ReactOS W32 Subsystem * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * PURPOSE: Coordinate systems * FILE: subsys/win32k/objects/coord.c * PROGRAMER: Unknown */ /* INCLUDES ******************************************************************/ #include #define NDEBUG #include /* FUNCTIONS *****************************************************************/ void FASTCALL IntFixIsotropicMapping(PDC dc) { PDC_ATTR pdcattr; LONG fx, fy, s; /* Get a pointer to the DC_ATTR */ pdcattr = dc->pdcattr; /* Check if all values are valid */ if (pdcattr->szlWindowExt.cx == 0 || pdcattr->szlWindowExt.cy == 0 || pdcattr->szlViewportExt.cx == 0 || pdcattr->szlViewportExt.cy == 0) { /* Don't recalculate */ return; } fx = abs(pdcattr->szlWindowExt.cx * pdcattr->szlViewportExt.cy); fy = abs(pdcattr->szlWindowExt.cy * pdcattr->szlViewportExt.cx); if (fy > fx) { s = pdcattr->szlWindowExt.cy * pdcattr->szlViewportExt.cx > 0 ? 1 : -1; pdcattr->szlViewportExt.cx = s * fx / pdcattr->szlWindowExt.cy; } else if (fx > fy) { s = pdcattr->szlWindowExt.cx * pdcattr->szlViewportExt.cy > 0 ? 1 : -1; pdcattr->szlViewportExt.cy = s * fy / pdcattr->szlWindowExt.cx; } } // FIXME: don't use floating point in the kernel! use XFORMOBJ function BOOL FASTCALL IntGdiCombineTransform( LPXFORM XFormResult, LPXFORM xform1, LPXFORM xform2) { XFORM xformTemp; /* Check for illegal parameters */ if (!XFormResult || !xform1 || !xform2) { return FALSE; } /* Create the result in a temporary XFORM, since xformResult may be * equal to xform1 or xform2 */ xformTemp.eM11 = xform1->eM11 * xform2->eM11 + xform1->eM12 * xform2->eM21; xformTemp.eM12 = xform1->eM11 * xform2->eM12 + xform1->eM12 * xform2->eM22; xformTemp.eM21 = xform1->eM21 * xform2->eM11 + xform1->eM22 * xform2->eM21; xformTemp.eM22 = xform1->eM21 * xform2->eM12 + xform1->eM22 * xform2->eM22; xformTemp.eDx = xform1->eDx * xform2->eM11 + xform1->eDy * xform2->eM21 + xform2->eDx; xformTemp.eDy = xform1->eDx * xform2->eM12 + xform1->eDy * xform2->eM22 + xform2->eDy; *XFormResult = xformTemp; return TRUE; } // FIXME: should be XFORML and use XFORMOBJ functions BOOL APIENTRY NtGdiCombineTransform( LPXFORM UnsafeXFormResult, LPXFORM Unsafexform1, LPXFORM Unsafexform2) { BOOL Ret; _SEH2_TRY { ProbeForWrite(UnsafeXFormResult, sizeof(XFORM), 1); ProbeForRead(Unsafexform1, sizeof(XFORM), 1); ProbeForRead(Unsafexform2, sizeof(XFORM), 1); Ret = IntGdiCombineTransform(UnsafeXFormResult, Unsafexform1, Unsafexform2); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Ret = FALSE; } _SEH2_END; return Ret; } // FIXME: Don't use floating point in the kernel BOOL FASTCALL IntGdiModifyWorldTransform( PDC pDc, CONST LPXFORM lpXForm, DWORD Mode) { XFORM xformWorld2Wnd; ASSERT(pDc); switch (Mode) { case MWT_IDENTITY: xformWorld2Wnd.eM11 = 1.0f; xformWorld2Wnd.eM12 = 0.0f; xformWorld2Wnd.eM21 = 0.0f; xformWorld2Wnd.eM22 = 1.0f; xformWorld2Wnd.eDx = 0.0f; xformWorld2Wnd.eDy = 0.0f; XForm2MatrixS(&pDc->dclevel.mxWorldToPage, &xformWorld2Wnd); break; case MWT_LEFTMULTIPLY: MatrixS2XForm(&xformWorld2Wnd, &pDc->dclevel.mxWorldToPage); IntGdiCombineTransform(&xformWorld2Wnd, lpXForm, &xformWorld2Wnd); XForm2MatrixS(&pDc->dclevel.mxWorldToPage, &xformWorld2Wnd); break; case MWT_RIGHTMULTIPLY: MatrixS2XForm(&xformWorld2Wnd, &pDc->dclevel.mxWorldToPage); IntGdiCombineTransform(&xformWorld2Wnd, &xformWorld2Wnd, lpXForm); XForm2MatrixS(&pDc->dclevel.mxWorldToPage, &xformWorld2Wnd); break; case MWT_MAX+1: // Must be MWT_SET???? XForm2MatrixS(&pDc->dclevel.mxWorldToPage, lpXForm); // Do it like Wine. break; default: return FALSE; } DC_UpdateXforms(pDc); return TRUE; } // FIXME: Don't use floating point in the kernel! void IntWindowToViewPort(PDC_ATTR pdcattr, LPXFORM xformWnd2Vport) { FLOAT scaleX, scaleY; scaleX = (pdcattr->szlWindowExt.cx ? (FLOAT)pdcattr->szlViewportExt.cx / (FLOAT)pdcattr->szlWindowExt.cx : 0.0f); scaleY = (pdcattr->szlWindowExt.cy ? (FLOAT)pdcattr->szlViewportExt.cy / (FLOAT)pdcattr->szlWindowExt.cy : 0.0f); xformWnd2Vport->eM11 = scaleX; xformWnd2Vport->eM12 = 0.0; xformWnd2Vport->eM21 = 0.0; xformWnd2Vport->eM22 = scaleY; xformWnd2Vport->eDx = (FLOAT)pdcattr->ptlViewportOrg.x - scaleX * (FLOAT)pdcattr->ptlWindowOrg.x; xformWnd2Vport->eDy = (FLOAT)pdcattr->ptlViewportOrg.y - scaleY * (FLOAT)pdcattr->ptlWindowOrg.y; } // FIXME: Should be XFORML and use XFORMOBJ functions directly BOOL APIENTRY NtGdiGetTransform( HDC hDC, DWORD iXform, LPXFORM XForm) { PDC dc; NTSTATUS Status = STATUS_SUCCESS; dc = DC_LockDc(hDC); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } if (!XForm) { DC_UnlockDc(dc); SetLastWin32Error(ERROR_INVALID_PARAMETER); return FALSE; } _SEH2_TRY { ProbeForWrite(XForm, sizeof(XFORM), 1); switch (iXform) { case GdiWorldSpaceToPageSpace: MatrixS2XForm(XForm, &dc->dclevel.mxWorldToPage); break; case GdiWorldSpaceToDeviceSpace: MatrixS2XForm(XForm, &dc->dclevel.mxWorldToDevice); break; case GdiPageSpaceToDeviceSpace: IntWindowToViewPort(dc->pdcattr, XForm); break; case GdiDeviceSpaceToWorldSpace: MatrixS2XForm(XForm, &dc->dclevel.mxDeviceToWorld); break; default: DPRINT1("Unknown transform %lu\n", iXform); Status = STATUS_INVALID_PARAMETER; break; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; DC_UnlockDc(dc); return NT_SUCCESS(Status); } /*! * Converts points from logical coordinates into device coordinates. Conversion depends on the mapping mode, * world transfrom, viewport origin settings for the given device context. * \param hDC device context. * \param Points an array of POINT structures (in/out). * \param Count number of elements in the array of POINT structures. * \return TRUE if success. */ BOOL APIENTRY NtGdiTransformPoints( HDC hDC, PPOINT UnsafePtsIn, PPOINT UnsafePtOut, INT Count, INT iMode) { PDC dc; NTSTATUS Status = STATUS_SUCCESS; LPPOINT Points; ULONG Size; dc = DC_LockDc(hDC); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } if (!UnsafePtsIn || !UnsafePtOut || Count <= 0) { DC_UnlockDc(dc); SetLastWin32Error(ERROR_INVALID_PARAMETER); return FALSE; } Size = Count * sizeof(POINT); // FIXME: It would be wise to have a small stack buffer as optimization Points = ExAllocatePoolWithTag(PagedPool, Size, TAG_COORD); if (!Points) { DC_UnlockDc(dc); SetLastWin32Error(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } _SEH2_TRY { ProbeForWrite(UnsafePtOut, Size, 1); ProbeForRead(UnsafePtsIn, Size, 1); RtlCopyMemory(Points, UnsafePtsIn, Size); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { DC_UnlockDc(dc); ExFreePoolWithTag(Points, TAG_COORD); SetLastNtError(Status); return FALSE; } switch (iMode) { case GdiDpToLp: IntDPtoLP(dc, Points, Count); break; case GdiLpToDp: IntLPtoDP(dc, Points, Count); break; case 2: // Not supported yet. Need testing. default: { DC_UnlockDc(dc); ExFreePoolWithTag(Points, TAG_COORD); SetLastWin32Error(ERROR_INVALID_PARAMETER); return FALSE; } } _SEH2_TRY { /* pointer was already probed! */ RtlCopyMemory(UnsafePtOut, Points, Size); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { DC_UnlockDc(dc); ExFreePoolWithTag(Points, TAG_COORD); SetLastNtError(Status); return FALSE; } // // If we are getting called that means User XForms is a mess! // DC_UnlockDc(dc); ExFreePoolWithTag(Points, TAG_COORD); return TRUE; } BOOL APIENTRY NtGdiModifyWorldTransform( HDC hDC, LPXFORM UnsafeXForm, DWORD Mode) { PDC dc; XFORM SafeXForm; BOOL Ret = TRUE; dc = DC_LockDc(hDC); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } // The xform is permitted to be NULL for MWT_IDENTITY. // However, if it is not NULL, then it must be valid even though it is not used. if (UnsafeXForm != NULL || Mode != MWT_IDENTITY) { _SEH2_TRY { ProbeForRead(UnsafeXForm, sizeof(XFORM), 1); RtlCopyMemory(&SafeXForm, UnsafeXForm, sizeof(XFORM)); } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Ret = FALSE; } _SEH2_END; } // Safe to handle kernel mode data. if (Ret) Ret = IntGdiModifyWorldTransform(dc, &SafeXForm, Mode); DC_UnlockDc(dc); return Ret; } BOOL APIENTRY NtGdiOffsetViewportOrgEx( HDC hDC, int XOffset, int YOffset, LPPOINT UnsafePoint) { PDC dc; PDC_ATTR pdcattr; NTSTATUS Status = STATUS_SUCCESS; dc = DC_LockDc(hDC); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } pdcattr = dc->pdcattr; if (UnsafePoint) { _SEH2_TRY { ProbeForWrite(UnsafePoint, sizeof(POINT), 1); UnsafePoint->x = pdcattr->ptlViewportOrg.x; UnsafePoint->y = pdcattr->ptlViewportOrg.y; if (pdcattr->dwLayout & LAYOUT_RTL) { UnsafePoint->x = -UnsafePoint->x; } } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { SetLastNtError(Status); DC_UnlockDc(dc); return FALSE; } } if (pdcattr->dwLayout & LAYOUT_RTL) { XOffset = -XOffset; } pdcattr->ptlViewportOrg.x += XOffset; pdcattr->ptlViewportOrg.y += YOffset; DC_UpdateXforms(dc); DC_UnlockDc(dc); return TRUE; } BOOL APIENTRY NtGdiOffsetWindowOrgEx( HDC hDC, int XOffset, int YOffset, LPPOINT Point) { PDC dc; PDC_ATTR pdcattr; dc = DC_LockDc(hDC); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } pdcattr = dc->pdcattr; if (Point) { NTSTATUS Status = STATUS_SUCCESS; _SEH2_TRY { ProbeForWrite(Point, sizeof(POINT), 1); Point->x = pdcattr->ptlWindowOrg.x; Point->y = pdcattr->ptlWindowOrg.y; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { SetLastNtError(Status); DC_UnlockDc(dc); return FALSE; } } pdcattr->ptlWindowOrg.x += XOffset; pdcattr->ptlWindowOrg.y += YOffset; DC_UpdateXforms(dc); DC_UnlockDc(dc); return TRUE; } BOOL APIENTRY NtGdiScaleViewportExtEx( HDC hDC, int Xnum, int Xdenom, int Ynum, int Ydenom, LPSIZE pSize) { PDC pDC; PDC_ATTR pdcattr; BOOL Ret = FALSE; LONG X, Y; pDC = DC_LockDc(hDC); if (!pDC) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } pdcattr = pDC->pdcattr; if (pSize) { NTSTATUS Status = STATUS_SUCCESS; _SEH2_TRY { ProbeForWrite(pSize, sizeof(LPSIZE), 1); pSize->cx = pdcattr->szlViewportExt.cx; pSize->cy = pdcattr->szlViewportExt.cy; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { SetLastNtError(Status); DC_UnlockDc(pDC); return FALSE; } } if (pdcattr->iMapMode > MM_TWIPS) { if (Xdenom && Ydenom) { X = Xnum * pdcattr->szlViewportExt.cx / Xdenom; if (X) { Y = Ynum * pdcattr->szlViewportExt.cy / Ydenom; if (Y) { pdcattr->szlViewportExt.cx = X; pdcattr->szlViewportExt.cy = Y; IntMirrorWindowOrg(pDC); pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | INVALIDATE_ATTRIBUTES | DEVICE_TO_WORLD_INVALID); if (pdcattr->iMapMode == MM_ISOTROPIC) { IntFixIsotropicMapping(pDC); } DC_UpdateXforms(pDC); Ret = TRUE; } } } } else Ret = TRUE; DC_UnlockDc(pDC); return Ret; } BOOL APIENTRY NtGdiScaleWindowExtEx( HDC hDC, int Xnum, int Xdenom, int Ynum, int Ydenom, LPSIZE pSize) { PDC pDC; PDC_ATTR pdcattr; BOOL Ret = FALSE; LONG X, Y; pDC = DC_LockDc(hDC); if (!pDC) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } pdcattr = pDC->pdcattr; if (pSize) { NTSTATUS Status = STATUS_SUCCESS; _SEH2_TRY { ProbeForWrite(pSize, sizeof(LPSIZE), 1); X = pdcattr->szlWindowExt.cx; if (pdcattr->dwLayout & LAYOUT_RTL) X = -X; pSize->cx = X; pSize->cy = pdcattr->szlWindowExt.cy; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { SetLastNtError(Status); DC_UnlockDc(pDC); return FALSE; } } if (pdcattr->iMapMode > MM_TWIPS) { if (Xdenom && Ydenom) { X = Xnum * pdcattr->szlWindowExt.cx / Xdenom; if (X) { Y = Ynum * pdcattr->szlWindowExt.cy / Ydenom; if (Y) { pdcattr->szlWindowExt.cx = X; pdcattr->szlWindowExt.cy = Y; IntMirrorWindowOrg(pDC); pdcattr->flXform |= (PAGE_EXTENTS_CHANGED|INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID); if (pdcattr->iMapMode == MM_ISOTROPIC) IntFixIsotropicMapping(pDC); DC_UpdateXforms(pDC); Ret = TRUE; } } } } else Ret = TRUE; DC_UnlockDc(pDC); return Ret; } int APIENTRY IntGdiSetMapMode( PDC dc, int MapMode) { int PrevMapMode; PDC_ATTR pdcattr = dc->pdcattr; PrevMapMode = pdcattr->iMapMode; pdcattr->iMapMode = MapMode; switch (MapMode) { case MM_TEXT: pdcattr->szlWindowExt.cx = 1; pdcattr->szlWindowExt.cy = 1; pdcattr->szlViewportExt.cx = 1; pdcattr->szlViewportExt.cy = 1; pdcattr->flXform &= ~(ISO_OR_ANISO_MAP_MODE|PTOD_EFM22_NEGATIVE| PTOD_EFM11_NEGATIVE|POSITIVE_Y_IS_UP); pdcattr->flXform |= (PAGE_XLATE_CHANGED|PAGE_TO_DEVICE_SCALE_IDENTITY| INVALIDATE_ATTRIBUTES|DEVICE_TO_WORLD_INVALID); break; case MM_ISOTROPIC: pdcattr->flXform |= ISO_OR_ANISO_MAP_MODE; /* Fall through */ case MM_LOMETRIC: pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 10; pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 10; pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; break; case MM_HIMETRIC: pdcattr->szlWindowExt.cx = pdcattr->szlVirtualDeviceMm.cx * 100; pdcattr->szlWindowExt.cy = pdcattr->szlVirtualDeviceMm.cy * 100; pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; break; case MM_LOENGLISH: pdcattr->szlWindowExt.cx = MulDiv(1000, pdcattr->szlVirtualDeviceMm.cx, 254); pdcattr->szlWindowExt.cy = MulDiv(1000, pdcattr->szlVirtualDeviceMm.cy, 254); pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; break; case MM_HIENGLISH: pdcattr->szlWindowExt.cx = MulDiv(10000, pdcattr->szlVirtualDeviceMm.cx, 254); pdcattr->szlWindowExt.cy = MulDiv(10000, pdcattr->szlVirtualDeviceMm.cy, 254); pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; break; case MM_TWIPS: pdcattr->szlWindowExt.cx = MulDiv(14400, pdcattr->szlVirtualDeviceMm.cx, 254); pdcattr->szlWindowExt.cy = MulDiv(14400, pdcattr->szlVirtualDeviceMm.cy, 254); pdcattr->szlViewportExt.cx = pdcattr->szlVirtualDevicePixel.cx; pdcattr->szlViewportExt.cy = -pdcattr->szlVirtualDevicePixel.cy; break; case MM_ANISOTROPIC: pdcattr->flXform &= ~(PAGE_TO_DEVICE_IDENTITY|POSITIVE_Y_IS_UP); pdcattr->flXform |= ISO_OR_ANISO_MAP_MODE; break; default: pdcattr->iMapMode = PrevMapMode; PrevMapMode = 0; } DC_UpdateXforms(dc); return PrevMapMode; } BOOL APIENTRY NtGdiSetViewportOrgEx( HDC hDC, int X, int Y, LPPOINT Point) { PDC dc; PDC_ATTR pdcattr; dc = DC_LockDc(hDC); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } pdcattr = dc->pdcattr; if (Point) { NTSTATUS Status = STATUS_SUCCESS; _SEH2_TRY { ProbeForWrite(Point, sizeof(POINT), 1); Point->x = pdcattr->ptlViewportOrg.x; Point->y = pdcattr->ptlViewportOrg.y; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { SetLastNtError(Status); DC_UnlockDc(dc); return FALSE; } } pdcattr->ptlViewportOrg.x = X; pdcattr->ptlViewportOrg.y = Y; DC_UpdateXforms(dc); DC_UnlockDc(dc); return TRUE; } BOOL APIENTRY NtGdiSetWindowOrgEx( HDC hDC, int X, int Y, LPPOINT Point) { PDC dc; PDC_ATTR pdcattr; dc = DC_LockDc(hDC); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } pdcattr = dc->pdcattr; if (Point) { NTSTATUS Status = STATUS_SUCCESS; _SEH2_TRY { ProbeForWrite(Point, sizeof(POINT), 1); Point->x = pdcattr->ptlWindowOrg.x; Point->y = pdcattr->ptlWindowOrg.y; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { SetLastNtError(Status); DC_UnlockDc(dc); return FALSE; } } pdcattr->ptlWindowOrg.x = X; pdcattr->ptlWindowOrg.y = Y; DC_UpdateXforms(dc); DC_UnlockDc(dc); return TRUE; } // // Mirror Window function. // VOID FASTCALL IntMirrorWindowOrg(PDC dc) { PDC_ATTR pdcattr; LONG X; pdcattr = dc->pdcattr; if (!(pdcattr->dwLayout & LAYOUT_RTL)) { pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx; // Flip it back. return; } if (!pdcattr->szlViewportExt.cx) return; // // WOrgx = wox - (Width - 1) * WExtx / VExtx // X = (dc->erclWindow.right - dc->erclWindow.left) - 1; // Get device width - 1 X = (X * pdcattr->szlWindowExt.cx) / pdcattr->szlViewportExt.cx; pdcattr->ptlWindowOrg.x = pdcattr->lWindowOrgx - X; // Now set the inverted win origion. return; } // NtGdiSetLayout // // The default is left to right. This function changes it to right to left, which // is the standard in Arabic and Hebrew cultures. // /* * @implemented */ DWORD APIENTRY NtGdiSetLayout( IN HDC hdc, IN LONG wox, IN DWORD dwLayout) { PDC dc; PDC_ATTR pdcattr; DWORD oLayout; dc = DC_LockDc(hdc); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return GDI_ERROR; } pdcattr = dc->pdcattr; pdcattr->dwLayout = dwLayout; oLayout = pdcattr->dwLayout; if (!(dwLayout & LAYOUT_ORIENTATIONMASK)) { DC_UnlockDc(dc); return oLayout; } if (dwLayout & LAYOUT_RTL) { pdcattr->iMapMode = MM_ANISOTROPIC; } pdcattr->szlWindowExt.cy = -pdcattr->szlWindowExt.cy; pdcattr->ptlWindowOrg.x = -pdcattr->ptlWindowOrg.x; if (wox == -1) IntMirrorWindowOrg(dc); else pdcattr->ptlWindowOrg.x = wox - pdcattr->ptlWindowOrg.x; if (!(pdcattr->flTextAlign & TA_CENTER)) pdcattr->flTextAlign |= TA_RIGHT; if (dc->dclevel.flPath & DCPATH_CLOCKWISE) dc->dclevel.flPath &= ~DCPATH_CLOCKWISE; else dc->dclevel.flPath |= DCPATH_CLOCKWISE; pdcattr->flXform |= (PAGE_EXTENTS_CHANGED | INVALIDATE_ATTRIBUTES | DEVICE_TO_WORLD_INVALID); // DC_UpdateXforms(dc); DC_UnlockDc(dc); return oLayout; } /* * @implemented */ LONG APIENTRY NtGdiGetDeviceWidth( IN HDC hdc) { PDC dc; LONG Ret; dc = DC_LockDc(hdc); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return 0; } Ret = dc->erclWindow.right - dc->erclWindow.left; DC_UnlockDc(dc); return Ret; } /* * @implemented */ BOOL APIENTRY NtGdiMirrorWindowOrg( IN HDC hdc) { PDC dc; dc = DC_LockDc(hdc); if (!dc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } IntMirrorWindowOrg(dc); DC_UnlockDc(dc); return TRUE; } /* * @implemented */ BOOL APIENTRY NtGdiSetSizeDevice( IN HDC hdc, IN INT cxVirtualDevice, IN INT cyVirtualDevice) { PDC dc; PDC_ATTR pdcattr; if (!cxVirtualDevice || !cyVirtualDevice) { return FALSE; } dc = DC_LockDc(hdc); if (!dc) return FALSE; pdcattr = dc->pdcattr; pdcattr->szlVirtualDeviceSize.cx = cxVirtualDevice; pdcattr->szlVirtualDeviceSize.cy = cyVirtualDevice; // DC_UpdateXforms(dc); DC_UnlockDc(dc); return TRUE; } /* * @implemented */ BOOL APIENTRY NtGdiSetVirtualResolution( IN HDC hdc, IN INT cxVirtualDevicePixel, IN INT cyVirtualDevicePixel, IN INT cxVirtualDeviceMm, IN INT cyVirtualDeviceMm) { PDC dc; PDC_ATTR pdcattr; /* Check parameters (all zeroes resets to real resolution) */ if (cxVirtualDevicePixel == 0 && cyVirtualDevicePixel == 0 && cxVirtualDeviceMm == 0 && cyVirtualDeviceMm == 0) { cxVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, HORZRES); cyVirtualDevicePixel = NtGdiGetDeviceCaps(hdc, VERTRES); cxVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, HORZSIZE); cyVirtualDeviceMm = NtGdiGetDeviceCaps(hdc, VERTSIZE); } else if (cxVirtualDevicePixel == 0 || cyVirtualDevicePixel == 0 || cxVirtualDeviceMm == 0 || cyVirtualDeviceMm == 0) { return FALSE; } dc = DC_LockDc(hdc); if (!dc) return FALSE; pdcattr = dc->pdcattr; pdcattr->szlVirtualDevicePixel.cx = cxVirtualDevicePixel; pdcattr->szlVirtualDevicePixel.cy = cyVirtualDevicePixel; pdcattr->szlVirtualDeviceMm.cx = cxVirtualDeviceMm; pdcattr->szlVirtualDeviceMm.cy = cyVirtualDeviceMm; // DC_UpdateXforms(dc); DC_UnlockDc(dc); return TRUE; } // FIXME: Don't use floating point in the kernel! BOOL FASTCALL DC_InvertXform(const XFORM *xformSrc, XFORM *xformDest) { FLOAT determinant; determinant = xformSrc->eM11*xformSrc->eM22 - xformSrc->eM12*xformSrc->eM21; if (determinant > -1e-12 && determinant < 1e-12) { return FALSE; } xformDest->eM11 = xformSrc->eM22 / determinant; xformDest->eM12 = -xformSrc->eM12 / determinant; xformDest->eM21 = -xformSrc->eM21 / determinant; xformDest->eM22 = xformSrc->eM11 / determinant; xformDest->eDx = -xformSrc->eDx * xformDest->eM11 - xformSrc->eDy * xformDest->eM21; xformDest->eDy = -xformSrc->eDx * xformDest->eM12 - xformSrc->eDy * xformDest->eM22; return TRUE; } VOID FASTCALL DC_UpdateXforms(PDC dc) { XFORM xformWnd2Vport; PDC_ATTR pdcattr = dc->pdcattr; XFORM xformWorld2Vport, xformWorld2Wnd, xformVport2World; /* Construct a transformation to do the window-to-viewport conversion */ IntWindowToViewPort(pdcattr, &xformWnd2Vport); /* Combine with the world transformation */ MatrixS2XForm(&xformWorld2Vport, &dc->dclevel.mxWorldToDevice); MatrixS2XForm(&xformWorld2Wnd, &dc->dclevel.mxWorldToPage); IntGdiCombineTransform(&xformWorld2Vport, &xformWorld2Wnd, &xformWnd2Vport); /* Create inverse of world-to-viewport transformation */ MatrixS2XForm(&xformVport2World, &dc->dclevel.mxDeviceToWorld); if (DC_InvertXform(&xformWorld2Vport, &xformVport2World)) { pdcattr->flXform &= ~DEVICE_TO_WORLD_INVALID; } else { pdcattr->flXform |= DEVICE_TO_WORLD_INVALID; } /* Update transformation matrices */ XForm2MatrixS(&dc->dclevel.mxWorldToDevice, &xformWorld2Vport); XForm2MatrixS(&dc->dclevel.mxDeviceToWorld, &xformVport2World); } LONG FASTCALL IntCalcFillOrigin(PDC pdc) { pdc->ptlFillOrigin.x = pdc->dclevel.ptlBrushOrigin.x + pdc->ptlDCOrig.x; pdc->ptlFillOrigin.y = pdc->dclevel.ptlBrushOrigin.y + pdc->ptlDCOrig.y; return pdc->ptlFillOrigin.y; } PPOINTL FASTCALL IntptlBrushOrigin(PDC pdc, LONG x, LONG y ) { pdc->dclevel.ptlBrushOrigin.x = x; pdc->dclevel.ptlBrushOrigin.y = y; IntCalcFillOrigin(pdc); return &pdc->dclevel.ptlBrushOrigin; } VOID APIENTRY GdiSetDCOrg(HDC hDC, LONG Left, LONG Top, PRECTL prc) { PDC pdc; pdc = DC_LockDc(hDC); if (!pdc) return; pdc->ptlDCOrig.x = Left; pdc->ptlDCOrig.y = Top; IntCalcFillOrigin(pdc); if (prc) pdc->erclWindow = *prc; DC_UnlockDc(pdc); } // FIXME: remove me BOOL FASTCALL IntGdiGetDCOrg(PDC pDc, PPOINTL ppt) { *ppt = pDc->ptlDCOrig; return TRUE; } // FIXME: remove me BOOL APIENTRY GdiGetDCOrgEx(HDC hDC, PPOINTL ppt, PRECTL prc) { PDC pdc; pdc = DC_LockDc(hDC); if (!pdc) return FALSE; *prc = pdc->erclWindow; *ppt = pdc->ptlDCOrig; DC_UnlockDc(pdc); return TRUE; } static VOID FASTCALL DC_vGetAspectRatioFilter(PDC pDC, LPSIZE AspectRatio) { if (pDC->pdcattr->flFontMapper & 1) // TRUE assume 1. { // "This specifies that Windows should only match fonts that have the // same aspect ratio as the display.", Programming Windows, Fifth Ed. AspectRatio->cx = pDC->ppdev->gdiinfo.ulLogPixelsX; AspectRatio->cy = pDC->ppdev->gdiinfo.ulLogPixelsY; } else { AspectRatio->cx = 0; AspectRatio->cy = 0; } } VOID FASTCALL DC_vUpdateViewportExt(PDC pdc) { PDC_ATTR pdcattr; /* Get a pointer to the dc attribute */ pdcattr = pdc->pdcattr; /* Check if we need to recalculate */ if (pdcattr->flXform & PAGE_EXTENTS_CHANGED) { /* Check if we need to do isotropic fixup */ if (pdcattr->iMapMode == MM_ISOTROPIC) { IntFixIsotropicMapping(pdc); } /* Update xforms, CHECKME: really done here? */ DC_UpdateXforms(pdc); } } BOOL APIENTRY NtGdiGetDCPoint( HDC hDC, UINT iPoint, PPOINTL Point) { BOOL Ret = TRUE; DC *pdc; POINTL SafePoint; SIZE Size; NTSTATUS Status = STATUS_SUCCESS; if (!Point) { SetLastWin32Error(ERROR_INVALID_PARAMETER); return FALSE; } pdc = DC_LockDc(hDC); if (!pdc) { SetLastWin32Error(ERROR_INVALID_HANDLE); return FALSE; } switch (iPoint) { case GdiGetViewPortExt: DC_vUpdateViewportExt(pdc); SafePoint.x = pdc->pdcattr->szlViewportExt.cx; SafePoint.y = pdc->pdcattr->szlViewportExt.cy; break; case GdiGetWindowExt: SafePoint.x = pdc->pdcattr->szlWindowExt.cx; SafePoint.y = pdc->pdcattr->szlWindowExt.cy; break; case GdiGetViewPortOrg: SafePoint = pdc->pdcattr->ptlViewportOrg; break; case GdiGetWindowOrg: SafePoint = pdc->pdcattr->ptlWindowOrg; break; case GdiGetDCOrg: SafePoint = pdc->ptlDCOrig; break; case GdiGetAspectRatioFilter: DC_vGetAspectRatioFilter(pdc, &Size); SafePoint.x = Size.cx; SafePoint.y = Size.cy; break; default: SetLastWin32Error(ERROR_INVALID_PARAMETER); Ret = FALSE; break; } if (Ret) { _SEH2_TRY { ProbeForWrite(Point, sizeof(POINT), 1); *Point = SafePoint; } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { Status = _SEH2_GetExceptionCode(); } _SEH2_END; if (!NT_SUCCESS(Status)) { SetLastNtError(Status); Ret = FALSE; } } DC_UnlockDc(pdc); return Ret; } DWORD APIENTRY NtGdiGetBoundsRect( IN HDC hdc, OUT LPRECT prc, IN DWORD f) { DPRINT1("stub\n"); return DCB_RESET; /* bounding rectangle always empty */ } DWORD APIENTRY NtGdiSetBoundsRect( IN HDC hdc, IN LPRECT prc, IN DWORD f) { DPRINT1("stub\n"); return DCB_DISABLE; /* bounding rectangle always empty */ } /* EOF */