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
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;
|
|
}
|
|
|