reactos/win32ss/gdi/ntgdi/dcobjs.c

795 lines
18 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS Win32k subsystem
* PURPOSE: Functions for creation and destruction of DCs
* FILE: win32ss/gdi/ntgdi/dcobjs.c
* PROGRAMER: Timo Kreuzer (timo.kreuzer@rectos.org)
*/
#include <win32k.h>
#define NDEBUG
#include <debug.h>
VOID
FASTCALL
DC_vUpdateFillBrush(PDC pdc)
{
PDC_ATTR pdcattr = pdc->pdcattr;
PBRUSH pbrFill;
/* Check if the brush handle has changed */
if (pdcattr->hbrush != pdc->dclevel.pbrFill->BaseObject.hHmgr)
{
/* Try to lock the new brush */
pbrFill = BRUSH_ShareLockBrush(pdcattr->hbrush);
if (pbrFill)
{
/* Unlock old brush, set new brush */
BRUSH_ShareUnlockBrush(pdc->dclevel.pbrFill);
pdc->dclevel.pbrFill = pbrFill;
/* Mark eboFill as dirty */
pdcattr->ulDirty_ |= DIRTY_FILL;
}
else
{
/* Invalid brush handle, restore old one */
pdcattr->hbrush = pdc->dclevel.pbrFill->BaseObject.hHmgr;
}
}
/* Check if the EBRUSHOBJ needs update */
if (pdcattr->ulDirty_ & DIRTY_FILL)
{
XLATEOBJ rewrite. The new XLATEOBJ is not allocated from paged pool anymore, but instead allocated on the stack and Initialized. Only when we habe more than a color table with more than 6 entries, we need to allocate an additional buffer. The new interface: EXLATEOBJ_vInitialize is the main init function. It takes a source and destination palette and back and fore colors for monochome surfaces. EXLATEOBJ_vInitXlateFromDCs takes the source and dest DC and is for color translation between 2 surfaces represented by 2 DCs. EXLATEOBJ_vInitBrushXlate initializes an XLATEOBJ for a pattern brush. Finally EXLATEOBJ_vCleanup needs to be called when the XLATEOBJ is not needed anymore. Implement individual iXlate functions for certain cases and store a function pointer in the EXLATEOBJ structure for quick access. Change the usage of the PALETTE.Mode member to be a flag instead of an enum, add usage of PAL_MONOCHOME, PAL_RGB16_555 and PAL_RGB16_565. Add gpalMono, which *should* be used as palette for 1bpp DDBs. Currently there's a hack in the XLATEOBJ init code, to hack around the fact that this is missing. Fix the Hatch brush patterns, as they were inverted. Implement PALETTE_ulGetNearestBitFieldsIndex and PALETTE_ulGetNearestIndex. Get rid of the XLATEOBJ for the mouse pointer instead realize the pointer before usage. Get rid of logicalToSystem PALETTE member. NtGdiGetDIBitsInternal: Don't create a DIBBrush from the BITMAPINFO, when pvBits is NULL, as the function might be uninitualized. This fixes a crash of gdi_regtest. The whole function is quite ugly and needs to be rewritten (like probably the rest of the DIB code). This fixes the problem of artifacts in the selected desktop icons and some color problems. svn path=/trunk/; revision=42391
2009-08-04 20:37:10 +00:00
/* Update eboFill */
EBRUSHOBJ_vUpdateFromDC(&pdc->eboFill, pdc->dclevel.pbrFill, pdc);
}
/* Check for DC brush */
if (pdcattr->hbrush == StockObjects[DC_BRUSH])
{
/* Update the eboFill's solid color */
EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboFill, pdcattr->crBrushClr);
}
/* Clear flags */
pdcattr->ulDirty_ &= ~(DIRTY_FILL | DC_BRUSH_DIRTY);
}
VOID
FASTCALL
DC_vUpdateLineBrush(PDC pdc)
{
PDC_ATTR pdcattr = pdc->pdcattr;
PBRUSH pbrLine;
/* Check if the pen handle has changed */
if (pdcattr->hpen != pdc->dclevel.pbrLine->BaseObject.hHmgr)
{
/* Try to lock the new pen */
pbrLine = PEN_ShareLockPen(pdcattr->hpen);
if (pbrLine)
{
/* Unlock old brush, set new brush */
BRUSH_ShareUnlockBrush(pdc->dclevel.pbrLine);
pdc->dclevel.pbrLine = pbrLine;
/* Mark eboLine as dirty */
pdcattr->ulDirty_ |= DIRTY_LINE;
}
else
{
/* Invalid pen handle, restore old one */
pdcattr->hpen = pdc->dclevel.pbrLine->BaseObject.hHmgr;
}
}
/* Check if the EBRUSHOBJ needs update */
if (pdcattr->ulDirty_ & DIRTY_LINE)
{
XLATEOBJ rewrite. The new XLATEOBJ is not allocated from paged pool anymore, but instead allocated on the stack and Initialized. Only when we habe more than a color table with more than 6 entries, we need to allocate an additional buffer. The new interface: EXLATEOBJ_vInitialize is the main init function. It takes a source and destination palette and back and fore colors for monochome surfaces. EXLATEOBJ_vInitXlateFromDCs takes the source and dest DC and is for color translation between 2 surfaces represented by 2 DCs. EXLATEOBJ_vInitBrushXlate initializes an XLATEOBJ for a pattern brush. Finally EXLATEOBJ_vCleanup needs to be called when the XLATEOBJ is not needed anymore. Implement individual iXlate functions for certain cases and store a function pointer in the EXLATEOBJ structure for quick access. Change the usage of the PALETTE.Mode member to be a flag instead of an enum, add usage of PAL_MONOCHOME, PAL_RGB16_555 and PAL_RGB16_565. Add gpalMono, which *should* be used as palette for 1bpp DDBs. Currently there's a hack in the XLATEOBJ init code, to hack around the fact that this is missing. Fix the Hatch brush patterns, as they were inverted. Implement PALETTE_ulGetNearestBitFieldsIndex and PALETTE_ulGetNearestIndex. Get rid of the XLATEOBJ for the mouse pointer instead realize the pointer before usage. Get rid of logicalToSystem PALETTE member. NtGdiGetDIBitsInternal: Don't create a DIBBrush from the BITMAPINFO, when pvBits is NULL, as the function might be uninitualized. This fixes a crash of gdi_regtest. The whole function is quite ugly and needs to be rewritten (like probably the rest of the DIB code). This fixes the problem of artifacts in the selected desktop icons and some color problems. svn path=/trunk/; revision=42391
2009-08-04 20:37:10 +00:00
/* Update eboLine */
EBRUSHOBJ_vUpdateFromDC(&pdc->eboLine, pdc->dclevel.pbrLine, pdc);
}
/* Check for DC pen */
if (pdcattr->hpen == StockObjects[DC_PEN])
{
/* Update the eboLine's solid color */
EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboLine, pdcattr->crPenClr);
}
/* Clear flags */
pdcattr->ulDirty_ &= ~(DIRTY_LINE | DC_PEN_DIRTY);
}
VOID
FASTCALL
DC_vUpdateTextBrush(PDC pdc)
{
PDC_ATTR pdcattr = pdc->pdcattr;
/* Timo : The text brush should never be changed.
* Jérôme : Yeah, but its palette must be updated anyway! */
if(pdcattr->ulDirty_ & DIRTY_TEXT)
EBRUSHOBJ_vUpdateFromDC(&pdc->eboText, pbrDefaultBrush, pdc);
/* Update the eboText's solid color */
EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboText, pdcattr->crForegroundClr);
/* Clear flag */
pdcattr->ulDirty_ &= ~DIRTY_TEXT;
}
VOID
FASTCALL
DC_vUpdateBackgroundBrush(PDC pdc)
{
PDC_ATTR pdcattr = pdc->pdcattr;
if(pdcattr->ulDirty_ & DIRTY_BACKGROUND)
EBRUSHOBJ_vUpdateFromDC(&pdc->eboBackground, pbrDefaultBrush, pdc);
/* Update the eboBackground's solid color */
EBRUSHOBJ_vSetSolidRGBColor(&pdc->eboBackground, pdcattr->crBackgroundClr);
/* Clear flag */
pdcattr->ulDirty_ &= ~DIRTY_BACKGROUND;
}
VOID
NTAPI
DC_vSetBrushOrigin(PDC pdc, LONG x, LONG y)
{
/* Set the brush origin */
pdc->dclevel.ptlBrushOrigin.x = x;
pdc->dclevel.ptlBrushOrigin.y = y;
/* Set the fill origin */
pdc->ptlFillOrigin.x = x + pdc->ptlDCOrig.x;
pdc->ptlFillOrigin.y = y + pdc->ptlDCOrig.y;
}
/**
* \name NtGdiSetBrushOrg
*
* \brief Sets the brush origin that GDI uses when drawing with pattern
* brushes. The brush origin is relative to the DC origin.
*
* @implemented
*/
_Success_(return!=FALSE)
__kernel_entry
BOOL
APIENTRY
NtGdiSetBrushOrg(
_In_ HDC hdc,
_In_ INT x,
_In_ INT y,
_Out_opt_ LPPOINT pptOut)
{
POINT ptOut;
/* Call the internal function */
BOOL Ret = GreSetBrushOrg( hdc, x, y, &ptOut);
if (Ret)
{
/* Check if the old origin was requested */
if (pptOut != NULL)
{
/* Enter SEH for buffer transfer */
_SEH2_TRY
{
/* Probe and copy the old origin */
ProbeForWrite(pptOut, sizeof(POINT), 1);
*pptOut = ptOut;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
_SEH2_YIELD(return FALSE);
}
_SEH2_END;
}
}
return Ret;
}
HPALETTE
NTAPI
GdiSelectPalette(
HDC hDC,
HPALETTE hpal,
BOOL ForceBackground)
{
PDC pdc;
HPALETTE oldPal = NULL;
PPALETTE ppal;
// FIXME: Mark the palette as a [fore\back]ground pal
pdc = DC_LockDc(hDC);
if (!pdc)
{
return NULL;
}
/* Check if this is a valid palette handle */
ppal = PALETTE_ShareLockPalette(hpal);
if (!ppal)
{
DC_UnlockDc(pdc);
return NULL;
}
/// FIXME: we shouldn't dereference pSurface when the PDEV is not locked
/* Is this a valid palette for this depth? */
if ((!pdc->dclevel.pSurface) ||
(BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) <= 8
&& (ppal->flFlags & PAL_INDEXED)) ||
(BitsPerFormat(pdc->dclevel.pSurface->SurfObj.iBitmapFormat) > 8))
{
/* Get old palette, set new one */
oldPal = pdc->dclevel.hpal;
pdc->dclevel.hpal = hpal;
DC_vSelectPalette(pdc, ppal);
/* Mark the brushes invalid */
pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE |
DIRTY_BACKGROUND | DIRTY_TEXT;
}
if(pdc->dctype == DCTYPE_MEMORY)
{
[WIN32K] Rewrite of the GDI handle manager - The old handle manager used a completely retarded spinlock in combination with KeDelayExecutionThread() for both exclusive and shared locks. This is probably the most uneffective algorithm possible. It was also duplicating code everywhere and it was a overall mess It is now replaced with a lock-free reference counter for shared locks and a pushlock for exclusive locks. -> Better performance and scalability. - Allocate user mode object attributes from the new gdi pool. This way, we don't need any caching, since the pool serves as a cache. Its also much faster and uses much less memory. - Allow object allocations of different size, instead of fixed size from a table. This way a single allocation can take care of actual needs. - Allow allcoating objects without a handle and insert them into the handle table later - Properly synchronize the process GDIHandleCount. Now gdiview and taskmanager show the correct number of gdi handles. - Implement a new event tracking system, that is capable of tracking all reverences and locks of objects and pool allocations to help track possible leaks - Make sure that all objects of a process are deleted in cleanup - Make sure all usermode memory allocations are freed, when cleaning up the process pool. - Make sure that each object type is using the correct type of lock (either shared or exclusive, not a mixture) - Fix some object / reference leaks - Lots of inferface improvements - Use global variables for certain things instead of members in the mapped gdi handle table - Make IntSysCreateRectpRgn create a region without a handle - Fix detection od source and mask use in GreStretchBltMask - Use GDIOBJ_bLockMultipleObjects in NtGdiCombineRegion to avoid possible deadlocks - Fix NtGdiAbortPath to reset DCPATH_ACTIVE flag in the dc and only bail out on error, instead of always - Replace DC_AllocateDcAttr and DC_AllocDcAttr with DC_bAllocDcAttr using the new user mode pool - Remove DCU_SyncDcAttrtoUser and DCU_SynchDcAttrtoUser. Those functions were unused and didn't do anything useful anyway, - Replace IntGdiSetDCOwnerEx and DC_SetOwnership with GreSetDCOwner, remove unused NoSetBrush parameter - Replace GDIOBJ_bValidateHandle and IsObjectDead with GreIsHandleValid - Chage GDIOBJ_bLockMultipleObjects: pass object type, return a BOOL, whether all objects could be locked, cleanup on failure svn path=/trunk/; revision=51470
2011-04-28 08:26:46 +00:00
// This didn't work anyway
//IntGdiRealizePalette(hDC);
}
PALETTE_ShareUnlockPalette(ppal);
DC_UnlockDc(pdc);
return oldPal;
}
/*
* @implemented
*/
HBRUSH
APIENTRY
NtGdiSelectBrush(
IN HDC hDC,
IN HBRUSH hBrush)
{
PDC pDC;
HBRUSH hOrgBrush;
if (hDC == NULL || hBrush == NULL) return NULL;
pDC = DC_LockDc(hDC);
if (!pDC)
{
return NULL;
}
/* Simply return the user mode value, without checking */
hOrgBrush = pDC->pdcattr->hbrush;
pDC->pdcattr->hbrush = hBrush;
DC_vUpdateFillBrush(pDC);
DC_UnlockDc(pDC);
return hOrgBrush;
}
/*
* @implemented
*/
HPEN
APIENTRY
NtGdiSelectPen(
IN HDC hDC,
IN HPEN hPen)
{
PDC pDC;
HPEN hOrgPen;
if (hDC == NULL || hPen == NULL) return NULL;
pDC = DC_LockDc(hDC);
if (!pDC)
{
return NULL;
}
/* Simply return the user mode value, without checking */
hOrgPen = pDC->pdcattr->hpen;
pDC->pdcattr->hpen = hPen;
DC_vUpdateLineBrush(pDC);
DC_UnlockDc(pDC);
return hOrgPen;
}
BOOL
NTAPI
DC_bIsBitmapCompatible(PDC pdc, PSURFACE psurf)
{
ULONG cBitsPixel;
/* Must be an API bitmap */
if (!(psurf->flags & API_BITMAP)) return FALSE;
/* DIB sections are always compatible */
if (psurf->hSecure != NULL) return TRUE;
/* See if this is the same PDEV */
if (psurf->SurfObj.hdev == (HDEV)pdc->ppdev)
return TRUE;
/* Get the bit depth of the bitmap */
cBitsPixel = gajBitsPerFormat[psurf->SurfObj.iBitmapFormat];
/* 1 BPP is compatible */
if ((cBitsPixel == 1) || (cBitsPixel == pdc->ppdev->gdiinfo.cBitsPixel))
return TRUE;
return FALSE;
}
/*
* @implemented
*/
HBITMAP
APIENTRY
NtGdiSelectBitmap(
IN HDC hdc,
IN HBITMAP hbmp)
{
PDC pdc;
HBITMAP hbmpOld;
PSURFACE psurfNew, psurfOld;
HDC hdcOld;
ASSERT_NOGDILOCKS();
/* Verify parameters */
if (hdc == NULL || hbmp == NULL) return NULL;
/* First lock the DC */
pdc = DC_LockDc(hdc);
if (!pdc)
{
return NULL;
}
/* Must be a memory dc to select a bitmap */
if (pdc->dctype != DCTYPE_MEMORY)
{
DC_UnlockDc(pdc);
return NULL;
}
/* Save the old bitmap */
psurfOld = pdc->dclevel.pSurface;
/* Check if there is a bitmap selected */
if (psurfOld)
{
/* Get the old bitmap's handle */
hbmpOld = psurfOld->BaseObject.hHmgr;
}
else
{
/* Use the default bitmap */
hbmpOld = StockObjects[DEFAULT_BITMAP];
}
/* Check if the new bitmap is already selected */
if (hbmp == hbmpOld)
{
/* Unlock the DC and return the old bitmap */
DC_UnlockDc(pdc);
return hbmpOld;
}
/* Check if the default bitmap was passed */
if (hbmp == StockObjects[DEFAULT_BITMAP])
{
psurfNew = NULL;
/* Default bitmap is 1x1 pixel */
pdc->dclevel.sizl.cx = 1;
pdc->dclevel.sizl.cy = 1;
}
else
{
/* Reference the new bitmap and check if it's valid */
psurfNew = SURFACE_ShareLockSurface(hbmp);
if (!psurfNew)
{
DC_UnlockDc(pdc);
return NULL;
}
/* Check if the bitmap is compatible with the dc */
if (!DC_bIsBitmapCompatible(pdc, psurfNew))
{
/* Dereference the bitmap, unlock the DC and fail. */
SURFACE_ShareUnlockSurface(psurfNew);
DC_UnlockDc(pdc);
return NULL;
}
/* Set the bitmap's hdc and check if it was set before */
hdcOld = InterlockedCompareExchangePointer((PVOID*)&psurfNew->hdc, hdc, 0);
if (hdcOld != NULL)
{
/* The bitmap is already selected into a different DC */
ASSERT(hdcOld != hdc);
/* Dereference the bitmap, unlock the DC and fail. */
SURFACE_ShareUnlockSurface(psurfNew);
DC_UnlockDc(pdc);
return NULL;
}
/* Copy the bitmap size */
pdc->dclevel.sizl = psurfNew->SurfObj.sizlBitmap;
/* Check if the bitmap is a dibsection */
if (psurfNew->hSecure)
{
/* Set DIBSECTION attribute */
pdc->pdcattr->ulDirty_ |= DC_DIBSECTION;
}
else
{
/* Remove DIBSECTION attribute */
pdc->pdcattr->ulDirty_ &= ~DC_DIBSECTION;
}
}
/* Select the new bitmap */
pdc->dclevel.pSurface = psurfNew;
/* Check if there was a bitmap selected before */
if (psurfOld)
{
/* Reset hdc of the old bitmap, it isn't selected anymore */
psurfOld->hdc = NULL;
/* Dereference the old bitmap */
SURFACE_ShareUnlockSurface(psurfOld);
}
/* Mark the DC brushes and the RAO region invalid */
pdc->pdcattr->ulDirty_ |= DIRTY_FILL | DIRTY_LINE;
pdc->fs |= DC_DIRTY_RAO;
/* Update the system region */
REGION_SetRectRgn(pdc->prgnVis,
0,
0,
pdc->dclevel.sizl.cx,
pdc->dclevel.sizl.cy);
/* Unlock the DC */
DC_UnlockDc(pdc);
/* Return the old bitmap handle */
return hbmpOld;
}
BOOL
APIENTRY
NtGdiSelectClipPath(
HDC hDC,
int Mode)
{
PREGION RgnPath;
PPATH pPath, pNewPath;
BOOL success = FALSE;
PDC_ATTR pdcattr;
PDC pdc;
pdc = DC_LockDc(hDC);
if (!pdc)
{
EngSetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
pdcattr = pdc->pdcattr;
pPath = PATH_LockPath(pdc->dclevel.hPath);
if (!pPath)
{
DC_UnlockDc(pdc);
return FALSE;
}
/* Check that path is closed */
if (pPath->state != PATH_Closed)
{
EngSetLastError(ERROR_CAN_NOT_COMPLETE);
success = FALSE;
goto Exit;
}
/* Construct a region from the path */
RgnPath = IntSysCreateRectpRgn(0, 0, 0, 0);
if (!RgnPath)
{
EngSetLastError(ERROR_NOT_ENOUGH_MEMORY);
DC_UnlockDc(pdc);
return FALSE;
}
pNewPath = PATH_FlattenPath(pPath);
success = PATH_PathToRegion(pNewPath, pdcattr->jFillMode, RgnPath);
PATH_UnlockPath(pNewPath);
PATH_Delete(pNewPath->BaseObject.hHmgr);
if (success) success = IntGdiExtSelectClipRgn(pdc, RgnPath, Mode) != ERROR;
REGION_Delete(RgnPath);
Exit:
PATH_UnlockPath(pPath);
PATH_Delete(pdc->dclevel.hPath);
pdc->dclevel.flPath &= ~DCPATH_ACTIVE;
pdc->dclevel.hPath = NULL;
DC_UnlockDc(pdc);
return success;
}
HFONT
NTAPI
DC_hSelectFont(
_In_ PDC pdc,
_In_ HFONT hlfntNew)
{
PLFONT plfntNew;
HFONT hlfntOld;
// Legacy crap that will die with font engine rewrite
if (!NT_SUCCESS(TextIntRealizeFont(hlfntNew, NULL)))
{
return NULL;
}
/* Get the current selected font */
hlfntOld = pdc->dclevel.plfnt->BaseObject.hHmgr;
/* Check if a new font should be selected */
if (hlfntNew != hlfntOld)
{
/* Lock the new font */
plfntNew = LFONT_ShareLockFont(hlfntNew);
if (plfntNew)
{
/* Success, dereference the old font */
LFONT_ShareUnlockFont(pdc->dclevel.plfnt);
/* Select the new font */
pdc->dclevel.plfnt = plfntNew;
pdc->pdcattr->hlfntNew = hlfntNew;
/* Update dirty flags */
pdc->pdcattr->ulDirty_ |= DIRTY_CHARSET;
pdc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
}
else
{
/* Failed, restore old, return NULL */
pdc->pdcattr->hlfntNew = hlfntOld;
hlfntOld = NULL;
}
}
return hlfntOld;
}
HFONT
APIENTRY
NtGdiSelectFont(
_In_ HDC hdc,
_In_ HFONT hfont)
{
HFONT hfontOld;
PDC pdc;
/* Check parameters */
if ((hdc == NULL) || (hfont == NULL))
{
return NULL;
}
/* Lock the DC */
pdc = DC_LockDc(hdc);
if (!pdc)
{
return NULL;
}
/* Call the internal function */
hfontOld = DC_hSelectFont(pdc, hfont);
/* Unlock the DC */
DC_UnlockDc(pdc);
/* Return the previously selected font */
return hfontOld;
}
HANDLE
APIENTRY
NtGdiGetDCObject(HDC hDC, INT ObjectType)
{
HGDIOBJ SelObject;
DC *pdc;
PDC_ATTR pdcattr;
/* From Wine: GetCurrentObject does not SetLastError() on a null object */
if(!hDC) return NULL;
if(!(pdc = DC_LockDc(hDC)))
{
return NULL;
}
pdcattr = pdc->pdcattr;
if (pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
DC_vUpdateFillBrush(pdc);
if (pdcattr->ulDirty_ & (DIRTY_LINE | DC_PEN_DIRTY))
DC_vUpdateLineBrush(pdc);
switch(ObjectType)
{
case GDI_OBJECT_TYPE_EXTPEN:
case GDI_OBJECT_TYPE_PEN:
SelObject = pdcattr->hpen;
break;
case GDI_OBJECT_TYPE_BRUSH:
SelObject = pdcattr->hbrush;
break;
case GDI_OBJECT_TYPE_PALETTE:
SelObject = pdc->dclevel.hpal;
break;
case GDI_OBJECT_TYPE_FONT:
SelObject = pdcattr->hlfntNew;
break;
case GDI_OBJECT_TYPE_BITMAP:
{
SURFACE *psurf = pdc->dclevel.pSurface;
SelObject = psurf ? psurf->BaseObject.hHmgr : StockObjects[DEFAULT_BITMAP];
break;
}
case GDI_OBJECT_TYPE_COLORSPACE:
DPRINT1("FIXME: NtGdiGetCurrentObject() ObjectType OBJ_COLORSPACE not supported yet!\n");
// SelObject = dc->dclevel.pColorSpace.BaseObject.hHmgr; ?
SelObject = NULL;
break;
default:
SelObject = NULL;
EngSetLastError(ERROR_INVALID_PARAMETER);
break;
}
DC_UnlockDc(pdc);
return SelObject;
}
/* See WINE, MSDN, OSR and Feng Yuan - Windows Graphics Programming Win32 GDI and DirectDraw
*
* 1st: http://www.codeproject.com/gdi/cliprgnguide.asp is wrong!
*
* The intersection of the clip with the meta region is not Rao it's API!
* Go back and read 7.2 Clipping pages 418-19:
* Rao = API & Vis:
* 1) The Rao region is the intersection of the API region and the system region,
* named after the Microsoft engineer who initially proposed it.
* 2) The Rao region can be calculated from the API region and the system region.
*
* API:
* API region is the intersection of the meta region and the clipping region,
* clearly named after the fact that it is controlled by GDI API calls.
*/
INT
APIENTRY
NtGdiGetRandomRgn(
HDC hdc,
HRGN hrgnDest,
INT iCode)
{
INT ret = 0;
PDC pdc;
PREGION prgnSrc = NULL;
pdc = DC_LockDc(hdc);
if (!pdc)
{
EngSetLastError(ERROR_INVALID_HANDLE);
return -1;
}
switch (iCode)
{
case CLIPRGN:
prgnSrc = pdc->dclevel.prgnClip;
break;
case METARGN:
prgnSrc = pdc->dclevel.prgnMeta;
break;
case APIRGN:
if (pdc->fs & DC_DIRTY_RAO)
CLIPPING_UpdateGCRegion(pdc);
if (pdc->prgnAPI)
{
prgnSrc = pdc->prgnAPI;
}
else if (pdc->dclevel.prgnClip)
{
prgnSrc = pdc->dclevel.prgnClip;
}
else if (pdc->dclevel.prgnMeta)
[WIN32K] Rewrite of the GDI handle manager - The old handle manager used a completely retarded spinlock in combination with KeDelayExecutionThread() for both exclusive and shared locks. This is probably the most uneffective algorithm possible. It was also duplicating code everywhere and it was a overall mess It is now replaced with a lock-free reference counter for shared locks and a pushlock for exclusive locks. -> Better performance and scalability. - Allocate user mode object attributes from the new gdi pool. This way, we don't need any caching, since the pool serves as a cache. Its also much faster and uses much less memory. - Allow object allocations of different size, instead of fixed size from a table. This way a single allocation can take care of actual needs. - Allow allcoating objects without a handle and insert them into the handle table later - Properly synchronize the process GDIHandleCount. Now gdiview and taskmanager show the correct number of gdi handles. - Implement a new event tracking system, that is capable of tracking all reverences and locks of objects and pool allocations to help track possible leaks - Make sure that all objects of a process are deleted in cleanup - Make sure all usermode memory allocations are freed, when cleaning up the process pool. - Make sure that each object type is using the correct type of lock (either shared or exclusive, not a mixture) - Fix some object / reference leaks - Lots of inferface improvements - Use global variables for certain things instead of members in the mapped gdi handle table - Make IntSysCreateRectpRgn create a region without a handle - Fix detection od source and mask use in GreStretchBltMask - Use GDIOBJ_bLockMultipleObjects in NtGdiCombineRegion to avoid possible deadlocks - Fix NtGdiAbortPath to reset DCPATH_ACTIVE flag in the dc and only bail out on error, instead of always - Replace DC_AllocateDcAttr and DC_AllocDcAttr with DC_bAllocDcAttr using the new user mode pool - Remove DCU_SyncDcAttrtoUser and DCU_SynchDcAttrtoUser. Those functions were unused and didn't do anything useful anyway, - Replace IntGdiSetDCOwnerEx and DC_SetOwnership with GreSetDCOwner, remove unused NoSetBrush parameter - Replace GDIOBJ_bValidateHandle and IsObjectDead with GreIsHandleValid - Chage GDIOBJ_bLockMultipleObjects: pass object type, return a BOOL, whether all objects could be locked, cleanup on failure svn path=/trunk/; revision=51470
2011-04-28 08:26:46 +00:00
{
prgnSrc = pdc->dclevel.prgnMeta;
[WIN32K] Rewrite of the GDI handle manager - The old handle manager used a completely retarded spinlock in combination with KeDelayExecutionThread() for both exclusive and shared locks. This is probably the most uneffective algorithm possible. It was also duplicating code everywhere and it was a overall mess It is now replaced with a lock-free reference counter for shared locks and a pushlock for exclusive locks. -> Better performance and scalability. - Allocate user mode object attributes from the new gdi pool. This way, we don't need any caching, since the pool serves as a cache. Its also much faster and uses much less memory. - Allow object allocations of different size, instead of fixed size from a table. This way a single allocation can take care of actual needs. - Allow allcoating objects without a handle and insert them into the handle table later - Properly synchronize the process GDIHandleCount. Now gdiview and taskmanager show the correct number of gdi handles. - Implement a new event tracking system, that is capable of tracking all reverences and locks of objects and pool allocations to help track possible leaks - Make sure that all objects of a process are deleted in cleanup - Make sure all usermode memory allocations are freed, when cleaning up the process pool. - Make sure that each object type is using the correct type of lock (either shared or exclusive, not a mixture) - Fix some object / reference leaks - Lots of inferface improvements - Use global variables for certain things instead of members in the mapped gdi handle table - Make IntSysCreateRectpRgn create a region without a handle - Fix detection od source and mask use in GreStretchBltMask - Use GDIOBJ_bLockMultipleObjects in NtGdiCombineRegion to avoid possible deadlocks - Fix NtGdiAbortPath to reset DCPATH_ACTIVE flag in the dc and only bail out on error, instead of always - Replace DC_AllocateDcAttr and DC_AllocDcAttr with DC_bAllocDcAttr using the new user mode pool - Remove DCU_SyncDcAttrtoUser and DCU_SynchDcAttrtoUser. Those functions were unused and didn't do anything useful anyway, - Replace IntGdiSetDCOwnerEx and DC_SetOwnership with GreSetDCOwner, remove unused NoSetBrush parameter - Replace GDIOBJ_bValidateHandle and IsObjectDead with GreIsHandleValid - Chage GDIOBJ_bLockMultipleObjects: pass object type, return a BOOL, whether all objects could be locked, cleanup on failure svn path=/trunk/; revision=51470
2011-04-28 08:26:46 +00:00
}
break;
case SYSRGN:
prgnSrc = pdc->prgnVis;
break;
default:
break;
}
if (prgnSrc)
{
PREGION prgnDest = REGION_LockRgn(hrgnDest);
if (prgnDest)
{
ret = IntGdiCombineRgn(prgnDest, prgnSrc, 0, RGN_COPY) == ERROR ? -1 : 1;
if ((ret == 1) && (iCode == SYSRGN))
{
/// \todo FIXME This is not really correct, since we already modified the region
ret = REGION_bOffsetRgn(prgnDest, pdc->ptlDCOrig.x, pdc->ptlDCOrig.y);
}
REGION_UnlockRgn(prgnDest);
}
else
ret = -1;
}
DC_UnlockDc(pdc);
return ret;
}
ULONG
APIENTRY
NtGdiEnumObjects(
IN HDC hdc,
IN INT iObjectType,
IN ULONG cjBuf,
OUT OPTIONAL PVOID pvBuf)
{
UNIMPLEMENTED;
return 0;
}
/* EOF */