reactos/win32ss/gdi/eng/pdevobj.c
Joachim Henze 1b27ce92e5 [0.4.7][WIN32K:ENG] Fix fullscreen switch regressions CORE-15325 & CORE-14684 PR#1659
In PDEVOBJ_vRefreshModeList, find a proper match for the current
display mode instead of assuming a constant index.

Both tickets CORE-15325 & CORE-14684 regressed by SVN r74404
384affe098

fix cherry picked from commit 0.4.13-dev-456-g
00e882c2b1
Many thanks to the patches author Thomas Faber.

With this commit we sync PDEVOBJ_vRefreshModeList() to the state I used in 0.4.12rls and 0.4.13rls.

This patch does fix:
- regression CORE-15325 "Pocket Tanks 1.6 not filling the whole screen because it does not switch its resolution when coming from desktop res 1024x768 32bpp"
- regression CORE-14684 "Fall 0.1.3 opens just a white window instead of content when started with desktop resolution 1024x768 32bpp"
- regression "Globulation 2 0.9.4.4 not filling the whole screen when configured to use fullscreen and running it from desktop resolution 1024x768 32bpp"

but also helps to fix the last app that was still affected by CORE-14363 "systray icons do flash through now when an app is running in fullscreen".
CORE-14363 actually was fixed for >95% of the apps already by my last commit into the releases, but there was an outlier that does require Thomas patch additionally, that was:
- "Pengupop 2.2.3 when being run from desktop with 1024x768 32 bpp"

I committed it beforehand:
- for master:    0.4.13-dev-456-g00e882c
- for 0.4.12rls: 0.4.12-RC-34-gec3cc13
- for 0.4.11rls: 0.4.11-release-4-g11e0b0b
- for 0.4.10rls: 0.4.10-release-6-g58f9e1e
- for 0.4.9rls:  0.4.9-release-8-ge8cc477
- for 0.4.8rls:  0.4.8-release-8-gabbb59b
2020-10-08 17:57:28 +02:00

