Some people were thinking they could use NtGdiExtTextOut from within Win32k and get away with it. Since MmCopyFromCaller is broken, it was actually working. Implement NtGdiExtTextOutW as a wrapper around the real function, that is now called GreExtTextOutW, using the naming style that ms also uses to get some more stucture in here. Also get rid of 2 pool allocations and use only one if a local buffer is not sufficient. Should get us more TextOut performance.

svn path=/trunk/; revision=38261
This commit is contained in:
Timo Kreuzer 2008-12-22 03:58:04 +00:00
parent 955a660368
commit 766c25b7e3
4 changed files with 139 additions and 73 deletions

View file

@ -104,6 +104,8 @@ DWORD FASTCALL ftGdiGetFontData(PFONTGDI,DWORD,DWORD,PVOID,DWORD);
BOOL FASTCALL IntGdiGetFontResourceInfo(PUNICODE_STRING,PVOID,DWORD*,DWORD);
BOOL FASTCALL ftGdiRealizationInfo(PFONTGDI,PREALIZATION_INFO);
DWORD FASTCALL ftGdiGetKerningPairs(PFONTGDI,DWORD,LPKERNINGPAIR);
BOOL NTAPI GreExtTextOutW(IN HDC,IN INT,IN INT,IN UINT,IN OPTIONAL LPRECT,
IN LPWSTR, IN INT, IN OPTIONAL LPINT, IN DWORD);
#define IntLockProcessPrivateFonts(W32Process) \
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&W32Process->PrivateFontListLock)

View file

@ -1536,7 +1536,7 @@ NtUserPaintDesktop(HDC hDC)
align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
mode_old = IntGdiSetBkMode(hDC, TRANSPARENT);
NtGdiExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
GreExtTextOutW(hDC, rect.right-16, rect.bottom-48, 0, NULL, s_wszVersion, len, NULL, 0);
IntGdiSetBkMode(hDC, mode_old);
IntGdiSetTextAlign(hDC, align_old);

View file

