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.
390 lines
14 KiB
390 lines
14 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: drawstream.c *
|
|
* *
|
|
* Client side draw stream support. Handles metafiling if primary *
|
|
* is a metafile. *
|
|
* *
|
|
* Created: 03-Mar-2001 *
|
|
* Author: Barton House [bhouse] *
|
|
* *
|
|
* Copyright (c) 1991-2001 Microsoft Corporation *
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
#pragma hdrstop
|
|
/******************************Public*Routine******************************\
|
|
* GdiDrawStream
|
|
*
|
|
*
|
|
* Arguments:
|
|
*
|
|
*
|
|
*
|
|
* Return Value:
|
|
*
|
|
*
|
|
*
|
|
* History:
|
|
*
|
|
* 3/21/2001 Barton House
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL
|
|
GdiDrawStream(
|
|
HDC hdcDst,
|
|
ULONG cjIn,
|
|
VOID *pvIn)
|
|
{
|
|
BOOL bRet = FALSE;
|
|
PDC_ATTR pdca;
|
|
|
|
FIXUP_HANDLE(hdcDst);
|
|
|
|
if (IS_ALTDC_TYPE(hdcDst))
|
|
{
|
|
HBITMAP hbmSource = NULL;
|
|
HRGN hrgnSaved = NULL;
|
|
HBITMAP hbmScratch = NULL;
|
|
HDC hdcScratch = NULL;
|
|
int iDstClip = -1;
|
|
ULONG * pul = (ULONG *) pvIn;
|
|
|
|
if(cjIn < sizeof(ULONG))
|
|
return FALSE;
|
|
|
|
if(*pul++ != 'DrwS')
|
|
return FALSE;
|
|
|
|
cjIn -= sizeof(ULONG);
|
|
|
|
while(cjIn >= sizeof(ULONG))
|
|
{
|
|
ULONG command = *pul;
|
|
ULONG commandSize;
|
|
RECTL rclDstClip;
|
|
|
|
switch(command)
|
|
{
|
|
case DS_SETTARGETID: // set target
|
|
{
|
|
DS_SETTARGET * cmd = (DS_SETTARGET *) pul;
|
|
|
|
commandSize = sizeof(*cmd);
|
|
|
|
if(cjIn < commandSize)
|
|
goto altExit;
|
|
|
|
if((HDC) ULongToHandle(cmd->hdc) != hdcDst)
|
|
{
|
|
// NOTE: This restriction is only in place for the
|
|
// initial implementation of GdiDrawStream.
|
|
|
|
WARNING("GdiDrawStream: target must match primary target");
|
|
goto altExit;
|
|
}
|
|
|
|
rclDstClip = cmd->rclDstClip;
|
|
|
|
if(hrgnSaved == NULL)
|
|
{
|
|
int iRet;
|
|
|
|
hrgnSaved = CreateRectRgn(0,0,0,0);
|
|
|
|
if(hrgnSaved == NULL)
|
|
{
|
|
WARNING("GdiDrawStream: unable to create saved region");
|
|
goto altExit;
|
|
}
|
|
|
|
iDstClip = GetClipRgn(hdcDst, hrgnSaved);
|
|
|
|
if(iDstClip == -1)
|
|
{
|
|
WARNING("GdiDrawStream: failed to get DC application clip");
|
|
goto altExit;
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
// need to restore target clip
|
|
|
|
if(iDstClip)
|
|
{
|
|
SelectClipRgn(hdcDst, hrgnSaved);
|
|
}
|
|
else
|
|
{
|
|
SelectClipRgn(hdcDst, NULL);
|
|
}
|
|
}
|
|
|
|
IntersectClipRect(hdcDst, rclDstClip.left, rclDstClip.top, rclDstClip.right, rclDstClip.bottom);
|
|
}
|
|
break;
|
|
|
|
case DS_SETSOURCEID: // set source
|
|
|
|
{
|
|
DS_SETSOURCE * cmd = (DS_SETSOURCE *) pul;
|
|
|
|
commandSize = sizeof(*cmd);
|
|
|
|
if(cjIn < commandSize)
|
|
goto altExit;
|
|
|
|
hbmSource = (HBITMAP) ULongToHandle(cmd->hbm);
|
|
|
|
}
|
|
break;
|
|
|
|
case DS_NINEGRIDID:
|
|
{
|
|
DS_NINEGRID * cmd = (DS_NINEGRID *) pul;
|
|
LONG lSrcWidth = cmd->rclSrc.right - cmd->rclSrc.left;
|
|
LONG lSrcHeight = cmd->rclSrc.bottom - cmd->rclSrc.top;
|
|
LONG lDstWidth = cmd->rclDst.right - cmd->rclDst.left;
|
|
LONG lDstHeight = cmd->rclDst.bottom - cmd->rclDst.top;
|
|
BOOL bRenderRet;
|
|
RECTL rclDst = cmd->rclDst;
|
|
|
|
struct {
|
|
BITMAPINFOHEADER bmih;
|
|
ULONG masks[3];
|
|
} bmi;
|
|
|
|
struct {
|
|
DS_HEADER hdr;
|
|
DS_SETTARGET setTarget;
|
|
DS_SETSOURCE setSource;
|
|
DS_NINEGRID ng;
|
|
} scratchStream;
|
|
|
|
RECTL rclScratch;
|
|
|
|
commandSize = sizeof(DS_NINEGRID);
|
|
|
|
// validate nine grid
|
|
|
|
#define DSDNG_MASK 0x007F // move to wingdip.h
|
|
|
|
if(cmd->ngi.flFlags & ~DSDNG_MASK)
|
|
{
|
|
WARNING("GreDrawStream: unrecognized nine grid flags set\n");
|
|
goto altExit;
|
|
}
|
|
|
|
if(lSrcWidth < 0 || lSrcHeight < 0)
|
|
{
|
|
WARNING("GreDrawStream: nine grid rclSrc is not well ordered\n");
|
|
goto altExit;
|
|
}
|
|
|
|
if(cmd->ngi.flFlags & DSDNG_TRUESIZE)
|
|
{
|
|
if(lDstWidth > lSrcWidth)
|
|
{
|
|
lDstWidth = lSrcWidth;
|
|
rclDst.right = rclDst.left + lDstWidth;
|
|
}
|
|
|
|
if(lDstHeight > lSrcHeight)
|
|
{
|
|
lDstHeight = lSrcHeight;
|
|
rclDst.bottom = rclDst.top + lDstHeight;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// 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 negative\n");
|
|
goto altExit;
|
|
}
|
|
}
|
|
|
|
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\n");
|
|
goto altExit;
|
|
}
|
|
|
|
// create temporary to render nine grid into
|
|
|
|
bmi.bmih.biSize = sizeof(bmi.bmih);
|
|
bmi.bmih.biWidth = lDstWidth;
|
|
bmi.bmih.biHeight = lDstHeight;
|
|
bmi.bmih.biPlanes = 1;
|
|
bmi.bmih.biBitCount = 32;
|
|
bmi.bmih.biCompression = BI_BITFIELDS;
|
|
bmi.bmih.biSizeImage = 0;
|
|
bmi.bmih.biXPelsPerMeter = 0;
|
|
bmi.bmih.biYPelsPerMeter = 0;
|
|
bmi.bmih.biClrUsed = 3;
|
|
bmi.bmih.biClrImportant = 0;
|
|
bmi.masks[0] = 0xff0000; // red
|
|
bmi.masks[1] = 0x00ff00; // green
|
|
bmi.masks[2] = 0x0000ff; // blue
|
|
|
|
if(hbmScratch != NULL)
|
|
DeleteObject(hbmScratch);
|
|
|
|
hbmScratch = CreateDIBitmap(hdcDst, &bmi.bmih, CBM_CREATEDIB , NULL, (BITMAPINFO*)&bmi.bmih, DIB_RGB_COLORS);
|
|
|
|
if(hbmScratch == NULL)
|
|
{
|
|
WARNING("GdiDrawStream: unable to create temporary\n");
|
|
goto altExit;
|
|
}
|
|
|
|
if(hdcScratch == NULL)
|
|
{
|
|
hdcScratch = CreateCompatibleDC(hdcDst);
|
|
|
|
if(hdcScratch == NULL)
|
|
{
|
|
WARNING("GdiDrawStream: unable to create temporary dc\n");
|
|
goto altExit;
|
|
}
|
|
}
|
|
|
|
SelectObject(hdcScratch, hbmScratch);
|
|
|
|
rclScratch.left = 0;
|
|
rclScratch.top = 0;
|
|
rclScratch.right = lDstWidth;
|
|
rclScratch.bottom = lDstHeight;
|
|
|
|
scratchStream.hdr.magic = DS_MAGIC;
|
|
scratchStream.setTarget.ulCmdID = DS_SETTARGETID;
|
|
scratchStream.setTarget.hdc = HandleToULong(hdcScratch);
|
|
scratchStream.setTarget.rclDstClip = rclScratch;
|
|
scratchStream.setSource.ulCmdID = DS_SETSOURCEID;
|
|
scratchStream.setSource.hbm = HandleToULong(hbmSource);
|
|
scratchStream.ng.ulCmdID = DS_NINEGRIDID;
|
|
scratchStream.ng.rclDst = rclScratch;
|
|
scratchStream.ng.rclSrc = cmd->rclSrc;
|
|
scratchStream.ng.ngi = cmd->ngi;
|
|
scratchStream.ng.ngi.flFlags &= ~(DSDNG_TRANSPARENT | DSDNG_PERPIXELALPHA);
|
|
|
|
NtGdiDrawStream(hdcScratch, sizeof(scratchStream), &scratchStream);
|
|
|
|
if(cmd->ngi.flFlags & DSDNG_TRANSPARENT)
|
|
{
|
|
bRenderRet = GdiTransparentBlt(hdcDst,
|
|
rclDst.left,
|
|
rclDst.top,
|
|
lDstWidth,
|
|
lDstHeight,
|
|
hdcScratch,
|
|
0,
|
|
0,
|
|
lDstWidth,
|
|
lDstHeight,
|
|
cmd->ngi.crTransparent);
|
|
}
|
|
else if(cmd->ngi.flFlags & DSDNG_PERPIXELALPHA)
|
|
{
|
|
// alpha blend
|
|
BLENDFUNCTION bfx;
|
|
|
|
bfx.AlphaFormat = AC_SRC_ALPHA;
|
|
bfx.BlendFlags = 0;
|
|
bfx.BlendOp = AC_SRC_OVER;
|
|
bfx.SourceConstantAlpha = 255;
|
|
|
|
bRenderRet = GdiAlphaBlend(hdcDst,
|
|
rclDst.left,
|
|
rclDst.top,
|
|
lDstWidth,
|
|
lDstHeight,
|
|
hdcScratch,
|
|
0,
|
|
0,
|
|
lDstWidth,
|
|
lDstHeight,
|
|
bfx);
|
|
}
|
|
else
|
|
{
|
|
// bitblt
|
|
|
|
bRenderRet = BitBlt(hdcDst,
|
|
rclDst.left,
|
|
rclDst.top,
|
|
lDstWidth,
|
|
lDstHeight,
|
|
hdcScratch,
|
|
0,
|
|
0,
|
|
SRCCOPY);
|
|
}
|
|
|
|
if(!bRenderRet)
|
|
{
|
|
WARNING("GdiDrawStream: failed to render temporary to destination");
|
|
goto altExit;
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
WARNING("GdiDrawStream: unrecognized command");
|
|
goto altExit;
|
|
}
|
|
|
|
pul += commandSize / sizeof(ULONG);
|
|
cjIn -= commandSize;
|
|
|
|
}
|
|
|
|
bRet = TRUE;
|
|
|
|
altExit:
|
|
|
|
if(iDstClip == 1)
|
|
{
|
|
SelectClipRgn(hdcDst, hrgnSaved);
|
|
}
|
|
else if(iDstClip == 0)
|
|
{
|
|
SelectClipRgn(hdcDst, NULL);
|
|
}
|
|
|
|
if(hbmScratch != NULL)
|
|
DeleteObject(hbmScratch);
|
|
|
|
if(hdcScratch != NULL)
|
|
DeleteDC(hdcScratch);
|
|
|
|
if(hrgnSaved != NULL)
|
|
DeleteObject(hrgnSaved);
|
|
|
|
return bRet;
|
|
}
|
|
|
|
RESETUSERPOLLCOUNT();
|
|
|
|
bRet = NtGdiDrawStream(
|
|
hdcDst,
|
|
cjIn,
|
|
pvIn);
|
|
return(bRet);
|
|
}
|
|
|
|
|