https://git.reactos.org/?p=reactos.git;a=commitdiff;h=d57f7becc3f3204080086…
commit d57f7becc3f320408008649fa21c86926d9d16b6
Author: James Tabor <james.tabor(a)reactos.org>
AuthorDate: Fri Mar 8 22:21:41 2019 -0600
Commit: James Tabor <james.tabor(a)reactos.org>
CommitDate: Fri Mar 8 22:21:41 2019 -0600
[Win32SS] Add TextOut to GDI Batch
Add fix ups to PolyPatBlt and freetype.
TextOut supports 580 characters w/o Dx and Dx at a max of 193 characters
with Dx*1, both if offset is 0.
Noticed a lot of over drawing with start menu from ComCtl32 SB_SETTEXT
going through User32 DrawText/Worker ExtTextOutW. Explain why it might
be slowing down.
If issues arise, commenting out lines in win32ss/include/gdi32p.h can
help.
Example:
else if (Cmd == GdiBCTextOut) cjSize = 0;//sizeof(GDIBSTEXTOUT); <----
this one most of all.
else if (Cmd == GdiBCExtTextOut) cjSize = 0;//sizeof(GDIBSEXTTEXTOUT);
Test results:
https://reactos.org/testman/compare.php?ids=66260,66262
---
win32ss/gdi/gdi32/include/gdi32p.h | 4 +-
win32ss/gdi/gdi32/objects/painting.c | 11 ++-
win32ss/gdi/gdi32/objects/text.c | 97 ++++++++++++++++++++++
win32ss/gdi/ntgdi/freetype.c | 2 +-
win32ss/gdi/ntgdi/gdibatch.c | 155 +++++++++++++++++++++++++++++++----
win32ss/include/ntgdityp.h | 10 ++-
6 files changed, 255 insertions(+), 24 deletions(-)
diff --git a/win32ss/gdi/gdi32/include/gdi32p.h b/win32ss/gdi/gdi32/include/gdi32p.h
index 67d3a68dbf..f0b4cb46d9 100644
--- a/win32ss/gdi/gdi32/include/gdi32p.h
+++ b/win32ss/gdi/gdi32/include/gdi32p.h
@@ -390,8 +390,8 @@ GdiAllocBatchCommand(
/* Get the size of the entry */
if (Cmd == GdiBCPatBlt) cjSize = sizeof(GDIBSPATBLT);
else if (Cmd == GdiBCPolyPatBlt) cjSize = sizeof(GDIBSPPATBLT);
- else if (Cmd == GdiBCTextOut) cjSize = 0;
- else if (Cmd == GdiBCExtTextOut) cjSize = 0;
+ else if (Cmd == GdiBCTextOut) cjSize = sizeof(GDIBSTEXTOUT);
+ else if (Cmd == GdiBCExtTextOut) cjSize = sizeof(GDIBSEXTTEXTOUT);
else if (Cmd == GdiBCSetBrushOrg) cjSize = sizeof(GDIBSSETBRHORG);
else if (Cmd == GdiBCExtSelClipRgn) cjSize = 0;
else if (Cmd == GdiBCSelObj) cjSize = sizeof(GDIBSOBJECT);
diff --git a/win32ss/gdi/gdi32/objects/painting.c b/win32ss/gdi/gdi32/objects/painting.c
index efc987e6cb..8fc0d645c3 100644
--- a/win32ss/gdi/gdi32/objects/painting.c
+++ b/win32ss/gdi/gdi32/objects/painting.c
@@ -548,7 +548,8 @@ PolyPatBlt(
pgO = GdiAllocBatchCommand(hdc, GdiBCPolyPatBlt);
if (pgO)
{
- USHORT cjSize = sizeof(GDIBSPPATBLT) + (nCount-1) * sizeof(PATRECT);
+ USHORT cjSize = 0;
+ if (nCount > 1) cjSize = (nCount-1) * sizeof(PATRECT);
if ((pTeb->GdiTebBatch.Offset + cjSize) <= GDIBATCHBUFSIZE)
{
@@ -563,10 +564,14 @@ PolyPatBlt(
pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
pgO->ulBrushClr = pdcattr->ulBrushClr;
RtlCopyMemory(pgO->pRect, pPoly, nCount * sizeof(PATRECT));
- // Recompute offset, remember one is already accounted for in the
structure.
- pTeb->GdiTebBatch.Offset += (nCount-1) * sizeof(PATRECT);
+ // Recompute offset and return size, remember one is already accounted
for in the structure.
+ pTeb->GdiTebBatch.Offset += cjSize;
+ ((PGDIBATCHHDR)pgO)->Size += cjSize;
return TRUE;
}
+ // Reset offset and count then fall through
+ pTeb->GdiTebBatch.Offset -= sizeof(GDIBSPPATBLT);
+ pTeb->GdiBatchCount--;
}
}
return NtGdiPolyPatBlt(hdc, dwRop, pPoly, nCount, dwMode);
diff --git a/win32ss/gdi/gdi32/objects/text.c b/win32ss/gdi/gdi32/objects/text.c
index 1242020639..9ff4fde9df 100644
--- a/win32ss/gdi/gdi32/objects/text.c
+++ b/win32ss/gdi/gdi32/objects/text.c
@@ -488,6 +488,8 @@ ExtTextOutW(
_In_ UINT cwc,
_In_reads_opt_(cwc) const INT *lpDx)
{
+ PDC_ATTR pdcattr;
+
HANDLE_METADC(BOOL,
ExtTextOut,
FALSE,
@@ -506,6 +508,101 @@ ExtTextOutW(
return LpkExtTextOut(hdc, x, y, fuOptions, lprc, lpString, cwc , lpDx, 0);
}
+ /* Get the DC attribute */
+ pdcattr = GdiGetDcAttr(hdc);
+ if ( pdcattr &&
+ !(pdcattr->ulDirty_ & DC_DIBSECTION) &&
+ !(pdcattr->lTextAlign & TA_UPDATECP))
+ {
+ if ( lprc && !cwc )
+ {
+ if ( fuOptions & ETO_OPAQUE )
+ {
+ PGDIBSEXTTEXTOUT pgO;
+
+ pgO = GdiAllocBatchCommand(hdc, GdiBCExtTextOut);
+ if (pgO)
+ {
+ pgO->Count = cwc;
+ pgO->Rect = *lprc;
+ pgO->Options = fuOptions;
+ /* Snapshot attribute */
+ pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
+ pgO->ptlViewportOrg = pdcattr->ptlViewportOrg;
+ return TRUE;
+ }
+ }
+ else // Do nothing, old explorer pops this off.
+ {
+ DPRINT1("GdiBCExtTextOut nothing\n");
+ return TRUE;
+ }
+ } // Max 580 wchars, if offset 0
+ else if ( cwc <= ((GDIBATCHBUFSIZE - sizeof(GDIBSTEXTOUT)) / sizeof(WCHAR)) )
+ {
+ PGDIBSTEXTOUT pgO;
+ PTEB pTeb = NtCurrentTeb();
+
+ pgO = GdiAllocBatchCommand(hdc, GdiBCTextOut);
+ if (pgO)
+ {
+ USHORT cjSize = 0;
+ ULONG DxSize = 0;
+
+ if (cwc > 2) cjSize = (cwc * sizeof(WCHAR)) - sizeof(pgO->String);
+
+ /* Calculate buffer size for string and Dx values */
+ if (lpDx)
+ {
+ /* If ETO_PDY is specified, we have pairs of INTs */
+ DxSize = (cwc * sizeof(INT)) * (fuOptions & ETO_PDY ? 2 : 1);
+ cjSize += DxSize;
+ // The structure buffer holds 4 bytes. Store Dx data then string.
+ // Result one wchar -> Buf[ Dx ]Str[wC], [4][2][X] one extra
unused wchar
+ // to assure alignment of 4.
+ }
+
+ if ((pTeb->GdiTebBatch.Offset + cjSize ) <= GDIBATCHBUFSIZE)
+ {
+ pgO->cbCount = cwc;
+ pgO->x = x;
+ pgO->y = y;
+ pgO->Options = fuOptions;
+ pgO->iCS_CP = 0;
+
+ if (lprc) pgO->Rect = *lprc;
+ else
+ {
+ pgO->Options |= GDIBS_NORECT; // Tell the other side lprc is
nill.
+ }
+
+ /* Snapshot attributes */
+ pgO->crForegroundClr = pdcattr->crForegroundClr;
+ pgO->crBackgroundClr = pdcattr->crBackgroundClr;
+ pgO->ulForegroundClr = pdcattr->ulForegroundClr;
+ pgO->ulBackgroundClr = pdcattr->ulBackgroundClr;
+ pgO->lBkMode = pdcattr->lBkMode == OPAQUE ? OPAQUE :
TRANSPARENT;
+ pgO->hlfntNew = pdcattr->hlfntNew;
+ pgO->flTextAlign = pdcattr->flTextAlign;
+ pgO->ptlViewportOrg = pdcattr->ptlViewportOrg;
+
+ pgO->Size = DxSize; // of lpDx then string after.
+ /* Put the Dx before the String to assure alignment of 4 */
+ if (lpDx) RtlCopyMemory( &pgO->Buffer, lpDx, DxSize);
+
+ if (cwc) RtlCopyMemory( &pgO->String[DxSize/sizeof(WCHAR)],
lpString, cwc * sizeof(WCHAR));
+
+ // Recompute offset and return size
+ pTeb->GdiTebBatch.Offset += cjSize;
+ ((PGDIBATCHHDR)pgO)->Size += cjSize;
+ return TRUE;
+ }
+ // Reset offset and count then fall through
+ pTeb->GdiTebBatch.Offset -= sizeof(GDIBSTEXTOUT);
+ pTeb->GdiBatchCount--;
+ }
+ }
+ }
return NtGdiExtTextOutW(hdc,
x,
y,
diff --git a/win32ss/gdi/ntgdi/freetype.c b/win32ss/gdi/ntgdi/freetype.c
index 197304d469..7005057a07 100644
--- a/win32ss/gdi/ntgdi/freetype.c
+++ b/win32ss/gdi/ntgdi/freetype.c
@@ -5814,7 +5814,7 @@ IntExtTextOutW(
if ((fuOptions & ETO_OPAQUE) && (dc->pdcattr->ulDirty_ &
DIRTY_BACKGROUND))
DC_vUpdateBackgroundBrush(dc) ;
- if(dc->pdcattr->ulDirty_ & DIRTY_TEXT)
+ if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
DC_vUpdateTextBrush(dc) ;
thickness = 1;
diff --git a/win32ss/gdi/ntgdi/gdibatch.c b/win32ss/gdi/ntgdi/gdibatch.c
index 3c7d6c2ad0..13d6ad9088 100644
--- a/win32ss/gdi/ntgdi/gdibatch.c
+++ b/win32ss/gdi/ntgdi/gdibatch.c
@@ -5,6 +5,8 @@
#include <debug.h>
BOOL FASTCALL IntPatBlt( PDC,INT,INT,INT,INT,DWORD,PEBRUSHOBJ);
+BOOL APIENTRY IntExtTextOutW(IN PDC,IN INT,IN INT,IN UINT,IN OPTIONAL PRECTL,IN
LPCWSTR,IN INT,IN OPTIONAL LPINT,IN DWORD);
+
//
// Gdi Batch Flush support functions.
@@ -40,7 +42,7 @@ DoDeviceSync( SURFOBJ *Surface, PRECTL Rect, FLONG fl)
VOID
FASTCALL
-SynchonizeDriver(FLONG Flags)
+SynchronizeDriver(FLONG Flags)
{
SURFOBJ *SurfObj;
//PPDEVOBJ Device;
@@ -130,7 +132,7 @@ GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
dc->pdcattr->ulForegroundClr = pgDPB->ulForegroundClr;
dc->pdcattr->ulBackgroundClr = pgDPB->ulBackgroundClr;
dc->pdcattr->ulBrushClr = pgDPB->ulBrushClr;
- // Process dirty attributes if any
+ // Process dirty attributes if any.
if (dc->pdcattr->ulDirty_ & (DIRTY_FILL | DC_BRUSH_DIRTY))
DC_vUpdateFillBrush(dc);
if (dc->pdcattr->ulDirty_ & DIRTY_TEXT)
@@ -157,7 +159,7 @@ GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
EBRUSHOBJ eboFill;
PBRUSH pbrush;
PPATRECT pRects;
- INT cRects, i;
+ INT i;
DWORD dwRop, flags;
COLORREF crColor, crBkColor, crBrushClr;
ULONG ulForegroundClr, ulBackgroundClr, ulBrushClr;
@@ -200,10 +202,9 @@ GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
DC_vUpdateBackgroundBrush(dc);
DPRINT1("GdiBCPolyPatBlt Testing\n");
- pRects = pgDPB->pRect;
- cRects = pgDPB->Count;
+ pRects = &pgDPB->pRect[0];
- for (i = 0; i < cRects; i++)
+ for (i = 0; i < pgDPB->Count; i++)
{
pbrush = BRUSH_ShareLockBrush(pRects->hBrush);
@@ -238,21 +239,141 @@ GdiFlushUserBatch(PDC dc, PGDIBATCHHDR pHdr)
dc->pdcattr->ulBrushClr = ulBrushClr;
dc->pdcattr->ulDirty_ |= flags;
break;
- }
+ }
+
case GdiBCTextOut:
+ {
+ PGDIBSTEXTOUT pgO;
+ COLORREF crColor = -1, crBkColor;
+ ULONG ulForegroundClr, ulBackgroundClr;
+ DWORD flags = 0, saveflags;
+ FLONG flTextAlign = -1;
+ HANDLE hlfntNew;
+ PRECTL lprc;
+ USHORT jBkMode;
+ LONG lBkMode;
+ if (!dc) break;
+ pgO = (PGDIBSTEXTOUT) pHdr;
+
+ // Save current attributes, flags and Set the attribute snapshots
+ saveflags = dc->pdcattr->ulDirty_ &
(DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_TEXT|DIRTY_FILL|DC_BRUSH_DIRTY|DIRTY_CHARSET);
+
+ // In this instance check for differences and set the appropriate dirty flags.
+ if ( dc->pdcattr->crForegroundClr != pgO->crForegroundClr)
+ {
+ crColor = dc->pdcattr->crForegroundClr;
+ dc->pdcattr->crForegroundClr = pgO->crForegroundClr;
+ ulForegroundClr = dc->pdcattr->ulForegroundClr;
+ dc->pdcattr->ulForegroundClr = pgO->ulForegroundClr;
+ flags |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT);
+ }
+ if (dc->pdcattr->crBackgroundClr != pgO->crBackgroundClr)
+ {
+ crBkColor = dc->pdcattr->ulBackgroundClr;
+ dc->pdcattr->crBackgroundClr = pgO->crBackgroundClr;
+ ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
+ dc->pdcattr->ulBackgroundClr = pgO->ulBackgroundClr;
+ flags |= (DIRTY_FILL|DIRTY_LINE|DIRTY_TEXT|DIRTY_BACKGROUND);
+ }
+ if (dc->pdcattr->flTextAlign != pgO->flTextAlign)
+ {
+ flTextAlign = dc->pdcattr->flTextAlign;
+ dc->pdcattr->flTextAlign = pgO->flTextAlign;
+ }
+ if (dc->pdcattr->hlfntNew != pgO->hlfntNew)
+ {
+ hlfntNew = dc->pdcattr->hlfntNew;
+ dc->pdcattr->hlfntNew = pgO->hlfntNew;
+ dc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
+ flags |= DIRTY_CHARSET;
+ }
+
+ dc->pdcattr->ulDirty_ |= flags;
+
+ jBkMode = dc->pdcattr->jBkMode;
+ dc->pdcattr->jBkMode = pgO->lBkMode;
+ lBkMode = dc->pdcattr->lBkMode;
+ dc->pdcattr->lBkMode = pgO->lBkMode;
+
+ lprc = (pgO->Options & GDIBS_NORECT) ? NULL : &pgO->Rect;
+ pgO->Options &= ~GDIBS_NORECT;
+
+ IntExtTextOutW( dc,
+ pgO->x,
+ pgO->y,
+ pgO->Options,
+ lprc,
+ (LPCWSTR)&pgO->String[pgO->Size/sizeof(WCHAR)],
+ pgO->cbCount,
+ pgO->Size ? (LPINT)&pgO->Buffer : NULL,
+ pgO->iCS_CP );
+
+ // Restore attributes and flags
+ dc->pdcattr->jBkMode = jBkMode;
+ dc->pdcattr->lBkMode = lBkMode;
+
+ if (flags & DIRTY_TEXT && crColor != -1)
+ {
+ dc->pdcattr->crForegroundClr = crColor;
+ dc->pdcattr->ulForegroundClr = ulForegroundClr;
+ }
+ if (flags & DIRTY_BACKGROUND)
+ {
+ dc->pdcattr->crBackgroundClr = crBkColor;
+ dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
+ }
+ if (flTextAlign != -1)
+ {
+ dc->pdcattr->flTextAlign = flTextAlign;
+ }
+
+ if (flags & DIRTY_CHARSET)
+ {
+ dc->pdcattr->hlfntNew = hlfntNew;
+ dc->pdcattr->ulDirty_ &= ~SLOW_WIDTHS;
+ }
+ dc->pdcattr->ulDirty_ |= saveflags | flags;
break;
+ }
case GdiBCExtTextOut:
{
- //GreExtTextOutW( hDC,
- // XStart,
- // YStart,
- // fuOptions,
- // &SafeRect,
- // SafeString,
- // Count,
- // SafeDx,
- // dwCodePage );
+ PGDIBSEXTTEXTOUT pgO;
+ COLORREF crBkColor;
+ ULONG ulBackgroundClr;
+ DWORD flags = 0, saveflags;
+ if (!dc) break;
+ pgO = (PGDIBSEXTTEXTOUT) pHdr;
+
+ saveflags = dc->pdcattr->ulDirty_ &
(DIRTY_BACKGROUND|DIRTY_TEXT|DIRTY_FILL|DC_BRUSH_DIRTY|DIRTY_CHARSET);
+
+ if (dc->pdcattr->crBackgroundClr != pgO->ulBackgroundClr)
+ {
+ crBkColor = dc->pdcattr->crBackgroundClr;
+ ulBackgroundClr = dc->pdcattr->ulBackgroundClr;
+ dc->pdcattr->crBackgroundClr = pgO->ulBackgroundClr;
+ dc->pdcattr->ulBackgroundClr = pgO->ulBackgroundClr;
+ flags |= (DIRTY_BACKGROUND|DIRTY_LINE|DIRTY_FILL);
+ }
+
+ dc->pdcattr->ulDirty_ |= flags;
+
+ IntExtTextOutW( dc,
+ 0,
+ 0,
+ pgO->Options,
+ &pgO->Rect,
+ NULL,
+ pgO->Count,
+ NULL,
+ 0 );
+
+ if (flags & DIRTY_BACKGROUND)
+ {
+ dc->pdcattr->crBackgroundClr = crBkColor;
+ dc->pdcattr->ulBackgroundClr = ulBackgroundClr;
+ }
+ dc->pdcattr->ulDirty_ |= saveflags | flags;
break;
}
@@ -308,7 +429,7 @@ APIENTRY
NtGdiFlush(
VOID)
{
- SynchonizeDriver(GCAPS2_SYNCFLUSH);
+ SynchronizeDriver(GCAPS2_SYNCFLUSH);
return STATUS_SUCCESS;
}
diff --git a/win32ss/include/ntgdityp.h b/win32ss/include/ntgdityp.h
index 4bf8aa92fa..99eed15cc9 100644
--- a/win32ss/include/ntgdityp.h
+++ b/win32ss/include/ntgdityp.h
@@ -495,12 +495,17 @@ typedef struct _GDIBSPPATBLT
PATRECT pRect[1]; // POLYPATBLT
} GDIBSPPATBLT, *PGDIBSPPATBLT;
+//
+// Both ExtSelectClipRgn and TextOut pass a nill RECT.
+//
+#define GDIBS_NORECT 0x80000000
+
typedef struct _GDIBSTEXTOUT
{
GDIBATCHHDR gbHdr;
COLORREF crForegroundClr;
COLORREF crBackgroundClr;
- LONG lmBkMode;
+ LONG lBkMode;
ULONG ulForegroundClr;
ULONG ulBackgroundClr;
int x;
@@ -513,7 +518,10 @@ typedef struct _GDIBSTEXTOUT
HANDLE hlfntNew;
FLONG flTextAlign;
POINTL ptlViewportOrg;
+ union {
WCHAR String[2];
+ ULONG Buffer[1];
+ };
} GDIBSTEXTOUT, *PGDIBSTEXTOUT;
typedef struct _GDIBSEXTTEXTOUT