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.
 
 
 
 
 
 

2477 lines
79 KiB

/******************************Module*Header*******************************\
* Module Name: drawstream.cxx
*
* All code related to handling draw streams except for multi-mon and
* sprite layer hooking.
*
* Created: 3-21-2001
* Author: Barton House [bhouse]
*
* Copyright (c) 1990-2001 Microsoft Corporation
\**************************************************************************/
#include "precomp.hxx"
#if defined(USE_NINEGRID_STATIC)
HSEMAPHORE gNineGridSem = 0;
#endif
/******************************Private*************************************\
* Nine Grid Code Follows
*
* A bunch of nine grid structures and code follow below. This code
* will be cleaned up and moved to its own file shortly.
*
* History:
*
* 3-18-2001 bhouse Created it
*
\**************************************************************************/
typedef struct _DNGSTRETCH
{
ULONG xStart;
ULONG xAccum;
ULONG xFrac;
ULONG xInt;
ULONG ulDestWidth;
ULONG ulSrcWidth;
int left;
int right;
} DNGSTRETCH;
typedef struct _DNGINTERNALDATA
{
int cxClipMin;
int cxClipMax;
ULONG* pvDestBits;
LONG lDestDelta;
int iDestWidth;
int iClipWidth;
ULONG* pvSrcBits;
LONG lSrcDelta;
int iSrcWidth;
int iSrcBufWidth;
int cxLeftWidth;
int xMinLeft;
int xMaxLeft;
int cxRightWidth;
int xMinRight;
int xMaxRight;
int cxMiddleWidth;
int cxNewMiddleWidth;
int xMinMiddle;
int xMaxMiddle;
// Variable for shrunken corners and sides
BOOL fShowMiddle;
DNGSTRETCH stretchLeft;
DNGSTRETCH stretchRight;
int cxNewLeftWidth;
int cxNewRightWidth;
BOOL fTileMode;
// Specific to non-tile mode (i.e. stretch mode)
DNGSTRETCH stretchMiddle;
LONG lBufWidth;
} DNGINTERNALDATA;
static inline void DNG_StretchRow(ULONG* pvDestBits, ULONG* pvSrcBits, DNGSTRETCH * ps)
{
ULONG* pvTemp = pvDestBits + ps->left;
ULONG* pvSentinel = pvDestBits + ps->right;
ULONG xInt = ps->xInt;
ULONG xFrac = ps->xFrac;
ULONG xTmp;
ULONG xAccum = ps->xAccum;
ULONG * pulSrc = pvSrcBits + ps->xStart;
ULONG ulSrc;
while (pvTemp != pvSentinel)
{
ulSrc = *pulSrc;
xTmp = xAccum + xFrac;
pulSrc = pulSrc + xInt + (xTmp < xAccum);
*pvTemp = ulSrc;
pvTemp++;
xAccum = xTmp;
}
}
static inline void DNG_InitStretch(DNGSTRETCH* pStretch, ULONG ulDestWidth, ULONG ulSrcWidth, int left, int right)
{
pStretch->right = right;
pStretch->left = left;
ULONGLONG dx = ((((ULONGLONG) ulSrcWidth << 32) - 1) / (ULONGLONG) ulDestWidth) + 1;
ULONGLONG x = (((ULONGLONG) ulSrcWidth << 32) / (ULONGLONG) ulDestWidth) >> 1;
ULONG xInt = pStretch->xInt = (ULONG) (dx >> 32);
ULONG xFrac = pStretch->xFrac = (ULONG) (dx & 0xFFFFFFFF);
ULONG xAccum = (ULONG) (x & 0xFFFFFFFF);
ULONG xStart = (ULONG) (x >> 32);
if (left <= 5)
{
ULONG xTmp;
for (int i = 0; i < left; i++)
{
xTmp = xAccum + xFrac;
xStart = xStart + xInt + (xTmp < xAccum);
xAccum = xTmp;
}
}
else
{
ULONGLONG xTmp = ((ULONGLONG) xFrac * (ULONGLONG) left) + (ULONGLONG) xAccum;
xStart = xStart + (xInt * left) + (ULONG) (xTmp >> 32);
xAccum = (ULONG) xTmp;
}
pStretch->xStart = xStart;
pStretch->xAccum = xAccum;
}
static inline void DNG_DrawRow(DNGINTERNALDATA* pdng)
{
ULONG* pvDestLoc = pdng->pvDestBits;
ULONG* pvSrcLoc = pdng->pvSrcBits;
// Left
if (pdng->cxClipMin < pdng->cxNewLeftWidth)
{
if (pdng->cxLeftWidth == pdng->cxNewLeftWidth)
{
RtlCopyMemory(pvDestLoc + pdng->xMinLeft, pvSrcLoc + pdng->xMinLeft, (pdng->xMaxLeft - pdng->xMinLeft) * sizeof(ULONG));
}
else
{
DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchLeft);
}
}
pvDestLoc += pdng->cxNewLeftWidth;
pvSrcLoc += pdng->cxLeftWidth;
// Middle
if (pdng->fShowMiddle)
{
if (pdng->xMinMiddle < pdng->xMaxMiddle)
{
if (pdng->fTileMode)
{
ULONG* pvTempSrc = pvSrcLoc;
ULONG* pvTempDest = pvDestLoc;
// Fill in Top Tile
int xMin = pdng->xMinMiddle;
int xDiff = xMin - pdng->cxLeftWidth;
pvDestLoc += xDiff;
int iTileSize = pdng->cxMiddleWidth - (xDiff % pdng->cxMiddleWidth);
pvSrcLoc += xDiff % pdng->cxMiddleWidth;
int xMax = pdng->xMaxMiddle;
for (int x = xMin; x < xMax; x++, pvDestLoc++ , pvSrcLoc++)
{
*pvDestLoc = *pvSrcLoc;
iTileSize--;
if (iTileSize == 0)
{
iTileSize = pdng->cxMiddleWidth;
pvSrcLoc -= iTileSize;
}
}
pvDestLoc = pvTempDest;
pvSrcLoc = pvTempSrc;
}
else
{
DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchMiddle);
}
}
pvDestLoc += pdng->cxNewMiddleWidth;
}
pvSrcLoc += pdng->cxMiddleWidth;
// Right
if (pdng->cxClipMax > (pdng->iDestWidth - pdng->cxNewRightWidth))
{
if (pdng->cxRightWidth == pdng->cxNewRightWidth)
{
RtlCopyMemory(pvDestLoc + pdng->xMinRight, pvSrcLoc + pdng->xMinRight, (pdng->xMaxRight - pdng->xMinRight) * sizeof(ULONG));
}
else
{
DNG_StretchRow(pvDestLoc, pvSrcLoc, &pdng->stretchRight);
}
}
}
static inline void DNG_StretchCol(DNGINTERNALDATA* pdng, DNGSTRETCH * ps)
{
ULONG* pvOldDestBits = pdng->pvDestBits;
ULONG* pvOldSrcBits = pdng->pvSrcBits;
ULONG* pvTemp = pdng->pvDestBits - (pdng->lDestDelta * ps->left);
ULONG* pvSentinel = pdng->pvDestBits - (pdng->lDestDelta * ps->right);
ULONG xInt = ps->xInt;
ULONG xFrac = ps->xFrac;
ULONG xTmp;
ULONG xAccum = ps->xAccum;
ULONG * pulSrc = pdng->pvSrcBits - (LONG)(pdng->lSrcDelta * ps->xStart); // Note the LONG cast so we get correct pointer arithmetic on WIN64.
ULONG xDelta = 1; // force stretch on first scan
while (pvTemp != pvSentinel)
{
if (xDelta != 0)
{
pdng->pvDestBits = pvTemp;
pdng->pvSrcBits = pulSrc;
DNG_DrawRow(pdng);
}
else
{
RtlCopyMemory(pvTemp + pdng->cxClipMin, pvTemp + pdng->cxClipMin + pdng->lDestDelta, pdng->iClipWidth * sizeof(ULONG));
}
xTmp = xAccum + xFrac;
xDelta = (xInt + (xTmp < xAccum));
pulSrc = pulSrc - (LONG)(pdng->lSrcDelta * xDelta); // Note LONG cast
pvTemp -= pdng->lDestDelta;
xAccum = xTmp;
}
pdng->pvDestBits = pvOldDestBits;
pdng->pvSrcBits = pvOldSrcBits;
}
static void RenderNineGridInternal(
SURFOBJ *psoScratch,
SURFOBJ *psoSrc,
RECTL *prclClip,
RECTL *prclDst,
RECTL *prclSrc,
DS_NINEGRIDINFO *ngi,
PDRAWSTREAMINFO pdsi,
BOOL bMirror)
{
RECTL rcDest = *prclDst;
RECTL rcClip = *prclClip;
ULONG* pvDestBits = NULL;
int iDestWidth = rcDest.right - rcDest.left;
int iDestHeight = rcDest.bottom - rcDest.top;
int iClipWidth = rcClip.right - rcClip.left;
int iClipHeight = rcClip.bottom - rcClip.top;
LONG lBufWidth = psoScratch->sizlBitmap.cx;
LONG lBufHeight = psoScratch->sizlBitmap.cy;
DNGINTERNALDATA dng;
// The code below assumes that the source and scratch is 32bpp
ASSERTGDI(psoSrc->iBitmapFormat == BMF_32BPP, "RenderNineGridInternal: source not 32bpp");
ASSERTGDI(psoScratch->iBitmapFormat == BMF_32BPP, "RenderNineGridInternal: scratch not 32bpp");
// The code below assumes that both source and scratch are bottom up
// ASSERTGDI(psoSrc->lDelta < 0, "RenderNineGridInternal: source is not bottom up");
// ASSERTGDI(psoScratch->lDelta < 0, "RenderNineGridInternal: scratch is not bottom up");
dng.lBufWidth = lBufWidth;
LONG lDestDelta = psoScratch->lDelta / (LONG)(sizeof(ULONG));
dng.lDestDelta = lDestDelta;
LONG lSrcDelta = psoSrc->lDelta / (LONG)(sizeof(ULONG));
dng.lSrcDelta = lSrcDelta;
dng.cxClipMin = rcClip.left - rcDest.left;
dng.cxClipMax = rcClip.right - rcDest.left;
int cyClipMin = rcClip.top - rcDest.top;
int cyClipMax = rcClip.bottom - rcDest.top;
// pvScan0 points to the pixel addressed at (cxClipMin, cyClipMin)
// pvDestBits points to the pixel addressed at (0, iDestHeight - 1)
pvDestBits = (ULONG *) psoScratch->pvScan0;
pvDestBits += (iDestHeight - 1 - cyClipMin) * lDestDelta;
pvDestBits -= dng.cxClipMin;
int cxImage = rcClip.right - rcClip.left;
int cyImage = rcClip.bottom - rcClip.top;
LONG lSrcBufWidth = psoSrc->sizlBitmap.cx;
LONG lSrcWidth = prclSrc->right - prclSrc->left;
LONG lSrcHeight = prclSrc->bottom - prclSrc->top;
ULONG * lSrcBits = (ULONG *) psoSrc->pvScan0 + (lSrcDelta * prclSrc->top) + prclSrc->left;
lSrcBits += (lSrcDelta * (prclSrc->bottom - prclSrc->top - 1));
// ULONG * lSrcBits = (ULONG *) psoSrc->pvScan0 + (lSrcDelta * (psoSrc->sizlBitmap.cy - 1));
if (ngi->flFlags & DSDNG_TRUESIZE)
{
ULONG* pvDestLoc = pvDestBits - ((iDestHeight - 1) * lDestDelta);
ULONG* pvSrcLoc = lSrcBits - ((lSrcHeight - 1) * lSrcDelta);
int yMin = cyClipMin;
pvDestLoc += yMin * lDestDelta;
pvSrcLoc += yMin * lSrcDelta;
int yMax = min(lSrcHeight, cyClipMax);
int xMin = dng.cxClipMin;
int xMax = min(lSrcWidth, dng.cxClipMax);
if (xMax > xMin)
{
for (int y = yMin; y < yMax; y++, pvDestLoc += lDestDelta, pvSrcLoc += lSrcDelta)
{
RtlCopyMemory(pvDestLoc + xMin, pvSrcLoc + xMin, (xMax - xMin) * 4);
}
}
cxImage = xMax - xMin;
cyImage = yMax - yMin;
}
else
{
// Setup data
dng.iDestWidth = iDestWidth;
dng.iClipWidth = iClipWidth;
dng.iSrcWidth = lSrcWidth;
dng.iSrcBufWidth = lSrcBufWidth;
dng.cxLeftWidth = ngi->ulLeftWidth;
dng.cxRightWidth = ngi->ulRightWidth;
dng.fTileMode = (ngi->flFlags & DSDNG_TILE);
// Calculate clip stuff
// Pre-calc corner stretching variables
dng.fShowMiddle = ((iDestWidth - dng.cxLeftWidth - dng.cxRightWidth > 0) && (lSrcWidth - dng.cxLeftWidth - dng.cxRightWidth > 0));
if (!dng.fShowMiddle)
{
dng.cxNewLeftWidth = (dng.cxLeftWidth + dng.cxRightWidth == 0) ? 0 : (dng.cxLeftWidth * dng.iDestWidth) / (dng.cxLeftWidth + dng.cxRightWidth);
dng.cxNewRightWidth = dng.iDestWidth - dng.cxNewLeftWidth;
}
else
{
dng.cxNewLeftWidth = dng.cxLeftWidth;
dng.cxNewRightWidth = dng.cxRightWidth;
}
// Pre-calc Left side variables
dng.xMinLeft = dng.cxClipMin;
dng.xMaxLeft = min(dng.cxNewLeftWidth, dng.cxClipMax);
if (!dng.fShowMiddle && dng.cxNewLeftWidth)
{
DNG_InitStretch(&dng.stretchLeft, dng.cxNewLeftWidth, dng.cxLeftWidth, dng.xMinLeft, dng.xMaxLeft);
}
// Pre-calc Horizontal Middle Variables
dng.cxMiddleWidth = dng.iSrcWidth - dng.cxLeftWidth - dng.cxRightWidth;
dng.cxNewMiddleWidth = dng.iDestWidth - dng.cxNewLeftWidth - dng.cxNewRightWidth;
dng.xMinMiddle = max(dng.cxNewLeftWidth, dng.cxClipMin);
dng.xMaxMiddle = min(dng.cxNewLeftWidth + dng.cxNewMiddleWidth, dng.cxClipMax);
if (dng.fShowMiddle)
{
DNG_InitStretch(&dng.stretchMiddle, dng.cxNewMiddleWidth, dng.cxMiddleWidth, dng.xMinMiddle - dng.cxNewLeftWidth, dng.xMaxMiddle - dng.cxNewLeftWidth);
}
// Pre-calc Right side variables
dng.xMinRight = max(dng.iDestWidth - dng.cxNewRightWidth, dng.cxClipMin) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
dng.xMaxRight = min(dng.iDestWidth, dng.cxClipMax) - dng.cxNewLeftWidth - dng.cxNewMiddleWidth;
if (!dng.fShowMiddle && dng.cxNewRightWidth)
{
DNG_InitStretch(&dng.stretchRight, dng.cxNewRightWidth, dng.cxRightWidth, dng.xMinRight, dng.xMaxRight);
}
BOOL fShowVertMiddle = ((iDestHeight - ngi->ulTopHeight - ngi->ulBottomHeight > 0) && (lSrcHeight - ngi->ulTopHeight - ngi->ulBottomHeight > 0));
int cyTopHeight = ngi->ulTopHeight;
int cyBottomHeight = ngi->ulBottomHeight;
int cyNewTopHeight;
int cyNewBottomHeight;
if (!fShowVertMiddle)
{
cyNewTopHeight = (cyTopHeight + cyBottomHeight == 0) ? 0 : (cyTopHeight * iDestHeight) / (cyTopHeight + cyBottomHeight);
cyNewBottomHeight = iDestHeight - cyNewTopHeight;
}
else
{
cyNewTopHeight = cyTopHeight;
cyNewBottomHeight = cyBottomHeight;
}
// Draw Bottom
// Draw the scan line from (iDestHeight - cyNewBottomHeight) to less than iDestHeight, in screen coordinates
int yMin = max(iDestHeight - cyNewBottomHeight, cyClipMin);
int yMax = min(iDestHeight, cyClipMax);
if (cyClipMax > iDestHeight - cyNewBottomHeight)
{
dng.pvDestBits = pvDestBits;
dng.pvSrcBits = lSrcBits;
if (cyBottomHeight == cyNewBottomHeight)
{
int yDiff = yMin - (iDestHeight - cyNewBottomHeight);
dng.pvDestBits -= (cyBottomHeight - 1 - yDiff) * lDestDelta;
dng.pvSrcBits -= (cyBottomHeight - 1 - yDiff) * lSrcDelta;
for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lSrcDelta)
{
DNG_DrawRow(&dng);
}
}
else if (cyNewBottomHeight > 0)
{
DNGSTRETCH stretch;
DNG_InitStretch(&stretch, cyNewBottomHeight, cyBottomHeight, cyNewBottomHeight - (yMax - iDestHeight + cyNewBottomHeight), cyNewBottomHeight - (yMin - iDestHeight + cyNewBottomHeight));
DNG_StretchCol(&dng, &stretch);
}
}
// Draw Middle
// Draw the scan line from cyNewTopHeight to less than (iDestHeight - cyNewBottomHeight), in screen coordinates
int cySrcTileSize = lSrcHeight - ngi->ulTopHeight - ngi->ulBottomHeight;
int cyDestTileSize = iDestHeight - ngi->ulTopHeight - ngi->ulBottomHeight;
if (fShowVertMiddle && (cySrcTileSize>0) && (cyDestTileSize>0) && (cyClipMin < iDestHeight - cyNewBottomHeight) && (cyClipMax > cyNewTopHeight))
{
dng.pvDestBits = pvDestBits - ngi->ulBottomHeight * lDestDelta;
dng.pvSrcBits = lSrcBits - ngi->ulBottomHeight * lSrcDelta;
int yMin = max(cyTopHeight, cyClipMin);
if (dng.fTileMode)
{
// Start off tile
dng.pvDestBits -= (cyDestTileSize - 1) * lDestDelta;
dng.pvSrcBits -= (cySrcTileSize - 1) * lSrcDelta;
int yDiff = yMin - cyTopHeight;
dng.pvDestBits += yDiff * lDestDelta;
int yOffset = (yDiff % cySrcTileSize);
dng.pvSrcBits += yOffset * dng.lSrcDelta;
int iTileOffset = cySrcTileSize - yOffset;
int yMax = min(yMin + min(cySrcTileSize, cyDestTileSize), min(iDestHeight - cyBottomHeight, cyClipMax));
for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lSrcDelta)
{
DNG_DrawRow(&dng);
iTileOffset--;
if (iTileOffset == 0)
{
iTileOffset = cySrcTileSize;
dng.pvSrcBits -= lSrcDelta * cySrcTileSize;
}
}
// Repeat tile pattern
dng.pvSrcBits = dng.pvDestBits - (lDestDelta * cySrcTileSize);
yMin = yMax;
yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lDestDelta)
{
RtlCopyMemory(dng.pvDestBits + dng.cxClipMin, dng.pvSrcBits + dng.cxClipMin, dng.iClipWidth * sizeof(ULONG));
}
}
else
{
int yMax = min(iDestHeight - cyBottomHeight, cyClipMax);
DNGSTRETCH stretch;
DNG_InitStretch(&stretch, cyDestTileSize, cySrcTileSize, cyDestTileSize - (yMax - cyTopHeight), cyDestTileSize - (yMin - cyTopHeight));
// Convert from screen coords to DIB coords
DNG_StretchCol(&dng, &stretch);
}
}
// Draw Top
// Draw the scan line from 0 to less than cyNewTopHeight, in screen coordinates
yMin = cyClipMin;
yMax = min(cyNewTopHeight, cyClipMax);
if (cyClipMin < cyNewTopHeight)
{
dng.pvDestBits = pvDestBits - (iDestHeight - cyNewTopHeight) * lDestDelta;
dng.pvSrcBits = lSrcBits - (lSrcHeight - ngi->ulTopHeight) * lSrcDelta;
if (cyTopHeight == cyNewTopHeight)
{
dng.pvDestBits -= (cyTopHeight - 1 - yMin) * lDestDelta;
dng.pvSrcBits -= (cyTopHeight - 1 - yMin) * lSrcDelta;
for (int y = yMin; y < yMax; y++, dng.pvDestBits += lDestDelta, dng.pvSrcBits += lSrcDelta)
{
DNG_DrawRow(&dng);
}
}
else if (cyNewTopHeight > 0)
{
DNGSTRETCH stretch;
DNG_InitStretch(&stretch, cyNewTopHeight, cyTopHeight, cyNewTopHeight - yMax, cyNewTopHeight - yMin);
DNG_StretchCol(&dng, &stretch);
}
}
}
if (bMirror)
{
// Flip the buffer
for (int y = 0; y < iClipHeight; y++)
{
ULONG* pvLeftBits = (ULONG *) psoScratch->pvScan0 + (y * lDestDelta);
ULONG* pvRightBits = pvLeftBits + iClipWidth - 1;
for (int x = 0; x < (iClipWidth / 2); x++)
{
ULONG ulTemp = *pvLeftBits;
*pvLeftBits = *pvRightBits;
*pvRightBits = ulTemp;
pvLeftBits++;
pvRightBits--;
}
}
}
}
static void RenderNineGrid(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoScratch,
CLIPOBJ *pco,
RECTL *prclClip,
XLATEOBJ *pxlo,
RECTL *prclDst,
RECTL *prclSrc,
DS_NINEGRIDINFO *ngi,
PDRAWSTREAMINFO pdsi,
BOOL bMirror)
{
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
PDEVOBJ pdoSrc(pSurfSrc->hdev());
PDEVOBJ pdoDst(pSurfDst->hdev());
XLATE * pxl = (XLATE *) pxlo;
SIZEL sizlScratch;
// only mirror the contents if we need to
bMirror = bMirror && (ngi->flFlags & DSDNG_MUSTFLIP);
// render nine grid into scratch
ERECTL erclClip = *prclClip;
if(bMirror)
{
// We need to remap the clip to ensure we generate the right flipped bits
erclClip.right = prclDst->right - (prclClip->left - prclDst->left);
erclClip.left = prclDst->right - (prclClip->right - prclDst->left);
}
RenderNineGridInternal(psoScratch, psoSrc, &erclClip, prclDst, prclSrc, ngi, pdsi, bMirror);
// copy scratch to destination
LONG lClipWidth = prclClip->right - prclClip->left;
LONG lClipHeight = prclClip->bottom - prclClip->top;
ERECTL erclScratch(0, 0, lClipWidth, lClipHeight);
if(ngi->flFlags & DSDNG_PERPIXELALPHA)
{
EBLENDOBJ eBlendObj;
eBlendObj.BlendFunction.AlphaFormat = AC_SRC_ALPHA;
eBlendObj.BlendFunction.BlendFlags = 0;
eBlendObj.BlendFunction.SourceConstantAlpha = 255;
eBlendObj.BlendFunction.BlendOp = AC_SRC_OVER;
eBlendObj.pxlo32ToDst = pdsi->pxloBGRAToDst;
eBlendObj.pxloDstTo32 = pdsi->pxloDstToBGRA;
eBlendObj.pxloSrcTo32 = pdsi->pxloSrcToBGRA;
PPFNDIRECT(psoDst, AlphaBlend)(psoDst, psoScratch, pco, pxlo, prclClip, &erclScratch, &eBlendObj);
}
else if(ngi->flFlags & DSDNG_TRANSPARENT)
{
PPFNDIRECT(psoDst, TransparentBlt)(psoDst, psoScratch, pco, pxlo, prclClip, &erclScratch, ngi->crTransparent, 0);
}
else
{
PPFNDIRECT(psoDst, CopyBits)(psoDst, psoScratch, pco, pxlo, prclClip, &gptlZero);
}
}
/******************************Private*Routine******************************\
* xxEngNineGrid
*
* This stuff will be moved to EngNineGrid
*
*
* History:
*
* 3-18-2001 bhouse Created it
*
\**************************************************************************/
static int xxEngNineGrid(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL * prclDst,
RECTL * prclSrc,
DS_NINEGRIDINFO *ngi,
PDRAWSTREAMINFO pdsi)
{
BOOL bRet = FALSE;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
PDEVOBJ pdoSrc(pSurfSrc->hdev());
PDEVOBJ pdoDst(pSurfDst->hdev());
XLATE * pxl = (XLATE *) pxlo;
ERECTL erclDst = *prclDst;
BOOL bMirror = (erclDst.left > erclDst.right);
if(bMirror)
{
LONG lRight = erclDst.left;
erclDst.left = erclDst.right;
erclDst.right = lRight;
}
// NOTE: TRUESIZE is a hack. The caller should do this reduction
// and pass us an appropriate destination.
// TODO: Talk with Justin Mann about changing his behavior in how
// he calls us here. We should add assertions that the
// destination dimensions never exceeds the source dimensions and
// modify GdiDrawStream callers to pass appropriate data.
if(ngi->flFlags & DSDNG_TRUESIZE)
{
LONG lSrcWidth = prclSrc->right - prclSrc->left;
LONG lSrcHeight = prclSrc->bottom - prclSrc->top;
// reduce destination to source size
if((erclDst.right - erclDst.left) > lSrcWidth)
{
if(bMirror)
erclDst.left = erclDst.right - lSrcWidth;
else
erclDst.right = erclDst.left + lSrcWidth;
}
if((erclDst.bottom - erclDst.top) > lSrcHeight)
{
if(bMirror)
erclDst.top = erclDst.bottom - lSrcHeight;
else
erclDst.bottom = erclDst.top + lSrcHeight;
}
}
SIZEL sizlScratch;
ERECTL erclClip = erclDst;
// For now, we only support 32bpp sources
ASSERTGDI(psoSrc->iBitmapFormat == BMF_32BPP, "EngNineGrid: source not 32bpp");
if(pco != (CLIPOBJ *) NULL && pco->iDComplexity != DC_TRIVIAL)
{
erclClip *= pco->rclBounds;
}
BOOL bClipOk = erclClip.left >= 0 &&
erclClip.top >= 0 &&
erclClip.right <= psoDst->sizlBitmap.cx &&
erclClip.bottom <= psoDst->sizlBitmap.cy;
ASSERTGDI(bClipOk, "EngNineGrid: bad clip");
if(!erclClip.bEmpty() && bClipOk)
{
LONG lClipWidth = erclClip.right - erclClip.left;
LONG lClipHeight = erclClip.bottom - erclClip.top;
ASSERTGDI(lClipWidth > 0, "RenderNineGrid: clip width <= 0");
ASSERTGDI(lClipHeight > 0, "RenderNineGrid: clip height <= 0");
#define SCRATCH_WIDTH (256)
#define SCRATCH_HEIGHT (64)
#if defined(USE_NINEGRID_STATIC)
SEMOBJ hsem(gNineGridSem);
static HSURF hsurfScratch = NULL;
if(hsurfScratch == NULL)
{
DEVBITMAPINFO dbmi;
SURFMEM surfScratch;
XEPALOBJ palScratch(pSurfSrc->ppal());
if(!palScratch.bValid())
{
WARNING("xxEngNineGrid: palScratch is not valid");
goto exit;
}
dbmi.cxBitmap = SCRATCH_WIDTH;
dbmi.cyBitmap = SCRATCH_HEIGHT;
dbmi.iFormat = pSurfSrc->iFormat();
dbmi.fl = 0;
dbmi.hpal = palScratch.hpal();
if(!surfScratch.bCreateDIB(&dbmi, (VOID*) NULL))
{
WARNING("xxEngNineGrid: could not create surfScratch");
goto exit;
}
surfScratch.vKeepIt();
surfScratch.vSetPID(OBJECT_OWNER_PUBLIC);
// Ensure that the scratch surface is not cached by driver
surfScratch.ps->iUniq(0);
hsurfScratch = surfScratch.ps->hsurf();
}
SURFREFAPI surfScratch(hsurfScratch);
if(!surfScratch.bValid())
{
WARNING("xxEngNineGrid: SURFREFAPI(surfScratch) failed");
goto exit;
}
SURFOBJ * psoScratch = surfScratch.pSurfobj();
#else
SURFACE *pSurfScratch;
SURFMEM dimoScratch;
{
DEVBITMAPINFO dbmi;
XEPALOBJ palScratch(pSurfSrc->ppal());
if(!palScratch.bValid())
{
WARINING("xxEngNineGrid: palScratch is not valid\n");
goto exit;
}
dbmi.cxBitmap = SCRATCH_WIDTH;
dbmi.cyBitmap = SCRATCH_HEIGHT;
dbmi.iFormat = pSurfSrc->iFormat();
dbmi.fl = 0;
dbmi.hpal = palScratch.hpal();
if(!dimoScratch.bCreateDIB(&dbmi, (VOID*) NULL))
{
WARINING("xxEngNineGrid: could not create surfScratch\n");
goto exit;
}
pSurfScratch = dimoScratch.ps;
}
SURFOBJ *psoScratch = pSurfScratch->pSurfobj();
#endif
if(lClipWidth > SCRATCH_WIDTH || lClipHeight > SCRATCH_HEIGHT)
{
LONG lBufWidth = SCRATCH_WIDTH;
LONG lBufHeight = SCRATCH_HEIGHT;
LONG lReducedClipTop = erclClip.top;
while(lReducedClipTop < erclClip.bottom)
{
LONG lReducedClipBottom = lReducedClipTop + lBufHeight;
if(lReducedClipBottom > erclClip.bottom)
lReducedClipBottom = erclClip.bottom;
LONG lReducedClipLeft = erclClip.left;
while(lReducedClipLeft < erclClip.right)
{
LONG lReducedClipRight = lReducedClipLeft + lBufWidth;
if(lReducedClipRight > erclClip.right)
lReducedClipRight = erclClip.right;
ERECTL erclReducedClip(lReducedClipLeft, lReducedClipTop,
lReducedClipRight, lReducedClipBottom);
RenderNineGrid(psoDst,
psoSrc,
psoScratch,
pco,
&erclReducedClip,
pxlo,
&erclDst,
prclSrc,
ngi,
pdsi,
bMirror);
lReducedClipLeft += lBufWidth;
}
lReducedClipTop += lBufHeight;
}
}
else
{
RenderNineGrid(psoDst, psoSrc, psoScratch, pco, &erclClip, pxlo, &erclDst, prclSrc, ngi, pdsi, bMirror);
}
}
bRet = TRUE;
exit:
return bRet;
}
/******************************Private*Routine******************************\
* EngNineGrid
*
* Purpose: Draws a nine grid.
*
* Description:
*
* <fill in details>
*
* History:
*
* 3-18-2001 bhouse Created it
*
\**************************************************************************/
BOOL EngNineGrid(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
PRECTL prclDst,
PRECTL prclSrc,
PNINEGRID png,
BLENDOBJ* pBlendObj,
PVOID pvReserved)
{
DRAWSTREAMINFO dsi;
EBLENDOBJ *peBlendObj = (EBLENDOBJ*)pBlendObj;
//
// The source surface of EngNineGrid should always be a
// GDI managed (memory) one.
//
if (psoSrc->iType != STYPE_BITMAP || psoSrc->iBitmapFormat != BMF_32BPP)
{
WARNING("EngNineGrid: psoSrc is not STYPE_BITMAP or not 32 Bpp");
SAVE_ERROR_CODE(ERROR_INVALID_PARAMETER);
return FALSE;
}
dsi.bCalledFromBitBlt = FALSE;
dsi.dss.blendFunction = pBlendObj->BlendFunction;
dsi.dss.crColorKey = png->crTransparent;
dsi.dss.ptlSrcOrigin.x = 0;
dsi.dss.ptlSrcOrigin.y = 0;
dsi.pptlDstOffset = &gptlZero;
dsi.pvStream = NULL;
dsi.ulStreamLength = 0;
dsi.pxloBGRAToDst = peBlendObj->pxlo32ToDst;
dsi.pxloDstToBGRA = peBlendObj->pxloDstTo32;
dsi.pxloSrcToBGRA = peBlendObj->pxloSrcTo32;
return xxEngNineGrid(psoDst, psoSrc, pco, pxlo, prclDst, prclSrc, (DS_NINEGRIDINFO *) png, &dsi);
}
#if 0
// code to convert nine grid to blt commands
LONG lSrcLeftWidth = cmd->ngi.ulLeftWidth;
LONG lSrcRightWidth = cmd->ngi.ulRightWidth;
LONG lSrcTopHeight = cmd->ngi.ulLeftWidth;
LONG lSrcBottomHeight = cmd->ngi.ulRightWidth;
LONG lDstLeftWidth = lSrcLeftWidth;
LONG lDstRightWidth = lSrcRightWidth;
LONG lDstTopHeight = lSrcTopHeight;
LONG lDstBottomHeight = lSrcBottomHeight;
LONG lDstWidth = erclDst.right - erclDst.left;
BOOL bDrawMiddle;
BOOL bMirror = (lDstWidth < 0);
if(bMirror)
{
// horizontal mirror
lDstLeftWidth = -lDstLeftWidth;
lDstRightWidth = -lDstRightWidth;
bDrawMiddle = (lDstWidth < lDstLeftWidth + lDstRightWidth);
}
else
{
bDrawMiddle = (lDstWidth > lDstLeftWidth + lDstRightWidth);
}
if(!bDrawMiddle && (lDstWidth != (lDstLeftWidth + lDstRightWidth)))
{
if((lDstLeftWidth + lDstRightWidth) == 0)
continue; // this should never happen, we can probably remove
lDstLeftWidth = lDstLeftWidth * lDstWidth / (lDstLeftWidth + lDstRightWidth);
lDstRightWidth = lDstWidth - lDstLeftWidth;
}
DS_BLT cmdBlts[9];
DS_BLT *cmdBlt = cmdBlts;
if(cmd->ngi.flFlags & DSDNG_TRUESIZE)
{
// left top
cmdBlt->ulCmdID = DS_BLTID;
cmdBlt->flFlags = 0;
if(cmd->ngi.flFlags & DSDNG_PERPIXELALPHA) cmdBlt->flFlags |= DSBLT_ALPHABLEND;
else if(cmd->ngi.flFlags & DSDNG_TRANSPARENT) cmdBlt->flFlags |= DSBLT_TRANSPARENT;
LONG lDstHeight = erclDst.bottom - erclDst.top;
LONG lSrcWidth = cmd->rclSrc.right - cmd->rclSrc.left;
LONG lSrcHeight = cmd->rclSrc.bottom - cmd->rclSrc.top;
LONG lWidth;
if(bMirror)
{
lWidth = (-lSrcWidth > lDstWidth ? -lSrcWidth : lDstWidth);
}
else
{
lWidth = (lSrcWidth < lDstWidth ? lSrcWidth : lDstWidth);
}
LONG lHeight = (lSrcHeight < lDstHeight ? lSrcHeight : lDstHeight);
cmdBlt->rclDst.left = erclDst.left;
cmdBlt->rclDst.top = erclDst.top;
cmdBlt->rclDst.right = erclDst.left + lWidth;
cmdBlt->rclDst.bottom = erclDst.top + lHeight;
cmdBlt->rclSrc.left = cmd->rclSrc.left;
cmdBlt->rclSrc.top = cmd->rclSrc.top;
cmdBlt->rclSrc.right = cmd->rclSrc.left + lWidth;
cmdBlt->rclSrc.bottom = cmd->rclSrc.top + lHeight;
cmd++;
}
else
{
// left top
cmdBlt->ulCmdID = DS_BLTID;
cmdBlt->flFlags = 0;
if(cmd->ngi.flFlags & DSDNG_TILE) cmdBlt->flFlags |= DSBLT_HTILE | DSBLT_VTILE;
if(cmd->ngi.flFlags & DSDNG_PERPIXELALPHA) cmdBlt->flFlags |= DSBLT_ALPHABLEND;
else if(cmd->ngi.flFlags & DSDNG_TRANSPARENT) cmdBlt->flFlags |= DSBLT_TRANSPARENT;
cmdBlt->rclDst.left = erclDst.left;
cmdBlt->rclDst.top = erclDst.top;
cmdBlt->rclDst.right = erclDst.left + lDstLeftWidth;
cmdBlt->rclDst.bottom = erclDst.top + lDstTopHeight;
cmdBlt->rclSrc.left = cmd->rclSrc.left;
cmdBlt->rclSrc.top = cmd->rclSrc.top;
cmdBlt->rclSrc.right = cmd->rclSrc.left + lSrcLeftWidth;
cmdBlt->rclSrc.bottom = cmd->rclSrc.top + lSrcTopHeight;
// middle top
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = cmdBlt->rclDst.right;
cmdBlt->rclDst.right = erclDst.right - lDstRightWidth;
cmdBlt->rclSrc.left = cmdBlt->rclSrc.right;
cmdBlt->rclSrc.right = cmd->rclSrc.right - lSrcRightWidth;
// right top
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = cmdBlt->rclDst.right;
cmdBlt->rclDst.right = erclDst.right;
cmdBlt->rclSrc.left = cmdBlt->rclSrc.right;
cmdBlt->rclSrc.right = cmd->rclSrc.right;
// left middle
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = erclDst.left;
cmdBlt->rclDst.top = erclDst.top + lDstTopHeight;
cmdBlt->rclDst.right = erclDst.left + lDstLeftWidth;
cmdBlt->rclDst.bottom = erclDst.bottom - lDstBottomHeight;
cmdBlt->rclSrc.left = cmd->rclSrc.left;
cmdBlt->rclSrc.top = cmd->rclSrc.top + lSrcTopHeight;
cmdBlt->rclSrc.right = cmd->rclSrc.left + lSrcLeftWidth;
cmdBlt->rclSrc.bottom = cmd->rclSrc.bottom - lSrcBottomHeight;
// middle middle
if(bDrawMiddle)
{
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = cmdBlt->rclDst.right;
cmdBlt->rclDst.right = erclDst.right - lDstRightWidth;
cmdBlt->rclSrc.left = cmdBlt->rclSrc.right;
cmdBlt->rclSrc.right = cmd->rclSrc.right - lSrcRightWidth;
}
// right middle
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = erclDst.right - lDstRightWidth;
cmdBlt->rclDst.right = erclDst.right;
cmdBlt->rclSrc.left = cmd->rclSrc.right - lSrcRightWidth;
cmdBlt->rclSrc.right = cmd->rclSrc.right;
// left bottom
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = erclDst.left;
cmdBlt->rclDst.top = erclDst.bottom - lDstBottomHeight;
cmdBlt->rclDst.right = erclDst.left + lDstLeftWidth;
cmdBlt->rclDst.bottom = erclDst.bottom;
cmdBlt->rclSrc.left = cmd->rclSrc.left;
cmdBlt->rclSrc.top = cmd->rclSrc.bottom - lSrcBottomHeight;
cmdBlt->rclSrc.right = cmd->rclSrc.left + lSrcLeftWidth;
cmdBlt->rclSrc.bottom = cmd->rclSrc.bottom;
// middle bottom
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = cmdBlt->rclDst.right;
cmdBlt->rclDst.right = erclDst.right - lDstRightWidth;
cmdBlt->rclSrc.left = cmdBlt->rclSrc.right;
cmdBlt->rclSrc.right = cmd->rclSrc.right - lSrcRightWidth;
// right bottom
cmdBlt++;
*cmdBlt = cmdBlt[-1];
cmdBlt->rclDst.left = cmdBlt->rclDst.right;
cmdBlt->rclDst.right = erclDst.right;
cmdBlt->rclSrc.left = cmdBlt->rclSrc.right;
cmdBlt->rclSrc.right = cmd->rclSrc.right;
cmdBlt++;
}
COLORREF crSave = pdss->crColorKey;
BLENDFUNCTION bfxSave = pdss->blendFunction;
pdss->blendFunction.AlphaFormat = AC_SRC_ALPHA;
pdss->blendFunction.BlendFlags = 0;
pdss->blendFunction.SourceConstantAlpha = 255;
pdss->blendFunction.BlendOp = AC_SRC_OVER;
// It is safe to go direct from here ... the source can't be a sprite
// and the destination has already been taken care of (we have to
// go through the sprite layer for the dest to get this far).
bRet = (*PPFNDRVENG(psoDst, DrawStream))(psoDst, psoSrc, pco, pxlo, prclDstClip, &gptlZero,
(ULONG) ((BYTE*) cmdBlt - (BYTE*) cmdBlts), cmdBlts, pdss);
pdss->crColorKey = crSave;
pdss->blendFunction = bfxSave;
#endif
#if DS_ENABLE_BLT
int EngTileBits(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL * prclDst,
RECTL * prclSrc,
POINTL * tileOrigin)
{
int iRet = TRUE;
if(tileOrigin->x != 0 || tileOrigin->y != 0)
return FALSE;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
PDEVOBJ pdoSrc(pSurfSrc->hdev());
PDEVOBJ pdoDst(pSurfDst->hdev());
XLATE * pxl = (XLATE *) pxlo;
// TODO bhouse
// we should handle all of the clipping cases
// in the fast copy.
LONG tileWidth = prclSrc->right - prclSrc->left;
LONG tileHeight = prclSrc->bottom - prclSrc->top;
if(tileWidth <= 0 || tileHeight <= 0)
return FALSE;
PFN_DrvCopyBits pfnCopyBits;
// TODO: create a new dest if DC_RECT and adjust tileOrigin
if((pSurfSrc->iType() == STYPE_BITMAP && !(pSurfSrc->fjBitmap() & BMF_NOTSYSMEM)) &&
(pSurfDst->iType() == STYPE_BITMAP && !(pSurfDst->fjBitmap() & BMF_NOTSYSMEM)) &&
pxl->bIsIdentity() &&
(pco == NULL || pco->iDComplexity == DC_TRIVIAL) &&
pSurfSrc->iFormat() >= BMF_8BPP &&
pSurfSrc->iFormat() <= BMF_32BPP)
{
// tile it by hand nice and fast
// TODO bhouse
// Easy optimization here, we don't need to sync
// every time ... seems wastefull as heck
pdoSrc.vSync(psoDst,NULL,0);
pdoDst.vSync(psoSrc,NULL,0);
ULONG ulBytesPerPixel = (pSurfSrc->iFormat() - BMF_8BPP) + 1;
ULONG ulTileWidthBytes = tileWidth * ulBytesPerPixel;
ULONG ulDstWidthBytes = (prclDst->right - prclDst->left) * ulBytesPerPixel;
PBYTE pbSrcStart = (PBYTE) pSurfSrc->pvScan0() +
(prclSrc->top * pSurfSrc->lDelta()) +
(prclSrc->left * ulBytesPerPixel);
PBYTE pbSrcEnd = (PBYTE) pSurfSrc->pvScan0() +
(prclSrc->bottom * pSurfSrc->lDelta()) +
(prclSrc->left * ulBytesPerPixel);
PBYTE pbDst = (PBYTE) pSurfDst->pvScan0() +
(prclDst->top * pSurfDst->lDelta()) +
(prclDst->left * ulBytesPerPixel);
PBYTE pbDstEnd = (PBYTE) pSurfDst->pvScan0() +
(prclDst->bottom * pSurfDst->lDelta()) +
(prclDst->left * ulBytesPerPixel);
PBYTE pbSrc = pbSrcStart;
while(pbDst != pbDstEnd)
{
PBYTE pbDstLineEnd = pbDst + ulDstWidthBytes;
PBYTE pbDstLine = pbDst;
while(pbDstLine < pbDstLineEnd)
{
ULONG ulCopyBytes = (ULONG)(pbDstLineEnd - pbDstLine);
if(ulCopyBytes > ulTileWidthBytes)
ulCopyBytes = ulTileWidthBytes;
RtlCopyMemory(pbDstLine, pbSrc, ulCopyBytes);
pbDstLine += ulCopyBytes;
}
pbSrc += pSurfSrc->lDelta();
if(pbSrc == pbSrcEnd)
pbSrc = pbSrcStart;
pbDst += pSurfDst->lDelta();
}
return TRUE;
}
// else if(pSurfDst->iType() == STYPE_BITMAP)
// pfnCopyBits = EngCopyBits;
else
pfnCopyBits = PPFNGET(pdoDst,CopyBits,pSurfDst->flags());
// brain dead method
LONG y = prclDst->top;
LONG yEnd = prclDst->bottom;
LONG xEnd = prclDst->right;
RECTL dstRect;
while(y < yEnd)
{
LONG dy = yEnd - y;
if(dy > tileHeight) dy = tileHeight;
LONG x = prclDst->left;
while(x < xEnd)
{
LONG dx = xEnd - x;
if(dx > tileWidth) dx = tileWidth;
dstRect.left = x;
dstRect.top = y;
dstRect.right = x + dx;
dstRect.bottom = y + dy;
// TODO bhouse
// Lame clipping has to be fixed
if(pco == NULL || pco->iDComplexity == DC_TRIVIAL || bIntersect(&pco->rclBounds, &dstRect))
if(!(*pfnCopyBits)(psoDst, psoSrc, pco, pxlo, &dstRect, (POINTL*) prclSrc))
return FALSE;
x += dx;
}
y += dy;
}
return TRUE;
}
int EngTransparentTile(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL * prclDst,
RECTL * prclSrc,
POINTL * tileOrigin,
COLORREF crTransparentColor
)
{
int iRet = TRUE;
if(tileOrigin->x != 0 || tileOrigin->y != 0)
return FALSE;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
PDEVOBJ pdoSrc(pSurfSrc->hdev());
PDEVOBJ pdoDst(pSurfDst->hdev());
XLATE * pxl = (XLATE *) pxlo;
// TODO bhouse
// we should handle all of the clipping cases
// in the fast copy.
LONG tileWidth = prclSrc->right - prclSrc->left;
LONG tileHeight = prclSrc->bottom - prclSrc->top;
if(tileWidth <= 0 || tileHeight <= 0)
return FALSE;
PFN_DrvTransparentBlt pfnTransparentBlt;
// if(pSurfDst->iType() == STYPE_BITMAP)
// pfnTransparentBlt = EngTransparentBlt;
// else
pfnTransparentBlt = PPFNGET(pdoDst,TransparentBlt,pSurfDst->flags());
// brain dead method
ERECTL dstRect;
ERECTL srcRect;
LONG y = prclDst->top;
LONG yEnd = prclDst->bottom;
LONG xEnd = prclDst->right;
srcRect.left = prclSrc->left;
srcRect.top = prclSrc->top;
while(y < yEnd)
{
LONG dy = yEnd - y;
if(dy > tileHeight) dy = tileHeight;
LONG x = prclDst->left;
dstRect.top = y;
dstRect.bottom = y + dy;
srcRect.bottom = srcRect.top + dy;
while(x < xEnd)
{
LONG dx = xEnd - x;
if(dx > tileWidth) dx = tileWidth;
dstRect.left = x;
dstRect.right = x + dx;
srcRect.right = srcRect.left + dx;
// TODO bhouse
// Lame clipping has to be fixed
if(pco == NULL || pco->iDComplexity == DC_TRIVIAL || bIntersect(&pco->rclBounds, &dstRect))
if(!(*pfnTransparentBlt)(psoDst, psoSrc, pco, pxlo, &dstRect, &srcRect, crTransparentColor, FALSE))
return FALSE;
x += dx;
}
y += dy;
}
return TRUE;
}
int EngAlphaTile(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL * prclDst,
RECTL * prclSrc,
POINTL * tileOrigin,
BLENDOBJ *pBlendObj
)
{
int iRet = TRUE;
if(tileOrigin->x != 0 || tileOrigin->y != 0)
return FALSE;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
PDEVOBJ pdoSrc(pSurfSrc->hdev());
PDEVOBJ pdoDst(pSurfDst->hdev());
XLATE * pxl = (XLATE *) pxlo;
// TODO bhouse
// we should handle all of the clipping cases
// in the fast copy.
LONG tileWidth = prclSrc->right - prclSrc->left;
LONG tileHeight = prclSrc->bottom - prclSrc->top;
if(tileWidth <= 0 || tileHeight <= 0)
return FALSE;
PFN_DrvAlphaBlend pfnAlphaBlend;
// if(pSurfDst->iType() == STYPE_BITMAP)
// pfnAlphaBlend = EngAlphaBlend;
// else
pfnAlphaBlend = PPFNGET(pdoDst,AlphaBlend,pSurfDst->flags());
// brain dead method
LONG y = prclDst->top;
LONG yEnd = prclDst->bottom;
LONG xEnd = prclDst->right;
RECTL dstRect;
RECTL srcRect;
while(y < yEnd)
{
LONG dy = yEnd - y;
if(dy > tileHeight) dy = tileHeight;
LONG x = prclDst->left;
while(x < xEnd)
{
LONG dx = xEnd - x;
if(dx > tileWidth) dx = tileWidth;
dstRect.left = x;
dstRect.top = y;
dstRect.right = x + dx;
dstRect.bottom = y + dy;
srcRect.left = prclSrc->left;
srcRect.top = prclSrc->top;
srcRect.right = srcRect.left + dx;
srcRect.bottom = srcRect.top + dy;
// TODO bhouse
// Lame clipping has to be fixed
if(pco == NULL || pco->iDComplexity == DC_TRIVIAL || bIntersect(&pco->rclBounds, &dstRect))
if(!(*pfnAlphaBlend)(psoDst, psoSrc, pco, pxlo, &dstRect, &srcRect, pBlendObj ))
return FALSE;
x += dx;
}
y += dy;
}
return TRUE;
}
int EngDrawStreamBlt(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL * prclDst,
RECTL * prclSrc,
FLONG flFlags,
PDRAWSTREAMINFO pdsi)
{
int iRet = TRUE;
ERECTL erclDst = *prclDst;
BOOL bMirror = (erclDst.left > erclDst.right);
if(bMirror)
{
LONG lRight = erclDst.left;
erclDst.left = erclDst.right;
erclDst.right = lRight;
}
if(pco != NULL && pco->iDComplexity != DC_TRIVIAL && !bIntersect(&pco->rclBounds, &erclDst))
return TRUE;
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
PDEVOBJ pdoDst(pSurfDst->hdev());
FLONG flTile = (flFlags & (DSBLT_VTILE | DSBLT_HTILE));
if(flTile && flTile != (DSBLT_VTILE | DSBLT_HTILE))
{
// TODO: handle the case where we are tiling in one
// direction and stretching in the other
return TRUE;
}
if(flFlags & DSBLT_ALPHABLEND)
{
EBLENDOBJ eBlendObj;
eBlendObj.BlendFunction = pdsi->dss.blendFunction;
eBlendObj.pxlo32ToDst = pdsi->pxloBGRAToDst;
eBlendObj.pxloDstTo32 = pdsi->pxloDstToBGRA;
eBlendObj.pxloSrcTo32 = pdsi->pxloSrcToBGRA;
if(flTile)
{
iRet = EngAlphaTile(psoDst, psoSrc, pco, pxlo, &erclDst,
prclSrc, &gptlZero, (BLENDOBJ*) &eBlendObj);
}
else
{
iRet = (*PPFNGET(pdoDst,AlphaBlend,pSurfDst->flags()))(psoDst, psoSrc, pco, pxlo, &erclDst, prclSrc, &eBlendObj);
}
}
else if(flFlags & DSBLT_TRANSPARENT)
{
if(flTile)
{
iRet = EngTransparentTile(psoDst, psoSrc, pco, pxlo, &erclDst,
prclSrc, &gptlZero, pdsi->dss.crColorKey);
}
else
{
iRet = (*PPFNGET(pdoDst, TransparentBlt, pSurfDst->flags()))(psoDst, psoSrc, pco, pxlo,
&erclDst, prclSrc,
pdsi->dss.crColorKey,
FALSE);
}
}
else
{
if(flTile)
{
iRet = EngTileBits(psoDst, psoSrc, pco, pxlo, &erclDst,
prclSrc, &gptlZero);
}
else
{
iRet = (*PPFNGET(pdoDst, StretchBlt, pSurfDst->flags()))(psoDst, psoSrc, NULL, pco, pxlo,
NULL, NULL,
&erclDst, prclSrc,
NULL,
COLORONCOLOR);
}
}
return iRet;
}
#endif
/******************************Private*Routine******************************\
* EngDrawStream
*
* Purpose: Draws a graphics stream
*
* Description:
*
* Parses the graphics stream rendering each command as approprite.
*
* History:
*
* 3-18-2001 bhouse Created it
*
\**************************************************************************/
BOOL
EngDrawStream(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
PRECTL prclDstClip,
PPOINTL pptlDstOffset,
ULONG cjIn,
PVOID pvIn,
DSSTATE *pdss
)
{
BOOL bRet = TRUE;
PDRAWSTREAMINFO pdsi = (PDRAWSTREAMINFO) pdss;
ASSERTGDI(psoDst != NULL, "ERROR EngDrawStream: No Dst. Object\n");
ASSERTGDI(psoSrc != NULL, "ERROR EngDrawStream: No Src. Object\n");
ASSERTGDI(prclDstClip != (PRECTL) NULL, "ERROR EngDrawStream: No Target Bounds Rect.\n");
ASSERTGDI(prclDstClip->left < prclDstClip->right, "ERROR EngCopyBits0\n");
ASSERTGDI(prclDstClip->top < prclDstClip->bottom, "ERROR EngCopyBits1\n");
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE(psoDst);
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(psoSrc);
PDEVOBJ pdoDst(pSurfDst->hdev());
ASSERTGDI(pSurfDst->iFormat() != BMF_JPEG,
"ERROR EngCopyBits: dst BMF_JPEG\n");
ASSERTGDI(pSurfDst->iFormat() != BMF_PNG,
"ERROR EngCopyBits: dst BMF_PNG\n");
ASSERTGDI(pSurfSrc->iFormat() != BMF_JPEG,
"ERROR EngCopyBits: src BMF_JPEG\n");
ASSERTGDI(pSurfSrc->iFormat() != BMF_PNG,
"ERROR EngCopyBits: src BMF_PNG\n");
ULONG * pul = (ULONG *) pvIn;
while(cjIn >= sizeof(ULONG))
{
ULONG command = *pul;
HDC hdcTarget;
HDC hdcSource;
ULONG commandSize;
switch(command)
{
case DS_NINEGRIDID:
{
// TODO: ensure that the destination rect is within bounds
DS_NINEGRID * cmd = (DS_NINEGRID *) pul;
commandSize = sizeof(*cmd);
if(cjIn < commandSize) goto exit;
ERECTL erclDst(cmd->rclDst);
erclDst += *pptlDstOffset;
// Note, we are going directly to the driver or to EngNineGrid
// without going back through sprite or multimon layer. This is
// ok because we will have already gone through those layers to
// get here and the source can not be a primary surface.
PFN_DrvNineGrid pfn = pSurfDst->pfnNineGrid();
if( psoDst->dhpdev == NULL || !(pdoDst.flGraphicsCaps2() & GCAPS2_REMOTEDRIVER))
pfn = EngNineGrid;
// TODO: have the eBlendObj be part of DRAWSTREAMINFO
EBLENDOBJ eBlendObj;
eBlendObj.BlendFunction.AlphaFormat = AC_SRC_ALPHA;
eBlendObj.BlendFunction.BlendFlags = 0;
eBlendObj.BlendFunction.SourceConstantAlpha = 255;
eBlendObj.BlendFunction.BlendOp = AC_SRC_OVER;
eBlendObj.pxlo32ToDst = pdsi->pxloBGRAToDst;
eBlendObj.pxloDstTo32 = pdsi->pxloDstToBGRA;
eBlendObj.pxloSrcTo32 = pdsi->pxloSrcToBGRA;
bRet = (*pfn)(psoDst, psoSrc, pco, pxlo, &erclDst, &cmd->rclSrc, (PNINEGRID) &cmd->ngi, &eBlendObj, NULL);
}
break;
#if DS_ENABLE_BLT
case DS_BLTID:
{
// TODO: ensure that the destination rect is within bounds
DS_BLT * cmd = (DS_BLT *) pul;
commandSize = sizeof(*cmd);
if(cjIn < commandSize) goto exit;
ERECTL erclDst(cmd->rclDst);
erclDst += *pptlDstOffset;
if(!EngDrawStreamBlt(psoDst, psoSrc, pco, pxlo, &erclDst,
&cmd->rclSrc, cmd->flFlags, pdsi))
goto exit;
}
break;
case DS_SETCOLORKEYID:
{
// TODO: ensure that the destination rect is within bounds
DS_SETCOLORKEY * cmd = (DS_SETCOLORKEY *) pul;
commandSize = sizeof(*cmd);
if(cjIn < commandSize) goto exit;
pdsi->dss.crColorKey = cmd->crColorKey;
}
break;
case DS_SETBLENDID:
{
// TODO: ensure that the destination rect is within bounds
DS_SETBLEND * cmd = (DS_SETBLEND *) pul;
commandSize = sizeof(*cmd);
if(cjIn < commandSize) goto exit;
pdsi->dss.blendFunction = cmd->blendFunction;
}
break;
#endif
default:
goto exit;
}
cjIn -= commandSize;
pul += commandSize / 4;
}
exit:
return bRet;
}
/******************************Private*Routine******************************\
*
* NtGdiDrawStreamInternal
*
* Draws the given graphics stream to the given destination using
* the given source for any stream commands which require a source.
*
* History:
* 3-18-2001 bhouse Created it
*
\**************************************************************************/
BOOL
NtGdiDrawStreamInternal(
XDCOBJ& dcoDst,
EXFORMOBJ& xoDst,
SURFACE* pSurfSrc,
XLATEOBJ * pxlo,
RECTL* prclDstClip,
RECTL* prclDstBounds,
LONG cjIn,
LPSTR pvIn,
PDRAWSTREAMINFO pdsi
)
{
BOOL bReturn = FALSE;
ASSERTGDI(dcoDst.bValid(), "NtGdiDrawStrea: invalide destination DC\n");
ASSERTGDI(pSurfSrc != NULL, "NtGdiDrawStream: null source surface\n");
ERECTL erclDstClip(*prclDstClip);
ERECTL erclDstBounds(*prclDstBounds);
EPOINTL eptlDstOffset(0,0);
if(dcoDst.bDisplay() && !dcoDst.bRedirection() && !UserScreenAccessCheck())
{
//WARNING("NtGdiDrawStreamInternal: Screen Access Check Failed\n");
SAVE_ERROR_CODE(ERROR_ACCESS_DENIED);
goto exit;
}
if(xoDst.bRotation())
{
WARNING("NtGdiDrawStreamInternal: destination has rotational transform");
goto exit;
}
if(xoDst.bTranslationsOnly())
{
xoDst.bXform(eptlDstOffset);
}
else
{
// walk the stream applying transform
ULONG *pul = (ULONG *) pvIn;
ULONG *pulEnd = (ULONG*) ((BYTE*) pul + cjIn);
while(pul < pulEnd)
{
switch(*pul)
{
case DS_NINEGRIDID:
{
DS_NINEGRID * cmd = (DS_NINEGRID *) pul;
xoDst.bXform(*(ERECTL*)&cmd->rclDst);
pul = (ULONG*) (cmd+1);
}
break;
default:
WARNING("NtGdiDrawStreamInternal: unrecognized draw stream command");
goto exit;
}
}
}
xoDst.bXform(erclDstBounds);
erclDstBounds.vOrder();
if(erclDstClip.bEmpty())
{
WARNING("NtGdiDrawStreamInternal: destination clip is empty");
goto exit;
}
//
// Check pSurfDst, this may be an info DC or a memory DC with default bitmap.
//
SURFACE *pSurfDst = dcoDst.pSurface();
//
// Set up the brush if necessary.
//
EBRUSHOBJ *pbo = NULL;
//
// With a fixed DC origin we can change the destination to SCREEN coordinates.
//
eptlDstOffset += dcoDst.eptlOrigin();
erclDstClip += dcoDst.eptlOrigin();
//
// This is a pretty gnarly expression to save a return in here.
// Basically pco can be NULL if the rect is completely in the
// cached rect in the DC or if we set up a clip object that isn't empty.
//
ECLIPOBJ *pco = NULL;
BOOL bForce = !erclDstClip.bContain(erclDstBounds);
if (((erclDstBounds.left >= dcoDst.prclClip()->left) &&
(erclDstBounds.right <= dcoDst.prclClip()->right) &&
(erclDstBounds.top >= dcoDst.prclClip()->top) &&
(erclDstBounds.bottom <= dcoDst.prclClip()->bottom) &&
(!bForce)) ||
(pco = dcoDst.pco(),
pco->vSetup(dcoDst.prgnEffRao(), erclDstClip, (bForce ? CLIP_FORCE : CLIP_NOFORCE)),
erclDstClip = pco->erclExclude(),
(!erclDstClip.bEmpty())))
{
//
// Inc the target surface uniqueness
//
INC_SURF_UNIQ(pSurfDst);
PFN_DrvDrawStream pfn = pSurfDst->pfnDrawStream();
//
// Only call through draw stream layer for primary pdev surfaces
// and Meta DEVBITMAPS.
// This will allows us to call through sprite layer and multi-mon
// layer for the primary and Meta DEVBITMAPS only.
// Device drivers currently are not allowed to hook draw stream.
// NOTE: we have run out of hook flags. We will need to extend the
// hook flag mechanism to support additional DDI. This check
// is a hack to avoid calling through the sprite and multi-mon
// layers. (Normally, the hook flags would be set correctly
// to do the right thing).
PDEVOBJ pdoDst(pSurfDst->hdev());
BOOL bDstMetaDriver = (dcoDst.bSynchronizeAccess() && pdoDst.bValid() && pdoDst.bMetaDriver());
if(!pSurfDst->bPDEVSurface() && !(bDstMetaDriver && pSurfDst->iType() == STYPE_DEVBITMAP))
pfn = EngDrawStream;
bReturn = (*pfn) (
pSurfDst->pSurfobj(),
pSurfSrc->pSurfobj(),
pco,
pxlo,
&erclDstClip,
&eptlDstOffset,
cjIn,
pvIn,
(DSSTATE*) pdsi);
}
else
{
bReturn = TRUE;
}
exit:
return(bReturn);
}
BOOL gGreDrawStream = TRUE;
BOOL gDrawClipped = FALSE;
/******************************Private*Routine******************************\
*
* GreDrawStream
*
* Draws a graphics stream. hdcDst is the primary output device is more
* then one target is set within the stream.
*
* History:
* 3-18-2001 bhouse Created it
*
\**************************************************************************/
BOOL GreDrawStream(
HDC hdcDst,
ULONG cjIn,
PVOID pvIn
)
{
XDCOBJ dcoDst;
XDCOBJ dcoSrc;
SURFREFDC soSrc;
BOOL bRet = FALSE;
EXFORMOBJ xoSrc;
EXFORMOBJ xoDst;
DEVLOCKBLTOBJ dloSrc;
DEVLOCKBLTOBJ dloDst;
SURFACE * pSurfDst;
SURFACE * pSurfSrc = NULL;
XEPALOBJ palSrcDC;
XLATEOBJ * pxlo;
XEPALOBJ palDst;
XEPALOBJ palDstDC;
XEPALOBJ palSrc;
XEPALOBJ palRGB(gppalRGB);
EXLATEOBJ xlo;
ERECTL erclDstClip;
BOOL bAlphaBlendPresent = FALSE;
PVOID pvPrimStart = NULL;
DRAWSTREAMINFO dsi;
ERECTL erclDstBounds;
BOOL bFoundTrg = FALSE;
dloSrc.vInit();
dloDst.vInit();
if(!gGreDrawStream)
{
WARNING("GreDrawStream: gGreDrawStream == 0");
goto exit;
}
if(cjIn < sizeof(ULONG))
{
WARNING("GreDrawStream: cjIn < sizeof(ULONG)");
goto exit;
}
ULONG * pul = (ULONG *) pvIn;
if(*pul++ != 'DrwS')
{
WARNING("GreDrawStream: did not find DrwS magic number");
goto exit;
}
cjIn -= sizeof(ULONG);
while(cjIn >= sizeof(ULONG))
{
ULONG command = *pul;
HDC hdcTarget;
HDC hdcSource;
ULONG commandSize;
switch(command)
{
case DS_SETTARGETID: // set target
{
if(pvPrimStart != NULL) goto drawStream;
dloDst.vUnLock();
dcoDst.vUnlock();
soSrc.vUnlock();
DS_SETTARGET * cmd = (DS_SETTARGET *) pul;
commandSize = sizeof(*cmd);
if(cjIn < commandSize)
{
WARNING("GreDrawStream: cjIn < commandSize");
goto exit;
}
if((HDC) LongToHandle((LONG)(cmd->hdc)) != hdcDst)
{
WARNING("GreDrawStream: cmd->hdc != hdcDst");
goto exit;
}
dcoDst.vLock((HDC) LongToHandle((LONG)(cmd->hdc)));
if(!dcoDst.bValid())
{
WARNING("GreDrawStream: !dcoDst.bValid()");
goto exit;
}
if(dcoDst.bStockBitmap())
{
WARNING("GreDrawStream: dcoDst has Stock bitmap selected");
goto exit;
}
if(!dloDst.bLock(dcoDst))
{
WARNING("GreDrawStream: Could not lock dcoDst");
goto exit;
}
xoDst.vQuickInit(dcoDst, WORLD_TO_DEVICE);
if(xoDst.bRotation())
{
WARNING("GreDrawStream: dcoDst has a rotation transform");
goto exit;
}
erclDstClip = cmd->rclDstClip;
xoDst.bXform(erclDstClip);
erclDstClip.vOrder();
if (dcoDst.fjAccum())
dcoDst.vAccumulate(erclDstClip);
pSurfDst = dcoDst.pSurface();
if (pSurfDst == NULL)
{
//WARNING("GreDrawStream: dcoDst has NULL pSurface\n");
goto exit;
}
palDst.ppalSet(pSurfDst->ppal());
palDstDC.ppalSet(dcoDst.ppal());
// we don't support monochrome destinations
if(palSrc.bIsMonochrome())
{
WARNING("GreDrawStream: palSrc.bIsMonochrome()");
goto exit;
}
bFoundTrg = TRUE;
}
break;
case DS_SETSOURCEID: // set source
{
if(pvPrimStart != NULL) goto drawStream;
dloSrc.vUnLock();
dcoSrc.vUnlock();
soSrc.vUnlock();
pSurfSrc = NULL;
DS_SETSOURCE * cmd = (DS_SETSOURCE *) pul;
commandSize = sizeof(*cmd);
if(cjIn < commandSize || !bFoundTrg)
{
WARNING("GreDrawStream: cjIn < commandSize || !bFoundTrg");
goto exit;
}
#if 0
// Old code to to allow source to be from HDC
// We might want to support this in the future (source from
// HDC)
dcoSrc.vLock(cmd->hdc);
if(!dcoSrc.bValid())
{
WARNING("GreDrawStream: source is invalid");
goto exit;
}
xoSrc.vQuickInit(dcoSrc, WORLD_TO_DEVICE);
if(!xoSrc.bIdentity())
{
WARNING("GreDrawStream: source transform is not identity");
goto exit;
}
if(!dloSrc.bLock(dcoSrc))
goto exit;
pSurfSrc = dcoSrc.pSurface();
ASSERTGDI(pSurfSrc != NULL, "GreDrawSteam: unexpected NULL source in valid DC\n");
// source must be different then target
if (pSurfSrc == pSurfDst)
goto exit;
if (!(pSurfSrc->bReadable() && (dcoDst.bDisplay() ? UserScreenAccessCheck() : TRUE)) &&
!((dcoSrc.bDisplay()) && ((dcoDst.bDisplay()) || UserScreenAccessCheck() )) )
{
WARNING("GreDrawStream: faild screena access check");
goto exit;
}
palSrcDC.ppalSet(dcoSrc.ppal());
#endif
soSrc.vLock((HSURF) ULongToHandle(cmd->hbm));
if(!soSrc.bValid())
{
WARNING("GreDrawStream: source is invalid");
goto exit;
}
pSurfSrc = soSrc.ps;
palSrcDC.ppalSet(ppalDefault);
palSrc.ppalSet(pSurfSrc->ppal());
if(!palSrc.bValid())
{
WARNING("GreDrawStream: source must have an associated palette");
goto exit;
}
if(palSrc.bIsMonochrome())
{
WARNING("GreDrawStream: monochrome sources are not supported");
goto exit;
}
// source must be different then target and 32bpp for now
if (pSurfSrc == pSurfDst || (pSurfSrc->iFormat() != BMF_32BPP))
{
WARNING("GreDrawStream: source and destination surfaces must differ or the source is not 32 Bpp");
goto exit;
}
//
// No ICM with BitBlt(), so pass NULL color transform to XLATEOBJ
//
if(!xlo.bInitXlateObj(NULL, // hColorTransform
dcoDst.pdc->lIcmMode(), // ICM mode
palSrc,
palDst,
palSrcDC,
palDstDC,
dcoDst.pdc->crTextClr(),
dcoDst.pdc->crBackClr(),
0))
{
WARNING("GreDrawStream: unable to initialize source to destination xlo");
goto exit;
}
pxlo = xlo.pxlo();
}
break;
case DS_NINEGRIDID:
{
commandSize = sizeof(DS_NINEGRID);
DS_NINEGRID * cmd = (DS_NINEGRID *) pul;
// validate nine grid
#define DSDNG_MASK 0x007F // move to wingdip.h
if(cmd->ngi.flFlags & ~DSDNG_MASK)
{
WARNING("GreDrawStream: unrecognized nine grid flags set");
goto exit;
}
if(pSurfSrc == NULL)
{
WARNING("GreDrawStream: source not set before nine grid command");
goto exit;
}
if(cmd->rclSrc.left < 0 || cmd->rclSrc.top < 0 ||
cmd->rclSrc.right > pSurfSrc->sizl().cx ||
cmd->rclSrc.bottom > pSurfSrc->sizl().cy)
{
WARNING("GreDrawStream: nine grid rclSrc not within bounds of source");
goto exit;
}
LONG lSrcWidth = cmd->rclSrc.right - cmd->rclSrc.left;
LONG lSrcHeight = cmd->rclSrc.bottom - cmd->rclSrc.top;
if(lSrcWidth <= 0 || lSrcHeight <= 0)
{
WARNING("GreDrawStream: nine grid rclSrc is not well ordered");
goto exit;
}
if(!(cmd->ngi.flFlags & DSDNG_TRUESIZE))
{
// NOTE: we have to check individual first then sum due to possible
// numerical overflows that could occur in the sum that might
// not be detected otherwise.
if(cmd->ngi.ulLeftWidth < 0 ||
cmd->ngi.ulRightWidth < 0 ||
cmd->ngi.ulTopHeight < 0 ||
cmd->ngi.ulBottomHeight < 0 ||
cmd->ngi.ulLeftWidth > lSrcWidth ||
cmd->ngi.ulRightWidth > lSrcWidth ||
cmd->ngi.ulTopHeight > lSrcHeight ||
cmd->ngi.ulBottomHeight > lSrcHeight ||
cmd->ngi.ulLeftWidth + cmd->ngi.ulRightWidth > lSrcWidth ||
cmd->ngi.ulTopHeight + cmd->ngi.ulBottomHeight > lSrcHeight)
{
WARNING("GreDrawStream: nine grid width is greater then rclSrc width or are negative");
goto exit;
}
}
if((cmd->ngi.flFlags & (DSDNG_TRANSPARENT | DSDNG_PERPIXELALPHA)) == (DSDNG_TRANSPARENT | DSDNG_PERPIXELALPHA))
{
WARNING("GreDrawStream: nine grid attempt to set both transparency and per pixel alpha");
goto exit;
}
if(cmd->ngi.flFlags & DSDNG_TRANSPARENT)
cmd->ngi.crTransparent = ulGetNearestIndexFromColorref(
palSrc,
palSrcDC,
cmd->ngi.crTransparent,
SE_DO_SEARCH_EXACT_FIRST
);
else if(cmd->ngi.flFlags & DSDNG_PERPIXELALPHA)
{
bAlphaBlendPresent = TRUE;
}
if(pvPrimStart == NULL)
{
pvPrimStart = (PVOID) pul;
erclDstBounds = cmd->rclDst;
}
else
erclDstBounds += cmd->rclDst;
}
break;
#if 0
case DS_BLTID:
{
commandSize = sizeof(DS_BLT);
DS_BLT * cmd = (DS_BLT *) pul;
if(cmd->flFlags & DSBLT_ALPHABLEND)
{
bAlphaBlendPresent = TRUE;
}
if(pvPrimStart == NULL)
{
pvPrimStart = (PVOID) pul;
erclDstBounds = cmd->rclDst;
}
else
erclDstBounds += cmd->rclDst;
}
break;
case DS_SETCOLORKEYID:
{
commandSize = sizeof(DS_SETCOLORKEY);
if(pvPrimStart == NULL) pvPrimStart = (PVOID) pul;
DS_SETCOLORKEY * cmd = (DS_SETCOLORKEY *) pul;
cmd->crColorKey = ulGetNearestIndexFromColorref(
palSrc,
palSrcDC,
cmd->crColorKey,
SE_DO_SEARCH_EXACT_FIRST
);
}
break;
case DS_SETBLENDID:
{
commandSize = sizeof(DS_SETBLEND);
if(pvPrimStart == NULL) pvPrimStart = (PVOID) pul;
DS_SETBLEND * cmd = (DS_SETBLEND *) pul;
}
break;
#endif
default:
goto exit;
}
cjIn -= commandSize;
pul += commandSize / 4;
if(cjIn == 0)
{
drawStream:
if(pvPrimStart != NULL && dcoDst.bValid() && pSurfSrc != NULL)
{
EXLATEOBJ xloSrcToBGRA;
EXLATEOBJ xloDstToBGRA;
EXLATEOBJ xloBGRAToDst;
dsi.dss.ulSize = sizeof(DRAWSTREAMINFO);
dsi.dss.crColorKey = 0;
dsi.dss.blendFunction.AlphaFormat = AC_SRC_ALPHA;
dsi.dss.blendFunction.BlendFlags = 0;
dsi.dss.blendFunction.SourceConstantAlpha = 255;
dsi.dss.blendFunction.BlendOp = AC_SRC_OVER;
dsi.bCalledFromBitBlt = FALSE;
dsi.dss.ptlSrcOrigin.x = 0;
dsi.dss.ptlSrcOrigin.y = 0;
if(bAlphaBlendPresent)
{
if(!xloSrcToBGRA.bInitXlateObj(
NULL,
DC_ICM_OFF,
palSrc,
palRGB,
palSrcDC,
palSrcDC,
0,
0,
0
))
{
WARNING("GreDrawStream: unable to initialize xloSrcToBGRA");
goto exit;
}
dsi.pxloSrcToBGRA = xloSrcToBGRA.pxlo();
if(!xloDstToBGRA.bInitXlateObj(
NULL,
DC_ICM_OFF,
palDst,
palRGB,
palDstDC,
palDstDC,
0,
0,
0
))
{
WARNING("GreDrawStream: unable to initialize xloDstToBGRA");
goto exit;
}
dsi.pxloDstToBGRA = xloDstToBGRA.pxlo();
if(!xloBGRAToDst.bInitXlateObj(
NULL,
DC_ICM_OFF,
palRGB,
palDst,
palDstDC,
palDstDC,
0,
0,
0
))
{
WARNING("GreDrawStream: unable to initialize xloBGRAToDst");
goto exit;
}
dsi.pxloBGRAToDst = xloBGRAToDst.pxlo();
}
else
{
dsi.pxloBGRAToDst = NULL;
dsi.pxloDstToBGRA = NULL;
dsi.pxloSrcToBGRA = NULL;
}
if(!NtGdiDrawStreamInternal(dcoDst, xoDst, pSurfSrc, pxlo,
(RECTL*) &erclDstClip,
(RECTL*) &erclDstBounds,
(LONG)((PBYTE) pul - (PBYTE) pvPrimStart),
(LPSTR) pvPrimStart,
&dsi))
{
//WARNING("GreDrawStream: NtGdiDrawStreamInternal failed\n");
goto exit;
}
pvPrimStart = NULL;
bAlphaBlendPresent = FALSE;
}
else
{
WARNING("GreDrawStream: !(pvPrimStart != NULL && dcoDst.bValid() && pSurfSrc != NULL)");
}
}
}
bRet = TRUE;
exit:
dcoDst.vUnlock();
dcoSrc.vUnlock();
return bRet;
}