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 IntGdiGetFontResourceInfo(PUNICODE_STRING,PVOID,DWORD*,DWORD);
BOOL FASTCALL ftGdiRealizationInfo(PFONTGDI,PREALIZATION_INFO); BOOL FASTCALL ftGdiRealizationInfo(PFONTGDI,PREALIZATION_INFO);
DWORD FASTCALL ftGdiGetKerningPairs(PFONTGDI,DWORD,LPKERNINGPAIR); 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) \ #define IntLockProcessPrivateFonts(W32Process) \
ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&W32Process->PrivateFontListLock) ExEnterCriticalRegionAndAcquireFastMutexUnsafe(&W32Process->PrivateFontListLock)

View file

@ -1536,7 +1536,7 @@ NtUserPaintDesktop(HDC hDC)
align_old = IntGdiSetTextAlign(hDC, TA_RIGHT); align_old = IntGdiSetTextAlign(hDC, TA_RIGHT);
mode_old = IntGdiSetBkMode(hDC, TRANSPARENT); 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); IntGdiSetBkMode(hDC, mode_old);
IntGdiSetTextAlign(hDC, align_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. //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, lpRc->top, 0, NULL, Text->Buffer,
Text->Length/sizeof(WCHAR), NULL, 0); Text->Length/sizeof(WCHAR), NULL, 0);

View file