979 lines
25 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* PURPOSE: Support for physical devices
* FILE: win32ss/gdi/eng/pdevobj.c
* PROGRAMER: Timo Kreuzer (timo.kreuzer@reactos.org)
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
PPDEVOBJ gppdevPrimary = NULL;
static PPDEVOBJ gppdevList = NULL;
static HSEMAPHORE ghsemPDEV;
INIT_FUNCTION
NTSTATUS
NTAPI
InitPDEVImpl(VOID)
{
ghsemPDEV = EngCreateSemaphore();
if (!ghsemPDEV) return STATUS_INSUFFICIENT_RESOURCES;
return STATUS_SUCCESS;
}
#if DBG
PPDEVOBJ
NTAPI
DbgLookupDHPDEV(DHPDEV dhpdev)
{
PPDEVOBJ ppdev;
/* Lock PDEV list */
EngAcquireSemaphoreShared(ghsemPDEV);
/* Walk through the list of PDEVs */
for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
{
/* Compare with the given DHPDEV */
if (ppdev->dhpdev == dhpdev) break;
}
/* Unlock PDEV list */
EngReleaseSemaphore(ghsemPDEV);
return ppdev;
}
#endif
PPDEVOBJ
PDEVOBJ_AllocPDEV(VOID)
{
PPDEVOBJ ppdev;
ppdev = ExAllocatePoolWithTag(PagedPool, sizeof(PDEVOBJ), GDITAG_PDEV);
if (!ppdev)
return NULL;
RtlZeroMemory(ppdev, sizeof(PDEVOBJ));
ppdev->hsemDevLock = EngCreateSemaphore();
if (ppdev->hsemDevLock == NULL)
{
ExFreePoolWithTag(ppdev, GDITAG_PDEV);
return NULL;
}
/* Allocate EDD_DIRECTDRAW_GLOBAL for our ReactX driver */
ppdev->pEDDgpl = ExAllocatePoolWithTag(PagedPool, sizeof(EDD_DIRECTDRAW_GLOBAL), GDITAG_PDEV);
if (ppdev->pEDDgpl)
RtlZeroMemory(ppdev->pEDDgpl, sizeof(EDD_DIRECTDRAW_GLOBAL));
ppdev->cPdevRefs = 1;
return ppdev;
}
static
VOID
PDEVOBJ_vDeletePDEV(
PPDEVOBJ ppdev)
{
EngDeleteSemaphore(ppdev->hsemDevLock);
if (ppdev->pEDDgpl)
ExFreePoolWithTag(ppdev->pEDDgpl, GDITAG_PDEV);
ExFreePoolWithTag(ppdev, GDITAG_PDEV);
}
VOID
NTAPI
PDEVOBJ_vRelease(PPDEVOBJ ppdev)
{
/* Lock loader */
EngAcquireSemaphore(ghsemPDEV);
/* Decrease reference count */
--ppdev->cPdevRefs;
ASSERT(ppdev->cPdevRefs >= 0) ;
/* Check if references are left */
if (ppdev->cPdevRefs == 0)
{
/* Do we have a surface? */
if (ppdev->pSurface)
{
/* Release the surface and let the driver free it */
SURFACE_ShareUnlockSurface(ppdev->pSurface);
ppdev->pfn.DisableSurface(ppdev->dhpdev);
}
/* Do we have a palette? */
if(ppdev->ppalSurf)
{
PALETTE_ShareUnlockPalette(ppdev->ppalSurf);
}
/* Check if the PDEV was enabled */
if (ppdev->dhpdev != NULL)
{
/* Disable the PDEV */
ppdev->pfn.DisablePDEV(ppdev->dhpdev);
}
/* Remove it from list */
if( ppdev == gppdevList )
gppdevList = ppdev->ppdevNext ;
else
{
PPDEVOBJ ppdevCurrent = gppdevList;
BOOL found = FALSE ;
while (!found && ppdevCurrent->ppdevNext)
{
if (ppdevCurrent->ppdevNext == ppdev)
found = TRUE;
else
ppdevCurrent = ppdevCurrent->ppdevNext ;
}
if(found)
ppdevCurrent->ppdevNext = ppdev->ppdevNext;
}
/* Is this the primary one ? */
if (ppdev == gppdevPrimary)
gppdevPrimary = NULL;
/* Free it */
PDEVOBJ_vDeletePDEV(ppdev);
}
/* Unlock loader */
EngReleaseSemaphore(ghsemPDEV);
}
BOOL
NTAPI
PDEVOBJ_bEnablePDEV(
PPDEVOBJ ppdev,
PDEVMODEW pdevmode,
PWSTR pwszLogAddress)
{
PFN_DrvEnablePDEV pfnEnablePDEV;
ULONG i;
DPRINT("PDEVOBJ_bEnablePDEV()\n");
/* Get the DrvEnablePDEV function */
pfnEnablePDEV = ppdev->pldev->pfn.EnablePDEV;
/* Call the drivers DrvEnablePDEV function */
ppdev->dhpdev = pfnEnablePDEV(pdevmode,
pwszLogAddress,
HS_DDI_MAX,
ppdev->ahsurf,
sizeof(GDIINFO),
(PULONG)&ppdev->gdiinfo,
sizeof(DEVINFO),
&ppdev->devinfo,
(HDEV)ppdev,
ppdev->pGraphicsDevice->pwszDescription,
ppdev->pGraphicsDevice->DeviceObject);
if (ppdev->dhpdev == NULL)
{
DPRINT1("Failed to enable PDEV\n");
return FALSE;
}
/* Fix up some values */
if (ppdev->gdiinfo.ulLogPixelsX == 0)
ppdev->gdiinfo.ulLogPixelsX = 96;
if (ppdev->gdiinfo.ulLogPixelsY == 0)
ppdev->gdiinfo.ulLogPixelsY = 96;
/* Set raster caps */
ppdev->gdiinfo.flRaster = RC_OP_DX_OUTPUT | RC_GDI20_OUTPUT | RC_BIGFONT;
if ((ppdev->gdiinfo.ulTechnology != DT_PLOTTER) && (ppdev->gdiinfo.ulTechnology != DT_CHARSTREAM))
ppdev->gdiinfo.flRaster |= RC_STRETCHDIB | RC_STRETCHBLT | RC_DIBTODEV | RC_DI_BITMAP | RC_BITMAP64 | RC_BITBLT;
if (ppdev->gdiinfo.ulTechnology == DT_RASDISPLAY)
ppdev->gdiinfo.flRaster |= RC_FLOODFILL;
if (ppdev->devinfo.flGraphicsCaps & GCAPS_PALMANAGED)
ppdev->gdiinfo.flRaster |= RC_PALETTE;
/* Setup Palette */
ppdev->ppalSurf = PALETTE_ShareLockPalette(ppdev->devinfo.hpalDefault);
/* Setup hatch brushes */
for (i = 0; i < HS_DDI_MAX; i++)
{
if (ppdev->ahsurf[i] == NULL)
ppdev->ahsurf[i] = gahsurfHatch[i];
}
DPRINT("PDEVOBJ_bEnablePDEV - dhpdev = %p\n", ppdev->dhpdev);
return TRUE;
}
VOID
NTAPI
PDEVOBJ_vCompletePDEV(
PPDEVOBJ ppdev)
{
/* Call the drivers DrvCompletePDEV function */
ppdev->pldev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev);
}
PSURFACE
NTAPI
PDEVOBJ_pSurface(
PPDEVOBJ ppdev)
{
HSURF hsurf;
/* Check if there is no surface for this PDEV yet */
if (ppdev->pSurface == NULL)
{
/* Call the drivers DrvEnableSurface */
hsurf = ppdev->pldev->pfn.EnableSurface(ppdev->dhpdev);
if (hsurf== NULL)
{
DPRINT1("Failed to create PDEV surface!\n");
return NULL;
}
/* Get a reference to the surface */
ppdev->pSurface = SURFACE_ShareLockSurface(hsurf);
NT_ASSERT(ppdev->pSurface != NULL);
}
/* Increment reference count */
GDIOBJ_vReferenceObjectByPointer(&ppdev->pSurface->BaseObject);
DPRINT("PDEVOBJ_pSurface() returning %p\n", ppdev->pSurface);
return ppdev->pSurface;
}
VOID
NTAPI
PDEVOBJ_vRefreshModeList(
PPDEVOBJ ppdev)
{
PGRAPHICS_DEVICE pGraphicsDevice;
PDEVMODEINFO pdminfo, pdmiNext;
DEVMODEW dmDefault;
DEVMODEW dmCurrent;
/* Lock the PDEV */
EngAcquireSemaphore(ppdev->hsemDevLock);
pGraphicsDevice = ppdev->pGraphicsDevice;
/* Remember our default mode */
dmDefault = *pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm;
dmCurrent = *ppdev->pdmwDev;
/* Clear out the modes */
for (pdminfo = pGraphicsDevice->pdevmodeInfo;
pdminfo;
pdminfo = pdmiNext)
{
pdmiNext = pdminfo->pdmiNext;
ExFreePoolWithTag(pdminfo, GDITAG_DEVMODE);
}
pGraphicsDevice->pdevmodeInfo = NULL;
ExFreePoolWithTag(pGraphicsDevice->pDevModeList, GDITAG_GDEVICE);
pGraphicsDevice->pDevModeList = NULL;
/* Now re-populate the list */
if (!EngpPopulateDeviceModeList(pGraphicsDevice, &dmDefault))
{
DPRINT1("FIXME: EngpPopulateDeviceModeList failed, we just destroyed a perfectly good mode list\n");
}
ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, &dmCurrent);
/* Unlock PDEV */
EngReleaseSemaphore(ppdev->hsemDevLock);
}
PDEVMODEW
NTAPI
PDEVOBJ_pdmMatchDevMode(
PPDEVOBJ ppdev,
PDEVMODEW pdm)
{
PGRAPHICS_DEVICE pGraphicsDevice;
PDEVMODEW pdmCurrent;
ULONG i;
DWORD dwFields;
pGraphicsDevice = ppdev->pGraphicsDevice;
for (i = 0; i < pGraphicsDevice->cDevModes; i++)
{
pdmCurrent = pGraphicsDevice->pDevModeList[i].pdm;
/* Compare asked DEVMODE fields
* Only compare those that are valid in both DEVMODE structs */
dwFields = pdmCurrent->dmFields & pdm->dmFields ;
/* For now, we only need those */
if ((dwFields & DM_BITSPERPEL) &&
(pdmCurrent->dmBitsPerPel != pdm->dmBitsPerPel)) continue;
if ((dwFields & DM_PELSWIDTH) &&
(pdmCurrent->dmPelsWidth != pdm->dmPelsWidth)) continue;
if ((dwFields & DM_PELSHEIGHT) &&
(pdmCurrent->dmPelsHeight != pdm->dmPelsHeight)) continue;
if ((dwFields & DM_DISPLAYFREQUENCY) &&
(pdmCurrent->dmDisplayFrequency != pdm->dmDisplayFrequency)) continue;
/* Match! Return the DEVMODE */
return pdmCurrent;
}
/* Nothing found */
return NULL;
}
static
PPDEVOBJ
EngpCreatePDEV(
PUNICODE_STRING pustrDeviceName,
PDEVMODEW pdm)
{
PGRAPHICS_DEVICE pGraphicsDevice;
PPDEVOBJ ppdev;
DPRINT("EngpCreatePDEV(%wZ, %p)\n", pustrDeviceName, pdm);
/* Try to find the GRAPHICS_DEVICE */
if (pustrDeviceName)
{
pGraphicsDevice = EngpFindGraphicsDevice(pustrDeviceName, 0, 0);
if (!pGraphicsDevice)
{
DPRINT1("No GRAPHICS_DEVICE found for %ls!\n",
pustrDeviceName ? pustrDeviceName->Buffer : 0);
return NULL;
}
}
else
{
pGraphicsDevice = gpPrimaryGraphicsDevice;
}
/* Allocate a new PDEVOBJ */
ppdev = PDEVOBJ_AllocPDEV();
if (!ppdev)
{
DPRINT1("failed to allocate a PDEV\n");
return NULL;
}
/* If no DEVMODEW is given, ... */
if (!pdm)
{
/* ... use the device's default one */
pdm = pGraphicsDevice->pDevModeList[pGraphicsDevice->iDefaultMode].pdm;
DPRINT("Using iDefaultMode = %lu\n", pGraphicsDevice->iDefaultMode);
}
/* Try to get a diplay driver */
ppdev->pldev = EngLoadImageEx(pdm->dmDeviceName, LDEV_DEVICE_DISPLAY);
if (!ppdev->pldev)
{
DPRINT1("Could not load display driver '%ls', '%ls'\n",
pGraphicsDevice->pDiplayDrivers,
pdm->dmDeviceName);
PDEVOBJ_vRelease(ppdev);
return NULL;
}
/* Copy the function table */
ppdev->pfn = ppdev->pldev->pfn;
/* Set MovePointer function */
ppdev->pfnMovePointer = ppdev->pfn.MovePointer;
if (!ppdev->pfnMovePointer)
ppdev->pfnMovePointer = EngMovePointer;
ppdev->pGraphicsDevice = pGraphicsDevice;
// DxEngGetHdevData asks for Graphics DeviceObject in hSpooler field
ppdev->hSpooler = ppdev->pGraphicsDevice->DeviceObject;
// Should we change the ative mode of pGraphicsDevice ?
ppdev->pdmwDev = PDEVOBJ_pdmMatchDevMode(ppdev, pdm) ;
/* FIXME! */
ppdev->flFlags = PDEV_DISPLAY;
/* HACK: Don't use the pointer */
ppdev->Pointer.Exclude.right = -1;
/* Call the driver to enable the PDEV */
if (!PDEVOBJ_bEnablePDEV(ppdev, pdm, NULL))
{
DPRINT1("Failed to enable PDEV!\n");
PDEVOBJ_vRelease(ppdev);
return NULL;
}
/* FIXME: this must be done in a better way */
pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_ATTACHED_TO_DESKTOP;
/* Tell the driver that the PDEV is ready */
PDEVOBJ_vCompletePDEV(ppdev);
/* Return the PDEV */
return ppdev;
}
FORCEINLINE
VOID
SwitchPointer(
_Inout_ PVOID pvPointer1,
_Inout_ PVOID pvPointer2)
{
PVOID *ppvPointer1 = pvPointer1;
PVOID *ppvPointer2 = pvPointer2;
PVOID pvTemp;
pvTemp = *ppvPointer1;
*ppvPointer1 = *ppvPointer2;
*ppvPointer2 = pvTemp;
}
VOID
NTAPI
PDEVOBJ_vSwitchPdev(
PPDEVOBJ ppdev,
PPDEVOBJ ppdev2)
{
union
{
DRIVER_FUNCTIONS pfn;
GDIINFO gdiinfo;
DEVINFO devinfo;
DWORD StateFlags;
} temp;
/* Exchange driver functions */
temp.pfn = ppdev->pfn;
ppdev->pfn = ppdev2->pfn;
ppdev2->pfn = temp.pfn;
/* Exchange LDEVs */
SwitchPointer(&ppdev->pldev, &ppdev2->pldev);
/* Exchange DHPDEV */
SwitchPointer(&ppdev->dhpdev, &ppdev2->dhpdev);
/* Exchange surfaces and associate them with their new PDEV */
SwitchPointer(&ppdev->pSurface, &ppdev2->pSurface);
ppdev->pSurface->SurfObj.hdev = (HDEV)ppdev;
ppdev2->pSurface->SurfObj.hdev = (HDEV)ppdev2;
/* Exchange devinfo */
temp.devinfo = ppdev->devinfo;
ppdev->devinfo = ppdev2->devinfo;
ppdev2->devinfo = temp.devinfo;
/* Exchange gdiinfo */
temp.gdiinfo = ppdev->gdiinfo;
ppdev->gdiinfo = ppdev2->gdiinfo;
ppdev2->gdiinfo = temp.gdiinfo;
/* Exchange DEVMODE */
SwitchPointer(&ppdev->pdmwDev, &ppdev2->pdmwDev);
/* Exchange state flags */
temp.StateFlags = ppdev->pGraphicsDevice->StateFlags;
ppdev->pGraphicsDevice->StateFlags = ppdev2->pGraphicsDevice->StateFlags;
ppdev2->pGraphicsDevice->StateFlags = temp.StateFlags;
/* Notify each driver instance of its new HDEV association */
ppdev->pfn.CompletePDEV(ppdev->dhpdev, (HDEV)ppdev);
ppdev2->pfn.CompletePDEV(ppdev2->dhpdev, (HDEV)ppdev2);
}
BOOL
NTAPI
PDEVOBJ_bSwitchMode(
PPDEVOBJ ppdev,
PDEVMODEW pdm)
{
UNICODE_STRING ustrDevice;
PPDEVOBJ ppdevTmp;
PSURFACE pSurface;
BOOL retval = FALSE;
/* Lock the PDEV */
EngAcquireSemaphore(ppdev->hsemDevLock);
/* And everything else */
EngAcquireSemaphore(ghsemPDEV);
DPRINT1("PDEVOBJ_bSwitchMode, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface);
// Lookup the GraphicsDevice + select DEVMODE
// pdm = PDEVOBJ_pdmMatchDevMode(ppdev, pdm);
/* 1. Temporarily disable the current PDEV */
if (!ppdev->pfn.AssertMode(ppdev->dhpdev, FALSE))
{
DPRINT1("DrvAssertMode failed\n");
goto leave;
}
/* 2. Create new PDEV */
RtlInitUnicodeString(&ustrDevice, ppdev->pGraphicsDevice->szWinDeviceName);
ppdevTmp = EngpCreatePDEV(&ustrDevice, pdm);
if (!ppdevTmp)
{
DPRINT1("Failed to create a new PDEV\n");
goto leave;
}
/* 3. Create a new surface */
pSurface = PDEVOBJ_pSurface(ppdevTmp);
if (!pSurface)
{
DPRINT1("PDEVOBJ_pSurface failed\n");
goto leave;
}
/* 4. Get DirectDraw information */
/* 5. Enable DirectDraw Not traced */
/* 6. Copy old PDEV state to new PDEV instance */
/* 7. Switch the PDEVs */
PDEVOBJ_vSwitchPdev(ppdev, ppdevTmp);
/* 8. Disable DirectDraw */
PDEVOBJ_vRelease(ppdevTmp);
/* Update primary display capabilities */
if(ppdev == gppdevPrimary)
{
PDEVOBJ_vGetDeviceCaps(ppdev, &GdiHandleTable->DevCaps);
}
/* Success! */
retval = TRUE;
leave:
/* Unlock PDEV */
EngReleaseSemaphore(ppdev->hsemDevLock);
EngReleaseSemaphore(ghsemPDEV);
DPRINT1("leave, ppdev = %p, pSurface = %p\n", ppdev, ppdev->pSurface);
return retval;
}
PPDEVOBJ
NTAPI
EngpGetPDEV(
_In_opt_ PUNICODE_STRING pustrDeviceName)
{
UNICODE_STRING ustrCurrent;
PPDEVOBJ ppdev;
PGRAPHICS_DEVICE pGraphicsDevice;
/* Acquire PDEV lock */
EngAcquireSemaphore(ghsemPDEV);
/* Did the caller pass a device name? */
if (pustrDeviceName)
{
/* Loop all present PDEVs */
for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
{
/* Get a pointer to the GRAPHICS_DEVICE */
pGraphicsDevice = ppdev->pGraphicsDevice;
/* Compare the name */
RtlInitUnicodeString(&ustrCurrent, pGraphicsDevice->szWinDeviceName);
if (RtlEqualUnicodeString(pustrDeviceName, &ustrCurrent, FALSE))
{
/* Found! */
break;
}
}
}
else
{
/* Otherwise use the primary PDEV */
ppdev = gppdevPrimary;
}
/* Did we find one? */
if (ppdev)
{
/* Yes, reference the PDEV */
InterlockedIncrement(&ppdev->cPdevRefs);
}
else
{
/* No, create a new PDEV for the given device */
ppdev = EngpCreatePDEV(pustrDeviceName, NULL);
if (ppdev)
{
/* Insert the PDEV into the list */
ppdev->ppdevNext = gppdevList;
gppdevList = ppdev;
/* Set as primary PDEV, if we don't have one yet */
if (!gppdevPrimary)
{
gppdevPrimary = ppdev;
ppdev->pGraphicsDevice->StateFlags |= DISPLAY_DEVICE_PRIMARY_DEVICE;
}
}
}
/* Release PDEV lock */
EngReleaseSemaphore(ghsemPDEV);
return ppdev;
}
INT
NTAPI
PDEVOBJ_iGetColorManagementCaps(PPDEVOBJ ppdev)
{
INT ret = CM_NONE;
if (ppdev->flFlags & PDEV_DISPLAY)
{
if (ppdev->devinfo.iDitherFormat == BMF_8BPP ||
ppdev->devinfo.flGraphicsCaps2 & GCAPS2_CHANGEGAMMARAMP)
ret = CM_GAMMA_RAMP;
}
if (ppdev->devinfo.flGraphicsCaps & GCAPS_CMYKCOLOR)
ret |= CM_CMYK_COLOR;
if (ppdev->devinfo.flGraphicsCaps & GCAPS_ICM)
ret |= CM_DEVICE_ICM;
return ret;
}
VOID
NTAPI
PDEVOBJ_vGetDeviceCaps(
IN PPDEVOBJ ppdev,
OUT PDEVCAPS pDevCaps)
{
PGDIINFO pGdiInfo = &ppdev->gdiinfo;
pDevCaps->ulVersion = pGdiInfo->ulVersion;
pDevCaps->ulTechnology = pGdiInfo->ulTechnology;
pDevCaps->ulHorzSizeM = (pGdiInfo->ulHorzSize + 500) / 1000;
pDevCaps->ulVertSizeM = (pGdiInfo->ulVertSize + 500) / 1000;
pDevCaps->ulHorzSize = pGdiInfo->ulHorzSize;
pDevCaps->ulVertSize = pGdiInfo->ulVertSize;
pDevCaps->ulHorzRes = pGdiInfo->ulHorzRes;
pDevCaps->ulVertRes = pGdiInfo->ulVertRes;
pDevCaps->ulBitsPixel = pGdiInfo->cBitsPixel;
if (pDevCaps->ulBitsPixel == 15) pDevCaps->ulBitsPixel = 16;
pDevCaps->ulPlanes = pGdiInfo->cPlanes;
pDevCaps->ulNumPens = pGdiInfo->ulNumColors;
if (pDevCaps->ulNumPens != -1) pDevCaps->ulNumPens *= 5;
pDevCaps->ulNumFonts = 0; // PDEVOBJ_cFonts(ppdev);
pDevCaps->ulNumColors = pGdiInfo->ulNumColors;
pDevCaps->ulRasterCaps = pGdiInfo->flRaster;
pDevCaps->ulAspectX = pGdiInfo->ulAspectX;
pDevCaps->ulAspectY = pGdiInfo->ulAspectY;
pDevCaps->ulAspectXY = pGdiInfo->ulAspectXY;
pDevCaps->ulLogPixelsX = pGdiInfo->ulLogPixelsX;
pDevCaps->ulLogPixelsY = pGdiInfo->ulLogPixelsY;
pDevCaps->ulSizePalette = pGdiInfo->ulNumPalReg;
pDevCaps->ulColorRes = pGdiInfo->ulDACRed +
pGdiInfo->ulDACGreen +
pGdiInfo->ulDACBlue;
pDevCaps->ulPhysicalWidth = pGdiInfo->szlPhysSize.cx;
pDevCaps->ulPhysicalHeight = pGdiInfo->szlPhysSize.cy;
pDevCaps->ulPhysicalOffsetX = pGdiInfo->ptlPhysOffset.x;
pDevCaps->ulPhysicalOffsetY = pGdiInfo->ptlPhysOffset.y;
pDevCaps->ulTextCaps = pGdiInfo->flTextCaps;
pDevCaps->ulTextCaps |= (TC_SO_ABLE|TC_UA_ABLE|TC_CP_STROKE|TC_OP_STROKE|TC_OP_CHARACTER);
if (pGdiInfo->ulTechnology != DT_PLOTTER)
pDevCaps->ulTextCaps |= TC_VA_ABLE;
pDevCaps->ulVRefresh = pGdiInfo->ulVRefresh;
pDevCaps->ulDesktopHorzRes = pGdiInfo->ulHorzRes;
pDevCaps->ulDesktopVertRes = pGdiInfo->ulVertRes;
pDevCaps->ulBltAlignment = pGdiInfo->ulBltAlignment;
pDevCaps->ulPanningHorzRes = pGdiInfo->ulPanningHorzRes;
pDevCaps->ulPanningVertRes = pGdiInfo->ulPanningVertRes;
pDevCaps->xPanningAlignment = pGdiInfo->xPanningAlignment;
pDevCaps->yPanningAlignment = pGdiInfo->yPanningAlignment;
pDevCaps->ulShadeBlend = pGdiInfo->flShadeBlend;
pDevCaps->ulColorMgmtCaps = PDEVOBJ_iGetColorManagementCaps(ppdev);
}
/** Exported functions ********************************************************/
_Must_inspect_result_ _Ret_z_
LPWSTR
APIENTRY
EngGetDriverName(_In_ HDEV hdev)
{
PPDEVOBJ ppdev = (PPDEVOBJ)hdev;
ASSERT(ppdev);
ASSERT(ppdev->pldev);
ASSERT(ppdev->pldev->pGdiDriverInfo);
ASSERT(ppdev->pldev->pGdiDriverInfo->DriverName.Buffer);
return ppdev->pldev->pGdiDriverInfo->DriverName.Buffer;
}
INT
APIENTRY
NtGdiGetDeviceCaps(
HDC hdc,
INT Index)
{
PDC pdc;
DEVCAPS devcaps;
/* Lock the given DC */
pdc = DC_LockDc(hdc);
if (!pdc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return 0;
}
/* Get the data */
PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps);
/* Unlock the DC */
DC_UnlockDc(pdc);
/* Return capability */
switch (Index)
{
case DRIVERVERSION:
return devcaps.ulVersion;
case TECHNOLOGY:
return devcaps.ulTechnology;
case HORZSIZE:
return devcaps.ulHorzSize;
case VERTSIZE:
return devcaps.ulVertSize;
case HORZRES:
return devcaps.ulHorzRes;
case VERTRES:
return devcaps.ulVertRes;
case LOGPIXELSX:
return devcaps.ulLogPixelsX;
case LOGPIXELSY:
return devcaps.ulLogPixelsY;
case BITSPIXEL:
return devcaps.ulBitsPixel;
case PLANES:
return devcaps.ulPlanes;
case NUMBRUSHES:
return -1;
case NUMPENS:
return devcaps.ulNumPens;
case NUMFONTS:
return devcaps.ulNumFonts;
case NUMCOLORS:
return devcaps.ulNumColors;
case ASPECTX:
return devcaps.ulAspectX;
case ASPECTY:
return devcaps.ulAspectY;
case ASPECTXY:
return devcaps.ulAspectXY;
case CLIPCAPS:
return CP_RECTANGLE;
case SIZEPALETTE:
return devcaps.ulSizePalette;
case NUMRESERVED:
return 20;
case COLORRES:
return devcaps.ulColorRes;
case DESKTOPVERTRES:
return devcaps.ulVertRes;
case DESKTOPHORZRES:
return devcaps.ulHorzRes;
case BLTALIGNMENT:
return devcaps.ulBltAlignment;
case SHADEBLENDCAPS:
return devcaps.ulShadeBlend;
case COLORMGMTCAPS:
return devcaps.ulColorMgmtCaps;
case PHYSICALWIDTH:
return devcaps.ulPhysicalWidth;
case PHYSICALHEIGHT:
return devcaps.ulPhysicalHeight;
case PHYSICALOFFSETX:
return devcaps.ulPhysicalOffsetX;
case PHYSICALOFFSETY:
return devcaps.ulPhysicalOffsetY;
case VREFRESH:
return devcaps.ulVRefresh;
case RASTERCAPS:
return devcaps.ulRasterCaps;
case CURVECAPS:
return (CC_CIRCLES | CC_PIE | CC_CHORD | CC_ELLIPSES | CC_WIDE |
CC_STYLED | CC_WIDESTYLED | CC_INTERIORS | CC_ROUNDRECT);
case LINECAPS:
return (LC_POLYLINE | LC_MARKER | LC_POLYMARKER | LC_WIDE |
LC_STYLED | LC_WIDESTYLED | LC_INTERIORS);
case POLYGONALCAPS:
return (PC_POLYGON | PC_RECTANGLE | PC_WINDPOLYGON | PC_SCANLINE |
PC_WIDE | PC_STYLED | PC_WIDESTYLED | PC_INTERIORS);
case TEXTCAPS:
return devcaps.ulTextCaps;
case CAPS1:
case PDEVICESIZE:
case SCALINGFACTORX:
case SCALINGFACTORY:
default:
return 0;
}
return 0;
}
_Success_(return!=FALSE)
BOOL
APIENTRY
NtGdiGetDeviceCapsAll(
IN HDC hDC,
OUT PDEVCAPS pDevCaps)
{
PDC pdc;
DEVCAPS devcaps;
BOOL bResult = TRUE;
/* Lock the given DC */
pdc = DC_LockDc(hDC);
if (!pdc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return FALSE;
}
/* Get the data */
PDEVOBJ_vGetDeviceCaps(pdc->ppdev, &devcaps);
/* Unlock the DC */
DC_UnlockDc(pdc);
/* Copy data to caller */
_SEH2_TRY
{
ProbeForWrite(pDevCaps, sizeof(DEVCAPS), 1);
RtlCopyMemory(pDevCaps, &devcaps, sizeof(DEVCAPS));
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
SetLastNtError(_SEH2_GetExceptionCode());
bResult = FALSE;
}
_SEH2_END;
return bResult;
}
DHPDEV
APIENTRY
NtGdiGetDhpdev(
IN HDEV hdev)
{
PPDEVOBJ ppdev;
DHPDEV dhpdev = NULL;
/* Check parameter */
if (!hdev || (PCHAR)hdev < (PCHAR)MmSystemRangeStart)
return NULL;
/* Lock PDEV list */
EngAcquireSemaphoreShared(ghsemPDEV);
/* Walk through the list of PDEVs */
for (ppdev = gppdevList; ppdev; ppdev = ppdev->ppdevNext)
{
/* Compare with the given HDEV */
if (ppdev == (PPDEVOBJ)hdev)
{
/* Found the PDEV! Get it's dhpdev and break */
dhpdev = ppdev->dhpdev;
break;
}
}
/* Unlock PDEV list */
EngReleaseSemaphore(ghsemPDEV);
return dhpdev;
}
PSIZEL
FASTCALL
PDEVOBJ_sizl(PPDEVOBJ ppdev, PSIZEL psizl)
{
if (ppdev->flFlags & PDEV_META_DEVICE)
{
psizl->cx = ppdev->ulHorzRes;
psizl->cy = ppdev->ulVertRes;
}
else
{
psizl->cx = ppdev->gdiinfo.ulHorzRes;
psizl->cy = ppdev->gdiinfo.ulVertRes;
}
return psizl;
}