- Fix pointer arithmetics in the gdi batch code (&pTeb->GdiTebBatch.Buffer[0] is a PULONG, but pTeb->GdiTebBatch.Offset is a byte offset)
- To prevent this from happening again, refactor the code to use one common routine GdiAllocBatchCommand to do most of the stuff.
- Reenable gdi batch for SelectObject
- Fixes gdi handle leak, causes some drawing problems in Acrobat reader, but those are less critical and I'll investigate those.

svn path=/trunk/; revision=47074
This commit is contained in:
Timo Kreuzer 2010-05-01 13:02:46 +00:00
parent 18af76559c
commit f4fd1abac0
3 changed files with 107 additions and 36 deletions

View file

@ -292,4 +292,91 @@ int FASTCALL DocumentEventEx(PVOID,HANDLE,HDC,int,ULONG,PVOID,ULONG,PVOID);
BOOL FASTCALL EndPagePrinterEx(PVOID,HANDLE);
BOOL FASTCALL LoadTheSpoolerDrv(VOID);
FORCEINLINE
PVOID
GdiAllocBatchCommand(
HDC hdc,
USHORT Cmd)
{
PTEB pTeb;
ULONG ulSize;
PGDIBATCHHDR pHdr;
/* Get a pointer to the TEB */
pTeb = NtCurrentTeb();
/* Check if we have a valid environment */
if (!pTeb || !pTeb->Win32ThreadInfo) return NULL;
/* Do we use a DC? */
if (hdc)
{
/* If the batch DC is NULL, we set this one as the new one */
if (!pTeb->GdiTebBatch.HDC) pTeb->GdiTebBatch.HDC = hdc;
/* If not, check if the batch DC equal to our DC */
else if (pTeb->GdiTebBatch.HDC != hdc) return NULL;
}
/* Get the size of the entry */
switch(Cmd)
{
case GdiBCPatBlt:
ulSize = 0;
break;
case GdiBCPolyPatBlt:
ulSize = 0;
break;
case GdiBCTextOut:
ulSize = 0;
break;
case GdiBCExtTextOut:
ulSize = 0;
break;
case GdiBCSetBrushOrg:
ulSize = 0;
break;
case GdiBCExtSelClipRgn:
ulSize = 0;
break;
case GdiBCSelObj:
ulSize = sizeof(GDIBSOBJECT);
break;
case GdiBCDelRgn:
ulSize = sizeof(GDIBSOBJECT);
break;
case GdiBCDelObj:
ulSize = sizeof(GDIBSOBJECT);
break;
default:
return NULL;
}
/* Unsupported operation */
if (ulSize == 0) return NULL;
/* Check if the buffer is full */
if ((pTeb->GdiBatchCount >= GDI_BatchLimit) ||
((pTeb->GdiTebBatch.Offset + ulSize) > GDIBATCHBUFSIZE))
{
/* Call win32k, the kernel will call NtGdiFlushUserBatch to flush
the current batch */
NtGdiFlush();
}
/* Get the head of the entry */
pHdr = (PVOID)((PUCHAR)pTeb->GdiTebBatch.Buffer + pTeb->GdiTebBatch.Offset);
/* Update Offset and batch count */
pTeb->GdiTebBatch.Offset += ulSize;
pTeb->GdiBatchCount++;
/* Fill in the core fields */
pHdr->Cmd = Cmd;
pHdr->Size = ulSize;
return pHdr;
}
/* EOF */

View file

@ -1540,7 +1540,6 @@ SelectObject(HDC hDC,
PDC_ATTR pDc_Attr;
HGDIOBJ hOldObj = NULL;
UINT uType;
// PTEB pTeb;
if(!GdiGetHandleUserData(hDC, GDI_OBJECT_TYPE_DC, (PVOID)&pDc_Attr))
{
@ -1582,29 +1581,23 @@ SelectObject(HDC hDC,
case GDI_OBJECT_TYPE_FONT:
hOldObj = pDc_Attr->hlfntNew;
if (hOldObj == hGdiObj) return hOldObj;
#if 0
pDc_Attr->ulDirty_ &= ~SLOW_WIDTHS;
pDc_Attr->ulDirty_ |= DIRTY_CHARSET;
pDc_Attr->hlfntNew = hGdiObj;
pTeb = NtCurrentTeb();
if (((pTeb->GdiTebBatch.HDC == 0) ||
(pTeb->GdiTebBatch.HDC == hDC)) &&
((pTeb->GdiTebBatch.Offset + sizeof(GDIBSOBJECT)) <= GDIBATCHBUFSIZE) &&
(!(pDc_Attr->ulDirty_ & DC_DIBSECTION)))
{
PGDIBSOBJECT pgO = (PGDIBSOBJECT)(&pTeb->GdiTebBatch.Buffer[0] +
pTeb->GdiTebBatch.Offset);
pgO->gbHdr.Cmd = GdiBCSelObj;
pgO->gbHdr.Size = sizeof(GDIBSOBJECT);
pgO->hgdiobj = hGdiObj;
pTeb->GdiTebBatch.Offset += sizeof(GDIBSOBJECT);
pTeb->GdiTebBatch.HDC = hDC;
pTeb->GdiBatchCount++;
if (pTeb->GdiBatchCount >= GDI_BatchLimit) NtGdiFlush();
return hOldObj;
if (!(pDc_Attr->ulDirty_ & DC_DIBSECTION))
{
PGDIBSOBJECT pgO;
pgO = GdiAllocBatchCommand(hDC, GdiBCSelObj);
if (pgO)
{
pgO->hgdiobj = hGdiObj;
return hOldObj;
}
}
#endif
// default for select object font
return NtGdiSelectFont(hDC, hGdiObj);

View file

@ -109,23 +109,14 @@ DeleteRegion( HRGN hRgn )
if ((GdiGetHandleUserData((HGDIOBJ) hRgn, GDI_OBJECT_TYPE_REGION, (PVOID) &Rgn_Attr)) &&
( Rgn_Attr != NULL ))
{
PTEB pTeb = NtCurrentTeb();
if (pTeb->Win32ThreadInfo != NULL)
{
if ((pTeb->GdiTebBatch.Offset + sizeof(GDIBSOBJECT)) <= GDIBATCHBUFSIZE)
{
PGDIBSOBJECT pgO = (PGDIBSOBJECT)(&pTeb->GdiTebBatch.Buffer[0] +
pTeb->GdiTebBatch.Offset);
pgO->gbHdr.Cmd = GdiBCDelRgn;
pgO->gbHdr.Size = sizeof(GDIBSOBJECT);
pgO->hgdiobj = (HGDIOBJ)hRgn;
pTeb->GdiTebBatch.Offset += sizeof(GDIBSOBJECT);
pTeb->GdiBatchCount++;
if (pTeb->GdiBatchCount >= GDI_BatchLimit) NtGdiFlush();
return TRUE;
}
}
PGDIBSOBJECT pgO;
pgO = GdiAllocBatchCommand(NULL, GdiBCDelRgn);
if (pgO)
{
pgO->hgdiobj = (HGDIOBJ)hRgn;
return TRUE;
}
}
return NtGdiDeleteObjectApp((HGDIOBJ) hRgn);
}