@ -1594,7 +1594,7 @@ UserDrawCaptionText(HDC hDc,
//FIXME: If string doesn't fit to rc, truncate it and add ellipsis.
NtGdiExtTextOutW(hDc, lpRc->left,
GreExtTextOutW(hDc, lpRc->left,
lpRc->top, 0, NULL, Text->Buffer,
Text->Length/sizeof(WCHAR), NULL, 0);

View file

@ -3079,15 +3079,15 @@ NtGdiGetFontFamilyInfo(HDC Dc,
BOOL
APIENTRY
NtGdiExtTextOutW(
GreExtTextOutW(
IN HDC hDC,
IN INT XStart,
IN INT YStart,
IN UINT fuOptions,
IN OPTIONAL LPRECT lprc,
IN LPWSTR UnsafeString,
IN LPWSTR String,
IN INT Count,
IN OPTIONAL LPINT UnsafeDx,
IN OPTIONAL LPINT Dx,
IN DWORD dwCodePage)
{
/*
@ -3108,7 +3108,7 @@ NtGdiExtTextOutW(
LONGLONG TextLeft, RealXStart;
ULONG TextTop, previous, BackgroundLeft;
FT_Bool use_kerning;
RECTL DestRect, MaskRect, SpecifiedDestRect;
RECTL DestRect, MaskRect;
POINTL SourcePoint, BrushOrigin;
HBRUSH hBrushFg = NULL;
PGDIBRUSHOBJ BrushFg = NULL;
@ -3129,11 +3129,8 @@ NtGdiExtTextOutW(
ULONG Mode;
FT_Render_Mode RenderMode;
BOOLEAN Render;
NTSTATUS Status;
INT *Dx = NULL;
POINT Start;
BOOL DoBreak = FALSE;
LPCWSTR String, SafeString = NULL;
HPALETTE hDestPalette;
// TODO: Write test-cases to exactly match real Windows in different
@ -3155,49 +3152,11 @@ NtGdiExtTextOutW(
if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
/* Check if String is valid */
if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
goto fail;
}
if (Count > 0)
{
SafeString = ExAllocatePoolWithTag(PagedPool, Count * sizeof(WCHAR), TAG_GDITEXT);
if (!SafeString)
{
goto fail;
}
Status = MmCopyFromCaller(SafeString, UnsafeString, Count * sizeof(WCHAR));
if (! NT_SUCCESS(Status))
{
goto fail;
}
}
String = SafeString;
if (NULL != UnsafeDx && Count > 0)
{
Dx = ExAllocatePoolWithTag(PagedPool, Count * sizeof(INT), TAG_GDITEXT);
if (NULL == Dx)
{
goto fail;
}
Status = MmCopyFromCaller(Dx, UnsafeDx, Count * sizeof(INT));
if (!NT_SUCCESS(Status))
{
goto fail;
}
}
if (lprc)
{
Status = MmCopyFromCaller(&SpecifiedDestRect, lprc, sizeof(RECT));
if (!NT_SUCCESS(Status))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
goto fail;
}
}
if (PATH_IsPathOpen(dc->DcLevel))
{
@ -3205,8 +3164,8 @@ NtGdiExtTextOutW(
XStart,
YStart,
fuOptions,
(const RECT *)&SpecifiedDestRect,
SafeString,
(const RECT *)lprc,
String,
Count,
(const INT *)Dx)) goto fail;
goto good;
@ -3214,7 +3173,7 @@ NtGdiExtTextOutW(
if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
{
IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2);
IntLPtoDP(dc, (POINT *)lprc, 2);
}
BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
@ -3288,10 +3247,10 @@ NtGdiExtTextOutW(
if ((fuOptions & ETO_OPAQUE) && lprc)
{
DestRect.left = SpecifiedDestRect.left + dc->ptlDCOrig.x;
DestRect.top = SpecifiedDestRect.top + dc->ptlDCOrig.y;
DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
DestRect.bottom = SpecifiedDestRect.bottom + dc->ptlDCOrig.y;
DestRect.left = lprc->left + dc->ptlDCOrig.x;
DestRect.top = lprc->top + dc->ptlDCOrig.y;
DestRect.right = lprc->right + dc->ptlDCOrig.x;
DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
IntEngBitBlt(
&BitmapObj->SurfObj,
@ -3602,12 +3561,12 @@ NtGdiExtTextOutW(
if (lprc &&
(fuOptions & ETO_CLIPPED) &&
DestRect.right >= SpecifiedDestRect.right + dc->ptlDCOrig.x)
DestRect.right >= lprc->right + dc->ptlDCOrig.x)
{
// We do the check '>=' instead of '>' to possibly save an iteration
// through this loop, since it's breaking after the drawing is done,
// and x is always incremented.
DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x;
DestRect.right = lprc->right + dc->ptlDCOrig.x;
DoBreak = TRUE;
}
@ -3661,14 +3620,6 @@ NtGdiExtTextOutW(
BRUSHOBJ_UnlockBrush(BrushFg);
NtGdiDeleteObject(hBrushFg);
good:
if (NULL != SafeString)
{
ExFreePoolWithTag((void*)SafeString, TAG_GDITEXT);
}
if (NULL != Dx)
{
ExFreePoolWithTag(Dx, TAG_GDITEXT);
}
DC_UnlockDc( dc );
return TRUE;
@ -3692,19 +3643,132 @@ fail:
BRUSHOBJ_UnlockBrush(BrushFg);
NtGdiDeleteObject(hBrushFg);
}
if (NULL != SafeString)
{
ExFreePoolWithTag((void*)SafeString, TAG_GDITEXT);
}
if (NULL != Dx)
{
ExFreePoolWithTag(Dx, TAG_GDITEXT);
}
DC_UnlockDc(dc);
return FALSE;
}
#define STACK_TEXT_BUFFER_SIZE 50
BOOL
APIENTRY
NtGdiExtTextOutW(
IN HDC hDC,
IN INT XStart,
IN INT YStart,
IN UINT fuOptions,
IN OPTIONAL LPRECT UnsafeRect,
IN LPWSTR UnsafeString,
IN INT Count,
IN OPTIONAL LPINT UnsafeDx,
IN DWORD dwCodePage)
{
BOOL Result = FALSE;
NTSTATUS Status = STATUS_SUCCESS;
RECT SafeRect;
BYTE LocalBuffer[STACK_TEXT_BUFFER_SIZE];
PVOID Buffer = LocalBuffer;
LPWSTR SafeString = NULL;
LPINT SafeDx = NULL;
ULONG BufSize, StringSize, DxSize = 0;
/* Check if String is valid */
if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL))
{
SetLastWin32Error(ERROR_INVALID_PARAMETER);
return FALSE;
}
if (Count > 0)
{
/* Calculate buffer size for string and Dx values */
BufSize = StringSize = Count * sizeof(WCHAR);
if (UnsafeDx)
{
/* If ETO_PDY is specified, we have pairs of INTs */
DxSize = (Count * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
BufSize += DxSize;
}
/* Check if our local buffer is large enough */
if (BufSize > STACK_TEXT_BUFFER_SIZE)
{
/* It's not, allocate a temp buffer */
Buffer = ExAllocatePoolWithTag(PagedPool, BufSize, TAG_GDITEXT);
if (!Buffer)
{
return FALSE;
}
}
/* Probe and copy user mode data to the buffer */
_SEH2_TRY
{
/* Probe and copy the string */
ProbeForRead(UnsafeString, StringSize, 1);
SafeString = Buffer;
memcpy((PVOID)SafeString, UnsafeString, StringSize);
/* If we have Dx values... */
if (UnsafeDx)
{
/* ... probe and copy them */
ProbeForRead(UnsafeDx, DxSize, 1);
SafeDx = (LPINT)(((ULONG_PTR)Buffer) + StringSize);
memcpy(SafeDx, UnsafeDx, DxSize);
}
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (!NT_SUCCESS(Status))
{
goto cleanup;
}
}
/* If we have a rect, copy it */
if (UnsafeRect)
{
_SEH2_TRY
{
ProbeForRead(UnsafeRect, sizeof(RECT), 1);
SafeRect = *UnsafeRect;
}
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
{
Status = _SEH2_GetExceptionCode();
}
_SEH2_END
if (!NT_SUCCESS(Status))
{
goto cleanup;
}
}
/* Finally call the internal routine */
Result = GreExtTextOutW(hDC,
XStart,
YStart,
fuOptions,
&SafeRect,
SafeString,
Count,
SafeDx,
dwCodePage);
cleanup:
/* If we allocated a buffer, free it */
if (Buffer != LocalBuffer)
{
ExFreePoolWithTag(Buffer, TAG_GDITEXT);
}
return Result;;
}
/*
* @implemented
*/