@ -3079,15 +3079,15 @@ NtGdiGetFontFamilyInfo(HDC Dc,
BOOL BOOL
APIENTRY APIENTRY
NtGdiExtTextOutW( GreExtTextOutW(
IN HDC hDC, IN HDC hDC,
IN INT XStart, IN INT XStart,
IN INT YStart, IN INT YStart,
IN UINT fuOptions, IN UINT fuOptions,
IN OPTIONAL LPRECT lprc, IN OPTIONAL LPRECT lprc,
IN LPWSTR UnsafeString, IN LPWSTR String,
IN INT Count, IN INT Count,
IN OPTIONAL LPINT UnsafeDx, IN OPTIONAL LPINT Dx,
IN DWORD dwCodePage) IN DWORD dwCodePage)
{ {
/* /*
@ -3108,7 +3108,7 @@ NtGdiExtTextOutW(
LONGLONG TextLeft, RealXStart; LONGLONG TextLeft, RealXStart;
ULONG TextTop, previous, BackgroundLeft; ULONG TextTop, previous, BackgroundLeft;
FT_Bool use_kerning; FT_Bool use_kerning;
RECTL DestRect, MaskRect, SpecifiedDestRect; RECTL DestRect, MaskRect;
POINTL SourcePoint, BrushOrigin; POINTL SourcePoint, BrushOrigin;
HBRUSH hBrushFg = NULL; HBRUSH hBrushFg = NULL;
PGDIBRUSHOBJ BrushFg = NULL; PGDIBRUSHOBJ BrushFg = NULL;
@ -3129,11 +3129,8 @@ NtGdiExtTextOutW(
ULONG Mode; ULONG Mode;
FT_Render_Mode RenderMode; FT_Render_Mode RenderMode;
BOOLEAN Render; BOOLEAN Render;
NTSTATUS Status;
INT *Dx = NULL;
POINT Start; POINT Start;
BOOL DoBreak = FALSE; BOOL DoBreak = FALSE;
LPCWSTR String, SafeString = NULL;
HPALETTE hDestPalette; HPALETTE hDestPalette;
// TODO: Write test-cases to exactly match real Windows in different // TODO: Write test-cases to exactly match real Windows in different
@ -3155,49 +3152,11 @@ NtGdiExtTextOutW(
if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr; if (!Dc_Attr) Dc_Attr = &dc->Dc_Attr;
/* Check if String is valid */ /* Check if String is valid */
if ((Count > 0xFFFF) || (Count > 0 && UnsafeString == NULL)) if ((Count > 0xFFFF) || (Count > 0 && String == NULL))
{ {
SetLastWin32Error(ERROR_INVALID_PARAMETER); SetLastWin32Error(ERROR_INVALID_PARAMETER);
goto fail; 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)) if (PATH_IsPathOpen(dc->DcLevel))
{ {
@ -3205,8 +3164,8 @@ NtGdiExtTextOutW(
XStart, XStart,
YStart, YStart,
fuOptions, fuOptions,
(const RECT *)&SpecifiedDestRect, (const RECT *)lprc,
SafeString, String,
Count, Count,
(const INT *)Dx)) goto fail; (const INT *)Dx)) goto fail;
goto good; goto good;
@ -3214,7 +3173,7 @@ NtGdiExtTextOutW(
if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED))) if (lprc && (fuOptions & (ETO_OPAQUE | ETO_CLIPPED)))
{ {
IntLPtoDP(dc, (POINT *) &SpecifiedDestRect, 2); IntLPtoDP(dc, (POINT *)lprc, 2);
} }
BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap); BitmapObj = BITMAPOBJ_LockBitmap(dc->w.hBitmap);
@ -3288,10 +3247,10 @@ NtGdiExtTextOutW(
if ((fuOptions & ETO_OPAQUE) && lprc) if ((fuOptions & ETO_OPAQUE) && lprc)
{ {
DestRect.left = SpecifiedDestRect.left + dc->ptlDCOrig.x; DestRect.left = lprc->left + dc->ptlDCOrig.x;
DestRect.top = SpecifiedDestRect.top + dc->ptlDCOrig.y; DestRect.top = lprc->top + dc->ptlDCOrig.y;
DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x; DestRect.right = lprc->right + dc->ptlDCOrig.x;
DestRect.bottom = SpecifiedDestRect.bottom + dc->ptlDCOrig.y; DestRect.bottom = lprc->bottom + dc->ptlDCOrig.y;
IntLPtoDP(dc, (LPPOINT)&DestRect, 2); IntLPtoDP(dc, (LPPOINT)&DestRect, 2);
IntEngBitBlt( IntEngBitBlt(
&BitmapObj->SurfObj, &BitmapObj->SurfObj,
@ -3602,12 +3561,12 @@ NtGdiExtTextOutW(
if (lprc && if (lprc &&
(fuOptions & ETO_CLIPPED) && (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 // We do the check '>=' instead of '>' to possibly save an iteration
// through this loop, since it's breaking after the drawing is done, // through this loop, since it's breaking after the drawing is done,
// and x is always incremented. // and x is always incremented.
DestRect.right = SpecifiedDestRect.right + dc->ptlDCOrig.x; DestRect.right = lprc->right + dc->ptlDCOrig.x;
DoBreak = TRUE; DoBreak = TRUE;
} }
@ -3661,14 +3620,6 @@ NtGdiExtTextOutW(
BRUSHOBJ_UnlockBrush(BrushFg); BRUSHOBJ_UnlockBrush(BrushFg);
NtGdiDeleteObject(hBrushFg); NtGdiDeleteObject(hBrushFg);
good: good:
if (NULL != SafeString)
{
ExFreePoolWithTag((void*)SafeString, TAG_GDITEXT);
}
if (NULL != Dx)
{
ExFreePoolWithTag(Dx, TAG_GDITEXT);
}
DC_UnlockDc( dc ); DC_UnlockDc( dc );
return TRUE; return TRUE;
@ -3692,19 +3643,132 @@ fail:
BRUSHOBJ_UnlockBrush(BrushFg); BRUSHOBJ_UnlockBrush(BrushFg);
NtGdiDeleteObject(hBrushFg); NtGdiDeleteObject(hBrushFg);
} }
if (NULL != SafeString)
{
ExFreePoolWithTag((void*)SafeString, TAG_GDITEXT);
}
if (NULL != Dx)
{
ExFreePoolWithTag(Dx, TAG_GDITEXT);
}
DC_UnlockDc(dc); DC_UnlockDc(dc);
return FALSE; 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 * @implemented
*/ */