Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

808 lines
21 KiB

/**************************************************************************\
*
* Copyright (c) 1999-2000 Microsoft Corporation
*
* Abstract:
*
* Contains all the 32-bit scan-buffer routines for the default supported
* bitmap formats.
*
* Revision History:
*
* 12/08/1998 andrewgo
* Created it.
*
\**************************************************************************/
#include "precomp.hpp"
/**************************************************************************\
*
* Function Description:
*
* Scan class helper function that SrcOver alpha blends two ARGB buffers.
*
* Arguments:
*
* [IN] driver - Driver interface
* [IN] context - Drawing context
* [IN] surface - Destination surface
* [OUT] nextBuffer - Points to a EpScan:: type function to return
* the next buffer
* [IN] scanType - The type of scan.
* [IN] pixFmtGeneral - the input pixel format for the color data,
* in the "Blend" and "CT" scan types.
* [IN] pixFmtOpaque - the input pixel format for the color data,
* in the "Opaque" scan type.
* [IN] solidColor - the solid fill color for "*SolidFill" scan types.
*
* Return Value:
*
* FALSE if all the necessary buffers couldn't be created
*
* History:
*
* 12/04/1998 andrewgo
* Created it.
*
\**************************************************************************/
BOOL
EpScanEngine::Start(
DpDriver *driver,
DpContext *context,
DpBitmap *surface,
NEXTBUFFERFUNCTION *nextBuffer,
EpScanType scanType,
PixelFormatID pixFmtGeneral,
PixelFormatID pixFmtOpaque,
ARGB solidColor
)
{
// Inherit initialization
EpScan::Start(
driver,
context,
surface,
nextBuffer,
scanType,
pixFmtGeneral,
pixFmtOpaque,
solidColor
);
// DIBSection destinations don't have an alpha channel
ASSERT(surface->SurfaceTransparency == TransparencyNoAlpha);
Surface = surface;
if(surface->Type == DpBitmap::D3D)
{
DDSURFACEDESC2 ddsd;
memset(&ddsd, 0, sizeof(ddsd));
ddsd.dwSize = sizeof(ddsd);
HRESULT err;
err = Surface->DdrawSurface7->Lock(NULL, &ddsd, DDLOCK_WAIT, NULL);
if(err != DD_OK)
return(FALSE);
Surface->Bits = ddsd.lpSurface;
Surface->Delta = ddsd.lPitch;
}
Dst = NULL;
Stride = surface->Delta;
Bits = (BYTE*) surface->Bits;
PixelSize = GetPixelFormatSize(surface->PixelFormat) >> 3;
// [agodfrey] This Scan class is only designed for use with formats
// which are supported natively, so it ignores the DIBSection and
// corresponding PixelFormatID returned by GetScanBuffers.
PixelFormatID dstFormat = surface->PixelFormat;
ASSERTMSG(dstFormat != PIXFMT_UNDEFINED,(("Unexpected surface format")));
*nextBuffer = (NEXTBUFFERFUNCTION) EpScanEngine::NextBuffer;
if (!driver->Device->GetScanBuffers(
surface->Width,
NULL,
NULL,
NULL,
Buffers)
)
{
return NULL;
}
// initialize the AlphaBlenders.
BlenderConfig[0].Initialize(
dstFormat,
context,
context->Palette,
Buffers,
TRUE,
FALSE,
solidColor
);
BlenderConfig[1].Initialize(
dstFormat,
context,
context->Palette,
Buffers,
TRUE,
FALSE,
solidColor
);
return TRUE;
}
/**************************************************************************\
*
* Function Description:
*
* Flushes the previous buffer (if there was), and returns the
* next buffer for doing a SrcOver blend.
*
* Arguments:
*
* [IN] x - Destination pixel coordinate in destination surface
* [IN] y - ""
* [IN] width - Number of pixels needed for the next buffer (can be 0)
* [IN] updateWidth - Number of pixels to update in the current buffer
*
* Return Value:
*
* Points to the resulting scan buffer
*
* History:
*
* 12/04/1998 andrewgo
* Created it.
*
\**************************************************************************/
VOID *EpScanEngine::NextBuffer(
INT x,
INT y,
INT newWidth,
INT updateWidth,
INT blenderNum
)
{
if (updateWidth != 0)
{
// Make sure we're not drawing outside the bounds of the surface.
// If these ASSERTs are triggered, the clipping code is broken.
// This class absolutely must have input clipped to the surface
// bounds otherwise we will AV writing on bad memory, or corrupt some
// other data structure.
ASSERT( CurrentX >= 0 );
ASSERT( CurrentY >= 0 );
ASSERT( CurrentX + updateWidth <= Surface->Width );
ASSERT( CurrentY < Surface->Height );
// Handle the previous scanline segment.
BlenderConfig[LastBlenderNum].AlphaBlender.Blend(
Dst,
Buffers[3],
updateWidth,
CurrentX - DitherOriginX,
CurrentY - DitherOriginY,
static_cast<BYTE *>(Buffers[4])
);
}
// Now move on to processing this scanline segment.
// The actual blend will be done on the next call through this routine
// when we know the width and the bits have been set into the buffer
// we're returning.
LastBlenderNum = blenderNum;
// Remember the x and y for the brush offset (halftone & dither).
CurrentX = x;
CurrentY = y;
// Calculate the destination for the scan:
Dst = Bits + (y * Stride) + (x * PixelSize);
return (Buffers[3]);
}
/**************************************************************************\
*
* Function Description:
*
* Denotes the end of the use of the scan buffer.
*
* Arguments:
*
* NONE
*
* Return Value:
*
* NONE
*
* History:
*
* 12/04/1998 andrewgo
* Created it.
*
\**************************************************************************/
VOID
EpScanEngine::End(
INT updateWidth
)
{
// Flush the last scan:
NextBuffer(0, 0, 0, updateWidth, 0);
if(Surface->Type == DpBitmap::D3D)
{
Surface->DdrawSurface7->Unlock(NULL);
Surface->Bits = NULL;
Surface->Delta = 0;
}
}
/**************************************************************************\
*
* Function Description:
*
* Scan class helper function that SrcOver alpha blends two ARGB buffers.
*
* Arguments:
*
* [IN] driver - Driver interface
* [IN] context - Drawing context
* [IN] surface - Destination surface
* [OUT] nextBuffer - Points to a EpScan:: type function to return
* the next buffer
* [IN] scanType - The type of scan.
* [IN] pixFmtGeneral - the input pixel format for the color data,
* in the "Blend" and "CT" scan types.
* [IN] pixFmtOpaque - the input pixel format for the color data,
* in the "Opaque" scan type.
* [IN] solidColor - the solid fill color for "*SolidFill" scan types.
*
* Return Value:
*
* FALSE if all the necessary buffers couldn't be created
*
* History:
*
* 09/22/1999 gilmanw
* Created it using EpScanEngine as a template
*
\**************************************************************************/
BOOL
EpScanBitmap::Start(
DpDriver *driver,
DpContext *context,
DpBitmap *surface,
NEXTBUFFERFUNCTION *nextBuffer,
EpScanType scanType,
PixelFormatID pixFmtGeneral,
PixelFormatID pixFmtOpaque,
ARGB solidColor
)
{
// Inherit initialization
EpScan::Start(
driver,
context,
surface,
nextBuffer,
scanType,
pixFmtGeneral,
pixFmtOpaque,
solidColor
);
GpStatus status;
BOOL writeOnly = FALSE;
GpCompositingMode compositingMode = context->CompositingMode;
Surface = surface;
if (scanType == EpScanTypeOpaque)
{
writeOnly = TRUE;
}
else
{
// Work out if this operation will write transparent pixels (alpha != 1)
// into the surface for the first time.
switch (surface->SurfaceTransparency)
{
case TransparencyUnknown:
case TransparencyNoAlpha:
break;
case TransparencyOpaque:
// If the surface contains only opaque pixels, the SourceOver
// operation will produce only opaque pixels. So for SourceOver,
// a transition from TransparencyOpaque to TransparencyUnknown is
// impossible.
if ( (scanType == EpScanTypeBlend)
&& (compositingMode == CompositingModeSourceOver))
{
break;
}
// Else, fall through:
case TransparencySimple:
// !!![agodfrey]: Theoretically, if the destination pixel format
// is 1555, we could set it to 'TransparencySimple' here.
surface->SurfaceTransparency = TransparencyUnknown;
Bitmap->SetTransparencyHint(surface->SurfaceTransparency);
break;
default:
RIP(("Unrecognized surface transparency"));
break;
}
}
// Pick the appropriate blending function based on the format of the
// bitmap.
ASSERTMSG(Bitmap != NULL, ("EpScanBitmap not initialized"));
PixelFormatID dstFormat;
if (FAILED(Bitmap->GetPixelFormatID(&dstFormat)))
return FALSE;
switch (dstFormat)
{
case PIXFMT_16BPP_RGB555:
case PIXFMT_16BPP_RGB565:
case PIXFMT_24BPP_RGB:
case PIXFMT_32BPP_RGB:
case PIXFMT_32BPP_ARGB:
case PIXFMT_24BPP_BGR:
case PIXFMT_32BPP_PARGB:
// Since we're doing just one lock of the whole image, we have
// to allow read-modify-write since only a portion of the bitmap
// may be written.
BitmapLockFlags = (IMGLOCK_WRITE | IMGLOCK_READ);
*nextBuffer = (NEXTBUFFERFUNCTION) EpScanBitmap::NextBufferNative;
EndFunc = (SCANENDFUNCTION) EpScanBitmap::EndNative;
status = Bitmap->LockBits(NULL, BitmapLockFlags,
dstFormat, &LockedBitmapData);
if (status == Ok)
{
CurrentScan = NULL;
PixelSize = GetPixelFormatSize(dstFormat) >> 3;
break;
}
// else fall into the generic case and use 32bpp ARGB
default:
// When locking a scanline at a time and the mode is SourceCopy,
// the read is unnecessary.
if (writeOnly)
{
BitmapLockFlags = IMGLOCK_WRITE;
}
else
{
BitmapLockFlags = (IMGLOCK_WRITE | IMGLOCK_READ);
}
dstFormat = PIXFMT_32BPP_ARGB;
*nextBuffer = (NEXTBUFFERFUNCTION) EpScanBitmap::NextBuffer32ARGB;
EndFunc = (SCANENDFUNCTION) EpScanBitmap::End32ARGB;
break;
}
// Allocate the temporary buffers.
// Buffers[3] will be given to the caller to be used to pass scans to us.
// Buffers[4] will be used for ClearType data.
if (Buffers[0] == NULL)
{
Size bitmapSize;
status = Bitmap->GetSize(&bitmapSize);
if (status == Ok)
{
Width = bitmapSize.Width;
Height = bitmapSize.Height;
Buffers[0] = GpMalloc(sizeof(ARGB64) * bitmapSize.Width * 5);
if (Buffers[0])
{
int i;
for (i=1;i<5;i++)
{
Buffers[i] = static_cast<BYTE *>(Buffers[i-1]) +
sizeof(ARGB64) * bitmapSize.Width;
}
}
else
{
ONCE(WARNING(("(once) Buffer allocation failed")));
return FALSE;
}
}
else
{
ONCE(WARNING(("(once) GetSize failed")));
return FALSE;
}
}
// initialize the AlphaBlenders.
BlenderConfig[0].Initialize(
dstFormat,
context,
context->Palette,
Buffers,
TRUE,
FALSE,
solidColor
);
BlenderConfig[1].Initialize(
dstFormat,
context,
context->Palette,
Buffers,
TRUE,
FALSE,
solidColor
);
return TRUE;
}
/**************************************************************************\
*
* Function Description:
*
* NextBuffer function used when we have low-level functions that match
* native format of the GpBitmap and we can read/write directly into the
* bitmap bits.
*
* Flushes the previous buffer (if there was), and returns the
* next buffer for doing a SrcOver blend.
*
* Arguments:
*
* [IN] x - Destination pixel coordinate in destination surface
* [IN] y - ""
* [IN] width - Number of pixels needed for the next buffer (can be 0)
* [IN] updateWidth - Number of pixels to update in the current buffer
*
* Return Value:
*
* Points to the resulting scan buffer
*
* History:
*
* 09/22/1999 gilmanw
* Created it using EpScanEngine as a template
*
\**************************************************************************/
VOID *EpScanBitmap::NextBufferNative(
INT x,
INT y,
INT newWidth,
INT updateWidth,
INT blenderNum
)
{
// Flush the previous buffer:
if ((updateWidth != 0) && (CurrentScan != NULL))
{
ASSERTMSG(Buffers[0] != NULL, ("no buffers"));
ASSERTMSG(updateWidth <= Width, ("updateWidth too big"));
// Handle the previous scanline segment.
BlenderConfig[LastBlenderNum].AlphaBlender.Blend(
CurrentScan,
Buffers[3],
updateWidth,
CurrentX - DitherOriginX,
CurrentY - DitherOriginY,
static_cast<BYTE *>(Buffers[4])
);
}
// Now move on to processing this scanline segment.
// The actual blend will be done on the next call through this routine
// when we know the width and the bits have been set into the buffer
// we're returning.
LastBlenderNum = blenderNum;
// Remember the x and y for the brush offset (halftone & dither).
CurrentX = x;
CurrentY = y;
// Get the next destination scan:
CurrentScan = NULL;
// Check that surface clipping has been done properly.
if((y >= 0) && (y < Height) && (x >= 0) && (x < Width))
{
// Clip against the right edge of the bitmap. newWidth is an upper
// bound only - not guaranteed to be clipped.
if (newWidth > (Width - x))
{
newWidth = Width - x;
}
if (newWidth > 0)
{
CurrentScan = static_cast<VOID *>
(static_cast<BYTE *>(LockedBitmapData.Scan0)
+ (y * LockedBitmapData.Stride)
+ (x * PixelSize));
}
}
else
{
// If we hit this, we're hosed. The OutputSpan routines in the
// DpOutputSpan classes are built assuming correct clipping (at least
// to the data buffer) and hence, if we hit this assert, we're going
// to crash horibly later writing all over memory when we start writing
// outside of the bounds of the destination allocation.
// if you're here, someone broke clipping or the dpi computation.
ASSERTMSG(!((y >= 0) && (y < Height) && (x >= 0) && (x < Width)),
(("EpScanBitmap::NextBufferNative: x, y out of bounds")));
}
return (Buffers[3]);
}
/**************************************************************************\
*
* Function Description:
*
* Generic NextBuffer function that accesses GpBitmap bits
* via GpBitmap::Lock/UnlockBits for each scan.
*
* Flushes the previous buffer (if there was), and returns the
* next buffer for doing a SrcOver blend.
*
* Arguments:
*
* [IN] x - Destination pixel coordinate in destination surface
* [IN] y - ""
* [IN] width - Number of pixels needed for the next buffer (can be 0)
* [IN] updateWidth - Number of pixels to update in the current buffer
*
* Return Value:
*
* Points to the resulting scan buffer
*
* History:
*
* 09/22/1999 gilmanw
* Created it using EpScanEngine as a template
*
\**************************************************************************/
VOID *EpScanBitmap::NextBuffer32ARGB(
INT x,
INT y,
INT newWidth,
INT updateWidth,
INT blenderNum
)
{
// Flush the previous buffer:
if (updateWidth != 0 && BitmapLocked)
{
ASSERTMSG(Buffers[0] != NULL, ("no buffers"));
ASSERTMSG(LockedBitmapData.Scan0 != NULL, ("no previous buffer"));
// Handle the previous scanline segment.
BlenderConfig[LastBlenderNum].AlphaBlender.Blend(
LockedBitmapData.Scan0,
Buffers[3],
updateWidth,
CurrentX - DitherOriginX,
CurrentY - DitherOriginY,
static_cast<BYTE *>(Buffers[4])
);
Bitmap->UnlockBits(&LockedBitmapData);
BitmapLocked = FALSE;
}
else if (BitmapLocked)
{
EpScanBitmap::Flush();
}
// Now move on to processing this scanline segment.
// The actual blend will be done on the next call through this routine
// when we know the width and the bits have been set into the buffer
// we're returning.
LastBlenderNum = blenderNum;
// Remember the x and y for the brush offset (halftone & dither).
CurrentX = x;
CurrentY = y;
// Lock the next destination:
// Check that surface clipping has been done properly.
if((y >= 0) && (y < Height) && (x >= 0) && (x < Width))
{
// Clip against the right edge of the bitmap. newWidth is an upper
// bound only - not guaranteed to be clipped. LockBits needs it
// to be clipped.
if (newWidth > (Width - x))
{
newWidth = Width - x;
}
if (newWidth > 0)
{
GpRect nextRect(x, y, newWidth, 1);
GpStatus status = Bitmap->LockBits(
&nextRect,
BitmapLockFlags,
PixelFormat32bppARGB,
&LockedBitmapData
);
if (status == Ok)
BitmapLocked = TRUE;
}
}
else
{
// If we hit this, we're hosed. The OutputSpan routines in the
// DpOutputSpan classes are built assuming correct clipping (at least
// to the data buffer) and hence, if we hit this assert, we're going
// to crash horibly later writing all over memory when we start writing
// outside of the bounds of the destination allocation.
// if you're here, someone broke clipping or the dpi computation.
ASSERTMSG(!((y >= 0) && (y < Height) && (x >= 0) && (x < Width)),
(("EpScanBitmap::NextBufferNative: x, y out of bounds")));
}
return (Buffers[3]);
}
/**************************************************************************\
*
* Function Description:
*
* Denotes the end of the use of the scan buffer.
*
* Arguments:
*
* NONE
*
* Return Value:
*
* NONE
*
* History:
*
* 09/22/1999 gilmanw
* Created it using EpScanEngine as a template
*
\**************************************************************************/
VOID
EpScanBitmap::End32ARGB(
INT updateWidth
)
{
// Flush the last scan:
EpScanBitmap::NextBuffer32ARGB(0, 0, 0, updateWidth, 0);
}
VOID
EpScanBitmap::EndNative(
INT updateWidth
)
{
// Flush the last scan and release bitmap access:
EpScanBitmap::NextBufferNative(0, 0, 0, updateWidth, 0);
Bitmap->UnlockBits(&LockedBitmapData);
}
VOID
EpScanBitmap::End(
INT updateWidth
)
{
(this->*EndFunc)(updateWidth);
// Lock/UnlockBitmap has to be very aggressive about setting
// TransparancyUnknown in the GpBitmap since the caller could be
// doing anything to the alpha channel. However, the EpScanBitmap
// knows what it is doing, so the surface->SurfaceTransparency is
// more accurate.
Bitmap->SetTransparencyHint(Surface->SurfaceTransparency);
}
/**************************************************************************\
*
* Function Description:
*
* Flush any batched rendering and optionally wait for rendering to finish.
*
* Return Value:
*
* NONE
*
* History:
*
* 09/22/1999 gilmanw
* Created it using EpScanEngine as a template
*
\**************************************************************************/
VOID EpScanBitmap::Flush()
{
if (BitmapLocked && Bitmap)
{
Bitmap->UnlockBits(&LockedBitmapData);
BitmapLocked = FALSE;
}
}