https://git.reactos.org/?p=reactos.git;a=commitdiff;h=30886e74f232eb72952ba…
commit 30886e74f232eb72952ba47045acb49be5cf2ca3
Author: Jérôme Gardou <jerome.gardou(a)reactos.org>
AuthorDate: Wed Mar 31 15:02:20 2021 +0200
Commit: Jérôme Gardou <zefklop(a)users.noreply.github.com>
CommitDate: Wed Mar 31 16:39:57 2021 +0200
[WIN32K] Fix case when buffers overlap in 1BPP -> 1BPP DIB copy
Logic by Doug Lyons
CORE-17520
---
win32ss/gdi/dib/dib1bpp.c | 99 ++++++++++++++++++++++++++++++++++++++---------
1 file changed, 80 insertions(+), 19 deletions(-)
diff --git a/win32ss/gdi/dib/dib1bpp.c b/win32ss/gdi/dib/dib1bpp.c
index c1b33ad4182..0bc25777f0c 100644
--- a/win32ss/gdi/dib/dib1bpp.c
+++ b/win32ss/gdi/dib/dib1bpp.c
@@ -55,7 +55,7 @@ DIB_1BPP_VLine(SURFOBJ *SurfObj, LONG x, LONG y1, LONG y2, ULONG c)
}
static
-void
+BOOLEAN
DIB_1BPP_BitBltSrcCopy_From1BPP (
SURFOBJ* DestSurf,
SURFOBJ* SourceSurf,
@@ -66,34 +66,96 @@ DIB_1BPP_BitBltSrcCopy_From1BPP (
BOOLEAN bLeftToRight )
{
LONG Height = RECTL_lGetHeight(DestRect);
+ LONG Width = RECTL_lGetWidth(DestRect);
BOOLEAN XorBit = !!XLATEOBJ_iXlate(pxlo, 0);
+ BOOLEAN Overlap = FALSE;
/* Make sure this is as expected */
ASSERT(DestRect->left >= 0);
ASSERT(DestRect->top >= 0);
ASSERT(Height > 0);
- ASSERT(RECTL_lGetWidth(DestRect) > 0);
+ ASSERT(Width > 0);
- while (Height--)
+ /*
+ * Check if we need to allocate a buffer for our operation.
+ * NB: if we're not mirroring, we're doing a memmove-like operation, so this
is always fine.
+ */
+ if (bTopToBottom || bLeftToRight)
{
- LONG yDst = DestRect->top + Height;
- LONG ySrc = bTopToBottom ?
- SourcePoint->y + RECTL_lGetHeight(DestRect) - Height - 1
- : SourcePoint->y + Height;
- LONG Width = RECTL_lGetWidth(DestRect);
+ BYTE* DstStart = (BYTE*)DestSurf->pvScan0 + DestRect->top *
DestSurf->lDelta + DestRect->left / 8;
+ BYTE* DstEnd = (BYTE*)DestSurf->pvScan0 + (DestRect->bottom - 1) *
DestSurf->lDelta + (DestRect->right) / 8;
+ BYTE* SrcStart = (BYTE*)SourceSurf->pvScan0 + SourcePoint->y *
SourceSurf->lDelta + SourcePoint->x / 8;
+ BYTE* SrcEnd = (BYTE*)SourceSurf->pvScan0 + (SourcePoint->y + Height - 1) *
SourceSurf->lDelta + (SourcePoint->x + Width) / 8;
+
+ /* Beware of bitmaps with negative pitch! */
+ if (DstStart > DstEnd)
+ {
+ BYTE* tmp = DstStart;
+ DstStart = DstEnd;
+ DstEnd = tmp;
+ }
- while (Width--)
+ if (SrcStart > SrcEnd)
{
- LONG xDst = DestRect->left + Width;
- LONG xSrc = bLeftToRight ?
- SourcePoint->x + RECTL_lGetWidth(DestRect) - Width - 1
- : SourcePoint->x + Width;
- ULONG PixelPut = DIB_1BPP_GetPixel(SourceSurf, xSrc, ySrc);
- if (XorBit)
- PixelPut = !PixelPut;
- DIB_1BPP_PutPixel(DestSurf, xDst, yDst, PixelPut);
+ BYTE* tmp = SrcStart;
+ SrcStart = SrcEnd;
+ SrcEnd = tmp;
}
+
+ /* We allocate a new buffer when the two buffers overlap */
+ Overlap = ((SrcStart >= DstStart) && (SrcStart < DstEnd)) ||
((SrcEnd >= DstStart) && (SrcEnd < DstEnd));
}
+
+ if (!Overlap)
+ {
+ LONG y;
+ for (y = 0; y < Height; y++)
+ {
+ LONG ySrc = bTopToBottom ? SourcePoint->y + Height - y - 1 :
SourcePoint->y + y;
+ LONG x;
+
+ for(x = 0; x < Width; x++)
+ {
+ LONG xSrc = bLeftToRight ? SourcePoint->x + Width - x - 1 :
SourcePoint->x + x;
+ ULONG Pixel = DIB_1BPP_GetPixel(SourceSurf, xSrc, ySrc);
+ if (XorBit)
+ Pixel = !Pixel;
+ DIB_1BPP_PutPixel(DestSurf, DestRect->left + x, DestRect->top + y,
Pixel);
+ }
+ }
+ }
+ else
+ {
+ LONG y;
+ BYTE* PixBuf = ExAllocatePoolZero(PagedPool, Height * (ALIGN_UP_BY(Width, 8) /
8), TAG_DIB);
+ if (!PixBuf)
+ return FALSE;
+ for (y = 0; y < Height; y++)
+ {
+ BYTE* Row = PixBuf + y * ALIGN_UP_BY(Width, 8) / 8;
+ LONG ySrc = bTopToBottom ? SourcePoint->y + Height - y - 1 :
SourcePoint->y + y;
+ LONG x;
+
+ for (x = 0; x < Width; x++)
+ {
+ LONG xSrc = bLeftToRight ? SourcePoint->x + Width - x - 1 :
SourcePoint->x + x;
+ if ((!DIB_1BPP_GetPixel(SourceSurf, xSrc, ySrc)) == XorBit)
+ Row[x / 8] |= 1 << (x & 7);
+ }
+ }
+
+ for (y = 0; y < Height; y++)
+ {
+ BYTE* Row = PixBuf + y * ALIGN_UP_BY(Width, 8) / 8;
+ LONG x;
+ for (x = 0; x < Width; x++)
+ DIB_1BPP_PutPixel(DestSurf, DestRect->left + x, DestRect->top + y,
!!(Row[x/8] & (1 << (x&7))));
+ }
+
+ ExFreePoolWithTag(PixBuf, TAG_DIB);
+ }
+
+ return TRUE;
}
BOOLEAN
@@ -129,10 +191,9 @@ DIB_1BPP_BitBltSrcCopy(PBLTINFO BltInfo)
DPRINT("1BPP Case Selected with DestRect Width of '%d'.\n",
BltInfo->DestRect.right - BltInfo->DestRect.left);
- DIB_1BPP_BitBltSrcCopy_From1BPP ( BltInfo->DestSurface,
BltInfo->SourceSurface,
+ return DIB_1BPP_BitBltSrcCopy_From1BPP ( BltInfo->DestSurface,
BltInfo->SourceSurface,
BltInfo->XlateSourceToDest, &BltInfo->DestRect,
&BltInfo->SourcePoint,
bTopToBottom, bLeftToRight );
- break;
case BMF_4BPP:
DPRINT("4BPP Case Selected with DestRect Width of '%d'.\n",