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