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

2519 lines
71 KiB

/******************************Module*Header*******************************\
* Module Name:
*
* bltlnk.cxx
*
* Abstract
*
* This module does general bit blt functions for 1,4,8,16,24,and 32 bpp
* DIB format bitmaps. SrcBltxx routines are used to align and copy data.
*
* Author:
*
* Mark Enstrom (marke) 9-27-93
*
* Copyright (c) 1993-1999 Microsoft Corporation
\**************************************************************************/
#include "precomp.hxx"
PVOID pvGetEngRbrush(BRUSHOBJ *pbo);
extern PFN_SRCCPY SrcCopyFunctionTable[];
PFN_BLTLNKROP RopFunctionTable[] = {
vRop2Function0,vRop2Function1,vRop2Function2,vRop2Function3,
vRop2Function4,vRop2Function5,vRop2Function6,vRop2Function7,
vRop2Function8,vRop2Function9,vRop2FunctionA,vRop2FunctionB,
vRop2FunctionC,vRop2FunctionD,vRop2FunctionE,vRop2FunctionF
};
#define DBG_BLTLNK 0
#if DBG_BLTLNK
ULONG DbgBltLnk = 0;
#endif
#define SCAN_LINE_BUFFER_LENGTH 64
/******************************Public*Routine******************************\
*
* Routine Name
*
* BltLnk
*
* Routine Description:
*
* BltLnk prepares all parameters then breaks the BitBlt region into
* rectangles based on clip information. Each rect is sent to BltLnkRect
* for operation.
*
* Arguments:
*
* pdioDst - Destination surface information
* pdioSrc - Source surface information
* pdioMsk - Mask information
* pco - Clip Object
* pxlo - Color translation object
* prclDst - Destination rectangle
* pptlSrc - Source Starting offset point
* pptlMsk - Mask Starting offset point
* pdbrush - Brush Information
* pptlBrush - Brush Starting offset point
* rop4 - Logical Raster Operation
*
* Return Value:
*
* BOOLEAN Status
*
\**************************************************************************/
BOOL
BltLnk(
SURFACE *pdioDst, // Target surface
SURFACE *pdioSrc, // Source surface
SURFACE *pdioMsk, // Msk
ECLIPOBJ *pco, // Clip through this
XLATE *pxlo, // Color translation
RECTL *prclDst, // Target offset and extent
POINTL *pptlSrc, // Source offset
POINTL *pptlMsk, // Msk offset
BRUSHOBJ *pdbrush, // Brush data (from cbRealizeBrush)
POINTL *pptlBrush, // Brush offset (origin)
ROP4 rop4) // Raster operation
{
BOOL bMore;
ULONG ircl;
LONG MaxWidth;
BLTLNKINFO bltInfo;
CLIPENUMRECT clenr;
BYTE Rop3Low;
BYTE Rop3High;
BYTE RopSrcLow;
BYTE RopSrcHigh;
BYTE RopDstLow;
BYTE RopDstHigh;
BOOL bNeedMsk = FALSE;
BOOL bNeedPat = FALSE;
BOOL bNeedSrc = FALSE;
BOOL bNeedDst = FALSE;
BOOL bNeedPatLow = FALSE;
BOOL bNeedSrcLow = FALSE;
BOOL bNeedDstLow = FALSE;
BOOL bNeedPatHigh = FALSE;
BOOL bNeedSrcHigh = FALSE;
BOOL bNeedDstHigh = FALSE;
BOOL bLocalAlloc = FALSE;
SURFMEM SurfDimo;
PENGBRUSH pBrush = NULL;
#if DBG_BLTLNK
if (DbgBltLnk >= 1)
{
DbgPrint("BltLnk: rop4 = %lx\n",rop4);
DbgPrint("pdioDst = 0x%p\n",pdioDst);
DbgPrint("pdioSrc = 0x%p\n",pdioSrc);
DbgPrint(" Destination Format = %li\n",pdioDst->iFormat());
DbgPrint(" prclDst = %li,%li to %li,%li\n",
prclDst->left,
prclDst->top,
prclDst->right,
prclDst->bottom);
}
#endif
//
// make sure destination format is not a device format or
// unknown format
//
ASSERTGDI(pdioDst->iFormat() != 0, "ERROR device dst format in BltLnk\n");
ASSERTGDI(pdioDst->iFormat() <= 7, "ERROR invalid dst format in BltLnk\n");
//
// check rectangle bounds
//
ASSERTGDI(prclDst->left < prclDst->right, "ERROR prclDst->left < right");
ASSERTGDI(prclDst->top < prclDst->bottom, "ERROR prclDst->top < bottom");
//
// calculate the widest blt using based on the width of scan line storage
//
// These numbers assume worst case unaligned transfers
//
switch(pdioDst->iFormat())
{
case BMF_1BPP:
MaxWidth = (SCAN_LINE_BUFFER_LENGTH << 5) -62;
break;
case BMF_4BPP:
MaxWidth = (SCAN_LINE_BUFFER_LENGTH << 3) -14;
break;
case BMF_8BPP:
MaxWidth = (SCAN_LINE_BUFFER_LENGTH << 2) -6;
break;
case BMF_16BPP:
MaxWidth = (SCAN_LINE_BUFFER_LENGTH << 1) -2;
break;
case BMF_24BPP:
MaxWidth = ((SCAN_LINE_BUFFER_LENGTH * 4) / 3) - 2;
break;
case BMF_32BPP:
MaxWidth = SCAN_LINE_BUFFER_LENGTH;
break;
}
//
// set bltInfo params
//
if (pxlo == NULL)
{
bltInfo.pxlo = &xloIdent;
}
else
{
bltInfo.pxlo = pxlo;
}
bltInfo.pdioDst = pdioDst;
bltInfo.pdioSrc = pdioSrc;
bltInfo.pco = (ECLIPOBJ *)pco;
bltInfo.rclDst = *prclDst;
bltInfo.pdbrush = (EBRUSHOBJ *) pdbrush;
//
// rop4 is a logical combination of Src,Dst,Pattern,Mask
//
// rop4[15:08] represents the rop3 used when Mask is high
// rop4[07:00] represents the rop3 used when Mask is low
//
// When rop4[15:08] == rop4[07:00], this indicates that no mask
// is needed for the operation.
//
// rop3 [07:04] represents the rop2 to be used is pattern is high
// rop3 [03:00] represents the rop2 to be used is pattern is low
//
// when rop3[07:04] == rop3[03:00], this indicates that no pattern
// is needed for the operation.
//
// By exchanging Src and Dst with Pattern and Mask, it is possible
// to compare rop4s to also determine is Src and Dst are needed for
// the logical operation. BltLnk does this below.
//
// A rop2 represents 16 different ways 2 variables may be combined, this
// is the basic logic element used in BltLnk.
//
// As an example of logic reduction rop4 = B8B8 would
// immediatly reduce to a rop3 because rop4[15:08] == rop4[07:00]. This
// leaves rop3 = B8. This is expressed as a Karnaugh map as:
//
//
// PS 00 01 11 10
// ÚÄÄÂÄÄÂÄÄÂÄÄ¿
// D 0³ 0³ 0³ 0³ 1³
// ÃÄÄÅÄÄÅÄÄÅÄÄ´
// 1³ 0³ 1³ 1³ 1³
// ÀÄÄÁÄÄÁÄÄÁÄÄÙ
// This reduces to a logic operation of Dst = (Pat & ~Src) | (Dst & Src)
//
// This is a special case rop handled by unique functions, but in gereral BltLnk
// will handle a rop like this by reducing it to functions of rop2s, in this case
//
// Pat and (Src and Dst) OR ~pat and (~Src or Dst)
//
// BltLnk will always try to manipulate the variables so that a rop2
// function may be performed directly. If this is not possible, a rop3
// functions is broken into 2 rop2 functions, one for pat=high and one
// for pat = low. (or mask in a rop3 in which pat is not needed but mask is)
// For a full rop4, two rop 3 passes are made, one for mask = high and
// one for mask = low.
//
// Actual Mask Blt, rop4 = AACC is handled by a special case accelerator.
//
// Masked Solid fill (Src = 1bpp mask), rop4 = B8B8 is also handled by a
// special case accelerator.
//
Rop3Low = (BYTE)(rop4 & 0xff);
Rop3High = (BYTE)(rop4 >> 8);
RopSrcLow = (Rop3Low & 0xC3) | ((Rop3Low & 0x0C) << 2) | ((Rop3Low & 0x30) >> 2);
RopDstLow = (Rop3Low & 0xA5) | ((Rop3Low & 0x0A) << 3) | ((Rop3Low & 0x50) >> 3);
RopSrcHigh = (Rop3High & 0xC3)|((Rop3High & 0x0C) << 2)|((Rop3High & 0x30) >> 2);
RopDstHigh = (Rop3High & 0xA5)|((Rop3High & 0x0A) << 3)|((Rop3High & 0x50) >> 3);
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint (" RopSrcLow = %lx, RopDstLow = %lx\n",
RopSrcLow,RopDstLow);
DbgPrint (" RopSrcHigh = %lx, RopDstHigh = %lx\n",
RopSrcHigh,RopDstHigh);
}
#endif
//
// if rop4[15:08] = rop4[07:00] then no mask is needed
//
if ((rop4 & 0xff) != ((rop4) >> 8))
{
bNeedMsk = TRUE;
}
//
// if Rop3Low[7:4] = Rop3Low[3:0] and
// if Rop3High[7:4] = Rop3High[3:0] Then no pat is needed
//
if ((Rop3Low & 0x0f) != ((Rop3Low & 0xf0) >> 4))
{
bNeedPatLow = TRUE;
}
if ((Rop3High & 0x0f) != ((Rop3High & 0xf0) >> 4))
{
bNeedPatHigh = TRUE;
}
bNeedPat = bNeedPatLow || bNeedPatHigh;
//
// if RopSrcLow[7:4] = RopSrcLow[3:0] and
// if RopSrcHigh[7:4] = RopSrcHigh[3:0] Then no src is needed
//
if ((RopSrcLow & 0x0F) != ((RopSrcLow & 0xF0) >> 4))
{
bNeedSrcLow = TRUE;
}
if ((RopSrcHigh & 0x0F) != ((RopSrcHigh & 0xF0) >> 4))
{
bNeedSrcHigh = TRUE;
}
bNeedSrc = bNeedSrcLow || bNeedSrcHigh;
//
// if RopDstLow[7:4] = RopDstLow[3:0] and
// if RopDstHigh[7:4] = RopDstHigh[3:0] Then no Dst is needed
//
if (((RopDstLow & 0x0f) != ((RopDstLow & 0xF0) >> 4)))
{
bNeedDstLow = TRUE;
}
if (((RopDstHigh & 0x0f) != ((RopDstHigh & 0xF0) >> 4)))
{
bNeedDstHigh = TRUE;
}
bNeedDst = bNeedDstHigh || bNeedDstLow;
//
// get the brush realization if we'll need it. This is either
// when the rop specifies a pattern is needed or when the rop specifies
// that a mask is needed but no mask is passed in, meaning the mask
// must be taken from the brush
//
if ((bNeedPat) || (bNeedMsk && (pdioMsk == (SURFACE*) NULL)))
{
if ((pdbrush != NULL) && (pdbrush->iSolidColor == -1))
{
pBrush = (PENGBRUSH) pvGetEngRbrush(pdbrush);
}
else
{
pBrush = (PENGBRUSH) pdbrush;
}
}
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" pBrush = %p\n",pBrush);
DbgPrint(" bNeedMsk = %x\n",bNeedMsk);
DbgPrint(" bNeedPat = %x\n",bNeedPat);
DbgPrint(" bNeedSrc = %x\n",bNeedSrc);
DbgPrint(" bNeedDst = %x\n",bNeedDst);
}
#endif
//
// Compute the direction of clipping enumeration
//
bltInfo.xDir = bltInfo.yDir = 1L;
bltInfo.iDir = CD_ANY;
//
// Get clip rectangle enumeration and directions set up. BltLnkRect
// always performs blt operations left to right using a temp
// scan line buffer.
// xDir is set to 1 or -1 as a flag
// for accelerators to not accelerate a special case if xDir < 0
//
if (bNeedSrc)
{
ASSERTGDI(pdioSrc != (SURFACE*) NULL, "ERROR: Bltlnk: no pdioSrc");
//
// fill out bltinfo for calls to BltLnkRect
//
bltInfo.pjSrc = (PBYTE) pdioSrc->pvScan0();
bltInfo.lDeltaSrc = pdioSrc->lDelta();
bltInfo.xSrcOrg = pptlSrc->x;
bltInfo.ySrcOrg = pptlSrc->y;
#if DBG_BLTLNK
if (DbgBltLnk >= 1) {
DbgPrint(" Src Format = %li\n",pdioSrc->iFormat());
DbgPrint(" Src Point = %li,%li\n",pptlSrc->x,pptlSrc->y);
}
if (DbgBltLnk >= 2)
{
DbgPrint(" pjSrc = %p, lDeltaSrc = %li\n",
bltInfo.pjSrc,bltInfo.lDeltaSrc);
DbgPrint(" xSrcOrg = %li, ySrcOrg = %li\n",
bltInfo.xSrcOrg,bltInfo.ySrcOrg);
}
#endif
//
// Only BLT bottom to top if the source and destination are on the
// same surface and the Dst is below the Src.
//
// ÚÄÄÄÄÄÄÄ¿
// ÚÄÄÄijSrc ³
// ³Dst ³ ³
// ³ ³ ³
// ³ ÀÄÄÄÄÄÄÄÙ
// ÀÄÄÄÄÄÄÄÙ
//
// Also check if it is the same surface for BLTs that must be
// done right to left. This is a case where the starting scan
// lines for Src and Dst are the same and the Src is to the
// left of the dst. We do this by comparing the pvScan0 pointers.
// The reason is that if we were to compare surface pointers or
// handles this won't work on some drivers that punt this call
// to GDI but pass us different SURFOBJs for the source and
// destination even when they're really the same surface.
//
// ÚÄÄÄÄÚÄÄÄÄÄÄÄ¿
// ³Src ³Dst ³
// ³ ³ ³
// ³ ³ ³
// ÀÄÄÄÄÀÄÄÄÄÄÄÄÙ
//
if (pdioSrc->pvScan0() == pdioDst->pvScan0())
{
if (pptlSrc->y < prclDst->top)
{
bltInfo.yDir = -1;
bltInfo.iDir = CD_RIGHTUP;
}
//
// check if:
//
// Src scan line = Dst Scan line AND Src < Dst
// and width > Scan line buffer
// OR
// MaskBlt needing Src for RopHigh and RopLow
// AND Src and Dst rect intersect
//
if ((pptlSrc->y == prclDst->top) &&
(pptlSrc->x < prclDst->left))
{
//
// This blt requires right to left operation. This will
// disable special accelerators in BltLnkRect.
//
bltInfo.xDir = -1;
}
//
// cases requiring temp Src:
//
if (
(bNeedMsk && bNeedSrcLow && bNeedSrcHigh) ||
(
((bltInfo.xDir == -1) || (bltInfo.yDir == -1)) &&
((prclDst->right - prclDst->left) > MaxWidth)
)
)
{
//
// create a temp src surface of width prclDst->right - prclDst->left
// and height prclDst->bottom - prclDst->top
//
DEVBITMAPINFO dbmi;
dbmi.iFormat = pdioSrc->iFormat();
dbmi.cxBitmap = prclDst->right - prclDst->left;
dbmi.cyBitmap = prclDst->bottom - prclDst->top;
dbmi.hpal = (HPALETTE) 0;
dbmi.fl = BMF_TOPDOWN;
SurfDimo.bCreateDIB(&dbmi, (PVOID) NULL);
if (!SurfDimo.bValid())
{
//
// (common return?)
//
return(FALSE);
}
//
// fill DIB with data from actual Src
//
POINTL ptlSrc;
ptlSrc.x = pptlSrc->x;
ptlSrc.y = pptlSrc->y;
RECTL rclDst;
rclDst.left = 0;
rclDst.right = dbmi.cxBitmap;
rclDst.top = 0;
rclDst.bottom = dbmi.cyBitmap;
if (!EngCopyBits(SurfDimo.pSurfobj(),
pdioSrc->pSurfobj(),
(CLIPOBJ *)NULL,
&xloIdent,
&rclDst,
&ptlSrc)
)
{
//
// return error
//
return(FALSE);
}
//
// fill in new Src info for BltLnkRect
//
bltInfo.pjSrc = (PBYTE) SurfDimo.ps->pvScan0();
bltInfo.lDeltaSrc = SurfDimo.ps->lDelta();
bltInfo.xSrcOrg = 0;
bltInfo.ySrcOrg = 0;
#if DBG_BLTLNK
if (DbgBltLnk >= 1) {
DbgPrint(" Allocate temp buffer: pjSrc = 0x%p\n",bltInfo.pjSrc);
DbgPrint(" lDeltaSrc = 0x%lx, SrcOrg = (0,0)\n",bltInfo.lDeltaSrc);
}
#endif
}
}
//
// set DeltaSrcDir based on yDir
//
if (bltInfo.yDir == 1)
{
bltInfo.lDeltaSrcDir = bltInfo.lDeltaSrc;
} else {
bltInfo.lDeltaSrcDir = -bltInfo.lDeltaSrc;
}
} else {
//
// no src to worry about
//
bltInfo.pjSrc = (PBYTE) NULL;
}
//
// Set up the destination information in bltInfo based on +/- yDir
//
// pjDst points to the upper left corner of the dest bitmap
//
// lDeltaDst is the number of (bytes) from one scan line to the next
//
bltInfo.pjDst = (PBYTE) pdioDst->pvScan0();
bltInfo.lDeltaDst = pdioDst->lDelta();
if (bltInfo.yDir == 1)
{
bltInfo.lDeltaDstDir = bltInfo.lDeltaDst;
} else {
bltInfo.lDeltaDstDir = -bltInfo.lDeltaDst;
}
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" pjDst = %p, lDeltaDst = %li\n",bltInfo.pjDst,bltInfo.lDeltaDst);
}
#endif
//
// Set up the Mask
//
if (!bNeedMsk || (pdioMsk == (SURFACE*) NULL))
{
//
// no mask to deal with
//
bltInfo.pdioMsk = (SURFACE*) NULL;
bltInfo.pjMsk = (PBYTE) NULL;
} else {
ASSERTGDI(pdioMsk->iType() == STYPE_BITMAP, "ERROR: BltLnk: Mask is not STYPE_BITMAP\n");
ASSERTGDI(pdioMsk->iFormat() == BMF_1BPP, "ERROR: BltLnk: Mask not 1Bpp\n");
ASSERTGDI(pptlMsk->x >= 0, "Illegal mask offset x\n");
ASSERTGDI(pptlMsk->y >= 0, "Illegal mask offset y\n");
//
// info for BltLnkRect
//
bltInfo.pdioMsk = pdioMsk;
bltInfo.pjMsk = (PBYTE) pdioMsk->pvScan0();
bltInfo.cxMsk = (pdioMsk->sizl()).cx;
bltInfo.cyMsk = (pdioMsk->sizl()).cy;
bltInfo.xMskOrg = pptlMsk->x;
bltInfo.yMskOrg = pptlMsk->y;
//
// Normalize mask x
//
if (bltInfo.xMskOrg >= (LONG)bltInfo.cxMsk)
{
bltInfo.xMskOrg %= bltInfo.cxMsk;
} else {
if (bltInfo.xMskOrg < 0)
{
bltInfo.xMskOrg = (bltInfo.cxMsk - 1) -
((-bltInfo.xMskOrg - 1) % bltInfo.cxMsk);
}
}
//
// Normalize Mask y
//
if (bltInfo.yMskOrg >= (LONG)bltInfo.cyMsk)
{
bltInfo.yMskOrg %= bltInfo.cyMsk;
} else {
if (bltInfo.yMskOrg < 0)
{
bltInfo.yMskOrg = (bltInfo.cyMsk - 1) -
((-bltInfo.yMskOrg - 1) % bltInfo.cyMsk);
}
}
//
// Scan line offsets
//
bltInfo.lDeltaMsk = pdioMsk->lDelta();
if (bltInfo.yDir == 1)
{
bltInfo.lDeltaMskDir = bltInfo.lDeltaMsk;
} else {
bltInfo.lDeltaMskDir = -bltInfo.lDeltaMsk;
}
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" pjMask = %p\n",bltInfo.pjMsk);
DbgPrint(" cxMask = %li\n",bltInfo.cxMsk);
DbgPrint(" cyMask = %li\n",bltInfo.cyMsk);
DbgPrint(" xMskOrg = %li\n",bltInfo.xMskOrg);
DbgPrint(" yMskOrg = %li\n",bltInfo.yMskOrg);
DbgPrint(" yMskDelta = %li\n",bltInfo.lDeltaMsk);
}
#endif
}
//
// Set up the pat and possibly the mask if a mask is included in pat
//
if (!bNeedPat)
{
//
// no Pat in this Blt
//
bltInfo.pjPat = (PBYTE) NULL;
} else {
//
// check for valid brush pointer
//
if (pdbrush == (BRUSHOBJ *) NULL) {
RIP("ERROR BltLnk brush Null");
return(FALSE);
}
ircl = pdbrush->iSolidColor;
//
// check for solid color of 0xffffffff... this indicates
// a real brush, not a solid color
//
if (ircl == 0xFFFFFFFF)
{
if (pBrush != (PENGBRUSH) NULL)
{
bltInfo.iSolidColor = ircl;
//
// Could have a brush that just has mask information.
//
if (pBrush->pjPat != (PBYTE) NULL)
{
//
// fill in Pat info for BltLnkrect
//
bltInfo.lDeltaPat = pBrush->lDeltaPat;
bltInfo.pjPat = pBrush->pjPat;
bltInfo.cxPat = pBrush->cxPat;
bltInfo.cyPat = pBrush->cyPat;
bltInfo.xPatOrg = pptlBrush->x;
bltInfo.yPatOrg = pptlBrush->y;
if (bltInfo.yDir == 1)
{
bltInfo.lDeltaPatDir = bltInfo.lDeltaPat;
} else {
bltInfo.lDeltaPatDir = -bltInfo.lDeltaPat;
}
}
} else {
//
// routine failed due to brush, return
//
return(FALSE);
}
} else {
//
// Set pjPat to Null.
//
bltInfo.pjPat = (PBYTE) NULL;
//
// Build iSolidColor into a 32 bit quantity
//
// Note cascaded fall through on switch to build up iColor.
//
switch(pdioDst->iFormat())
{
case BMF_1BPP:
if (ircl) {
ircl = 0xFFFFFFFF;
}
break;
case BMF_4BPP:
ircl = ircl | (ircl << 4);
case BMF_8BPP:
ircl = ircl | (ircl << 8);
case BMF_16BPP:
ircl = ircl | (ircl << 16);
}
bltInfo.iSolidColor = ircl;
}
}
//
// Check if there is a mask with this brush. The Mask passed
// in with the call takes precedence over the brush mask.
//
if ((bNeedMsk) &&
(bltInfo.pjMsk == (PBYTE) NULL) &&
(pBrush != (PENGBRUSH) NULL) &&
(pBrush->pjMsk != (PBYTE) NULL))
{
bltInfo.pjMsk = pBrush->pjMsk;
bltInfo.cxMsk = pBrush->cxMsk;
bltInfo.cyMsk = pBrush->cyMsk;
bltInfo.lDeltaMsk = pBrush->lDeltaMsk;
bltInfo.xMskOrg = prclDst->left - pptlBrush->x;
bltInfo.yMskOrg = prclDst->top - pptlBrush->y;
//
// Normalize Mask x
//
if (bltInfo.xMskOrg >= (LONG)bltInfo.cxMsk)
{
bltInfo.xMskOrg %= bltInfo.cxMsk;
} else {
if (bltInfo.xMskOrg < 0)
{
bltInfo.xMskOrg = (bltInfo.cxMsk-1) -
((-bltInfo.xMskOrg-1) % bltInfo.cxMsk);
}
}
//
// Normalize Mask y
//
if (bltInfo.yMskOrg >= (LONG)bltInfo.cyMsk)
{
bltInfo.yMskOrg %= bltInfo.cyMsk;
} else {
if (bltInfo.yMskOrg < 0)
{
bltInfo.yMskOrg = (bltInfo.cyMsk-1) -
((-bltInfo.yMskOrg-1) % bltInfo.cyMsk);
}
}
//
// set sign on lDeltaMask based on a bottom to top or
// top to bottom blt
//
if (bltInfo.yDir == 1)
{
bltInfo.lDeltaMskDir = bltInfo.lDeltaMsk;
} else {
bltInfo.lDeltaMskDir = -bltInfo.lDeltaMsk;
}
}
//
// make sure that if a mask is specified by the rop ,then a mask is available
//
if (bNeedMsk && (bltInfo.pjMsk == (PBYTE)NULL)) {
RIP("ERROR: Bltlnk: ROP specifies mask but mask is null");
return(FALSE);
}
//
// set up clipping boundaries and call blt routine for each rect
//
if (pco != (CLIPOBJ *) NULL)
{
switch(pco->iDComplexity)
{
case DC_TRIVIAL:
//
// use the target for clipping
//
bMore = FALSE;
clenr.c = 1;
clenr.arcl[0] = *prclDst;
break;
case DC_RECT:
//
// use the bounding rect for clipping
//
bMore = FALSE;
clenr.c = 1;
clenr.arcl[0] = pco->rclBounds;
break;
case DC_COMPLEX:
//
// set up clipping enumeration
//
bMore = TRUE;
((ECLIPOBJ *) pco)->cEnumStart(FALSE,CT_RECTANGLES,bltInfo.iDir,CLIPOBJ_ENUM_LIMIT);
break;
default:
RIP("ERROR: BltLnk - bad clipping type");
return (FALSE);
}
} else {
//
// use target for clipping
//
bMore = FALSE;
clenr.c = 1;
clenr.arcl[0] = *prclDst;
}
//
// blt each rect
//
do
{
if (bMore)
{
bMore = ((ECLIPOBJ *) pco)->bEnum(sizeof(clenr), (PVOID) &clenr);
}
for (ircl = 0; ircl < clenr.c; ircl++)
{
PRECTL prcl = &clenr.arcl[ircl];
if (prcl->left < prclDst->left) {
prcl->left = prclDst->left;
}
if (prcl->right > prclDst->right){
prcl->right = prclDst->right;
}
if (prcl->top < prclDst->top) {
prcl->top = prclDst->top;
}
if (prcl->bottom > prclDst->bottom){
prcl->bottom = prclDst->bottom;
}
//
// We check for NULL or inverted rectanges because we may get them.
//
if (prcl->top < prcl->bottom)
{
ASSERTGDI(prcl->top >= 0, "ERROR prcl->top >= 0");
ASSERTGDI(prcl->left >= 0, "ERROR prcl->left >= 0");
//
// call BltLnkRect once for each vertical stripe that has width <=
// to the size of the temporary scan line storage
//
// ulong count = (prcl->right - prcl->left)/(pixels per ulong) + 1;
//
while ((prcl->right - prcl->left) > 0)
{
RECTL TempRect;
TempRect.left = prcl->right;
TempRect.right = prcl->right;
if (!bLocalAlloc) {
if ((prcl->right - prcl->left) > MaxWidth)
{
prcl->right = prcl->left + MaxWidth;
TempRect.left = prcl->right;
}
}
//
// if there is a mask, 2 passes will be required, one with negative
// mask using the Rop3Low and then once with a positive mask flag
// using Rop3High
//
if (Rop3Low != 0xAA)
{
bltInfo.rop3 = Rop3Low;
bltInfo.RopSrc = RopSrcLow;
bltInfo.RopDst = RopDstLow;
bltInfo.bNeedSrc = bNeedSrcLow;
bltInfo.bNeedDst = bNeedDstLow;
bltInfo.bNeedPat = bNeedPatLow;
bltInfo.bNeedMsk = bNeedMsk;
bltInfo.NegateMsk = 0x00;
BltLnkRect(&bltInfo,prcl);
}
if (bNeedMsk &&(Rop3High != 0xAA) )
{
//
// perform second call to write the high mask ROP pixels
//
bltInfo.rop3 = Rop3High;
bltInfo.RopSrc = RopSrcHigh;
bltInfo.RopDst = RopDstHigh;
bltInfo.bNeedSrc = bNeedSrcHigh;
bltInfo.bNeedDst = bNeedDstHigh;
bltInfo.bNeedPat = bNeedPatHigh;
bltInfo.bNeedMsk = bNeedMsk;
bltInfo.NegateMsk = 0xFF;
BltLnkRect(&bltInfo,prcl);
}
prcl->left = TempRect.left;
prcl->right = TempRect.right;
}
}
}
} while (bMore);
return(TRUE);
}
/******************************Public*Routine******************************\
*
* Routine Name:
*
* BltLnkRect
*
* Routine Description:
*
* Perform rectangular BitBlt using rop3 passed from BltLnk. The rops are
* performed using temporary scan line buffers so that the logical
* operations are done 1 DWORD at a time. The Src data is copied to the
* temporary buffer using SrcBlt so the the bitmap format and color
* translation is done to match Src to Dst. Also Src alignment in matched
* to Dst alignment in SrcBlt. The result of the logical combination is
* copied to the destination using the appropriate SrcBlt routine.
*
* Arguments:
*
* pBlt - BLT specific information
* prcl - clipping rectangle
*
* Return Value:
*
* None
*
\**************************************************************************/
VOID
BltLnkRect(
PBLTLNKINFO pBlt,
PRECTL prcl
)
{
LONG cy;
LONG DwordCount;
ULONG ByteOffset;
ULONG PixelOffset;
ULONG PixelCount;
ULONG rop2;
BLTINFO SrcCopyBltInfo;
BLTINFO DstCopyBltInfo;
PFN_SRCCPY pfnSrcCopy;
PFN_SRCCPY pfnDstCopy;
PFN_BLTLNKROP pfnRop1,pfnRop2;
PFN_READPAT pfnReadPat;
PFN_SRCCOPYMASK pfnCopyMask;
ULONG SrcBuffer[SCAN_LINE_BUFFER_LENGTH];
ULONG DstBuffer[SCAN_LINE_BUFFER_LENGTH];
ULONG RopBuffer0[SCAN_LINE_BUFFER_LENGTH];
ULONG RopBuffer1[SCAN_LINE_BUFFER_LENGTH];
PBYTE pjSrc = (PBYTE)NULL;
PBYTE pjDst = (PBYTE)NULL;
PBYTE pjPat = (PBYTE)NULL;
ULONG cxPat;
ULONG ixPat;
LONG cyPat;
LONG iyPat;
ULONG ixMsk;
LONG iyMsk;
ULONG iSolidColor;
ULONG ulDstStart;
ULONG Index;
ULONG ulIndex;
ULONG BytesPerPixel = 0;
ULONG ByteOffset24Bpp = 0;
BLTLNK_MASKINFO bmskMaskInfo;
#if DBG_BLTLNK
if (DbgBltLnk >= 1)
{
DbgPrint("BltLnkRect:\n");
DbgPrint(" prcl = %li,%li to %li,%li\n",
prcl->left,prcl->top,prcl->right,prcl->bottom);
DbgPrint(" yDir = %li, xDir = %li\n",
pBlt->yDir,pBlt->xDir);
DbgPrint(" pjSrc = 0x%lx, pjDst = 0x%lx\n",pBlt->pjSrc,pBlt->pjDst);
}
if (DbgBltLnk >= 2)
{
DbgPrint(" Address of SrcBuffer = 0x%p\n",&SrcBuffer[0]);
DbgPrint(" Address of DstBuffer = 0x%p\n",&DstBuffer[0]);
DbgPrint(" Address of RopBuffer0 = 0x%p\n",&RopBuffer0[0]);
DbgPrint(" Address of RopBuffer1 = 0x%p\n",&RopBuffer1[0]);
}
#endif
//
// Calculate all temporary parameters needed to perform the BitBlt
// based on source and destination bitmap formats (which may be different)
//
// cy = number of scan lines to Blt
//
cy = prcl->bottom - prcl->top;
PixelCount = prcl->right - prcl->left;
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" cy = %li\n",cy);
}
#endif
//
// calculate parameters for:
//
// 1) SrcBlt routine to load source into DWORD buffer
// transformed to Dst alignment, format and color
// 2) ROP2 routine to operate on DWORDS
// 3) SrcBlt routine to store DWORD buffer to pjDst
//
switch(pBlt->pdioDst->iFormat())
{
case BMF_1BPP:
ulDstStart = prcl->left >> 5;
ByteOffset = (prcl->left >> 3) & 0x03;
PixelOffset = prcl->left & 0x1f;
DwordCount = (PixelOffset + PixelCount + 31) >> 5;
break;
case BMF_4BPP:
ulDstStart = prcl->left >> 3;
ByteOffset = (prcl->left >> 1) & 0x03;
PixelOffset = prcl->left & 0x07;
DwordCount = (PixelOffset + PixelCount + 7) >> 3;
break;
case BMF_8BPP:
ulDstStart = prcl->left >> 2;
ByteOffset = prcl->left & 0x03;
PixelOffset = prcl->left & 0x03;
DwordCount = (PixelOffset + PixelCount + 3) >> 2;
BytesPerPixel = 1;
break;
case BMF_16BPP:
ulDstStart = prcl->left >> 1;
ByteOffset = (prcl->left & 0x01) << 1;
PixelOffset = prcl->left & 0x01;
DwordCount = (PixelOffset + PixelCount + 1) >> 1;
BytesPerPixel = 2;
break;
case BMF_24BPP:
ulDstStart = (prcl->left * 3) >> 2;
ByteOffset = (prcl->left * 3) & 0x03;
PixelOffset = 0;
ByteOffset24Bpp = ByteOffset;
BytesPerPixel = 3;
DwordCount = (ByteOffset + 3 * PixelCount + 3) >> 2;
break;
case BMF_32BPP:
ulDstStart = prcl->left;
DwordCount = PixelCount;
ByteOffset = 0;
PixelOffset = 0;
BytesPerPixel = 4;
break;
}
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" ulDstStart = %li\n",ulDstStart);
DbgPrint(" DwordCount = %li\n",DwordCount);
DbgPrint(" ByteOffset = 0x%lx\n",ByteOffset);
DbgPrint(" PixelOffset = 0x%lx\n",PixelOffset);
}
#endif
//
// if there is a pat that isn't a solid color then
// set up params based on prcl
//
if (pBlt->pjPat != (PBYTE) NULL)
{
//
// Set up format-specific pattern parameters for the call to
// ReadPat. Note: there is only one call for reading
// 8,16,24 and 32 Bpp patterns so cxPat, the pixel count is
// adjusted to become a byte count for these cases. ixPat is
// also adjusted to be a byte offset in these cases.
//
switch(pBlt->pdioDst->iFormat())
{
case BMF_1BPP:
cxPat = pBlt->cxPat;
ixPat = prcl->left - pBlt->xPatOrg;
pfnReadPat = BltLnkReadPat1;
break;
case BMF_4BPP:
cxPat = pBlt->cxPat;
ixPat = prcl->left - pBlt->xPatOrg;
pfnReadPat = BltLnkReadPat4;
break;
case BMF_8BPP:
cxPat = pBlt->cxPat;
ixPat = prcl->left - pBlt->xPatOrg;
pfnReadPat = BltLnkReadPat;
break;
case BMF_16BPP:
cxPat = pBlt->cxPat << 1;
ixPat = ((prcl->left - pBlt->xPatOrg) << 1);
pfnReadPat = BltLnkReadPat;
break;
case BMF_24BPP:
cxPat = pBlt->cxPat * 3;
ixPat = ((prcl->left - pBlt->xPatOrg) * 3);
pfnReadPat = BltLnkReadPat;
break;
case BMF_32BPP:
cxPat = pBlt->cxPat << 2;
ixPat = ((prcl->left - pBlt->xPatOrg) << 2);
pfnReadPat = BltLnkReadPat;
break;
}
//
// Normalize Pattern:
//
// make sure starting ixPat is within pattern limits
// and set up iyPat and cyPat
//
if (ixPat >= cxPat)
{
ixPat %= cxPat;
}// else if (ixPat < 0) {
// ixPat = (cxPat - 1) - ((-(LONG)ixPat - 1) % cxPat);
// }
cyPat = pBlt->cyPat;
iyPat = prcl->top - pBlt->yPatOrg;
if (pBlt->yDir < 0)
{
iyPat = iyPat + (cy - 1);
}
if (iyPat >= cyPat)
{
iyPat %= cyPat;
} else if (iyPat < 0) {
iyPat = (cyPat - 1) - ((-(LONG)iyPat - 1) % cyPat);
}
pjPat = pBlt->pjPat + (iyPat * pBlt->lDeltaPat);
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" cxPat = 0x%lx cyPat = 0x%lx\n",cxPat,cyPat);
DbgPrint(" ixPat = 0x%lx iyPat = 0x%lx\n",ixPat,iyPat);
DbgPrint(" pjPat = 0x%p\n",pjPat);
DbgPrint(" lDeltaPat = 0x%lx\n",pBlt->lDeltaPat);
}
#endif
} else {
//
// solid color for pat
//
iSolidColor = pBlt->iSolidColor;
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" iSolidColor = 0x%lx\n",iSolidColor);
}
#endif
}
//
// pjDst pointer to the beginning of the Dst scan line
//
// ulDstStart is added to (PULONG)pjDst to get the
// address of the first ULONG containing pixels needed in
// the blt
//
if (pBlt->yDir > 0)
{
pjDst = pBlt->pjDst + prcl->top * pBlt->lDeltaDst;
} else {
pjDst = pBlt->pjDst + (prcl->bottom - 1) * pBlt->lDeltaDst;
}
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" ulDstStart = 0x%lx\n",ulDstStart);
DbgPrint(" starting pjDst = 0x%p\n",pjDst);
DbgPrint(" Byte Offset = 0x%lx\n",ByteOffset);
}
#endif
//
// calculate Src parameters if the Src is needed. Src paramters are
// used to load the entire Src into the temp buffer, aligned to
// Dst and converted to Dst format, one scan line at a time
//
if (pBlt->pjSrc != (PBYTE) NULL)
{
//
// set up color translate routines
//
SrcCopyBltInfo.pxlo = pBlt->pxlo;
//
// ySrc is the offset in scan lines from the start of the src bitmap
//
// xSrctart is the pixel offset from the strart of the scan line
// to the first pixel neded
//
// xSrcEnd is 1 pixel beyond the last one needed for the scan line
//
pBlt->ySrc = pBlt->ySrcOrg + prcl->top - pBlt->rclDst.top;
pBlt->xSrcStart = pBlt->xSrcOrg + prcl->left - pBlt->rclDst.left;
pBlt->xSrcEnd = pBlt->xSrcStart + (PixelCount);
//
// initialize pjSrc to point to the start of each scan line to be
// copied
//
pjSrc = pBlt->pjSrc;
if (pBlt->yDir > 0)
{
pjSrc = pjSrc + (pBlt->ySrc * pBlt->lDeltaSrc);
} else {
pjSrc = pjSrc + (pBlt->ySrc + cy - 1) * pBlt->lDeltaSrc;
}
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" starting pjSrc = %p\n",pjSrc);
DbgPrint(" ySrc = %li\n",pBlt->ySrc);
DbgPrint(" xSrcStart = %li\n",pBlt->xSrcStart);
DbgPrint(" ySrcEnd = %li\n",pBlt->xSrcEnd);
}
#endif
}
//
// set up mask params
//
if (pBlt->bNeedMsk)
{
bmskMaskInfo.cxMsk = pBlt->cxMsk;
ixMsk = pBlt->xMskOrg + prcl->left - pBlt->rclDst.left;
iyMsk = pBlt->yMskOrg + prcl->top - pBlt->rclDst.top;
//
// # of pixels offsets to first pixel for src from start of scan
//
if (pBlt->yDir < 0)
{
iyMsk += (cy - 1);
}
//
// Normalize Msk again since prcl->left-pBlt->rclDst.left has
// been added.
//
// ixMsk should not be < 0 because MskOrg has already
// been normalized.
//
ASSERTGDI(iyMsk >= 0, " ERROR, negative iyMsk that has already been normalized");
if (ixMsk >= pBlt->cxMsk)
{
ixMsk = ixMsk % pBlt->cxMsk;
}
if (iyMsk >= pBlt->cyMsk)
{
iyMsk = iyMsk % pBlt->cyMsk;
}
//
// info for SrcCopyMsk routines
//
bmskMaskInfo.pjMskBase = pBlt->pjMsk;
bmskMaskInfo.pjMsk = pBlt->pjMsk + (iyMsk * pBlt->lDeltaMsk);
bmskMaskInfo.ixMsk = ixMsk;
bmskMaskInfo.cxMsk = pBlt->cxMsk;
bmskMaskInfo.iyMsk = iyMsk;
bmskMaskInfo.cyMsk = pBlt->cyMsk;
bmskMaskInfo.NegateMsk = pBlt->NegateMsk;
bmskMaskInfo.lDeltaMskDir = pBlt->lDeltaMskDir;
//
// select mask store routine
//
switch(pBlt->pdioDst->iFormat())
{
case BMF_1BPP:
pfnCopyMask = BltLnkSrcCopyMsk1;
break;
case BMF_4BPP:
pfnCopyMask = BltLnkSrcCopyMsk4;
break;
case BMF_8BPP:
pfnCopyMask = BltLnkSrcCopyMsk8;
break;
case BMF_16BPP:
pfnCopyMask = BltLnkSrcCopyMsk16;
break;
case BMF_24BPP:
pfnCopyMask = BltLnkSrcCopyMsk24;
break;
case BMF_32BPP:
pfnCopyMask = BltLnkSrcCopyMsk32;
break;
}
}
////////////////////////////////////////////////////////////////
// //
// Place Accelerators Here for special cases that can not //
// go through the normal load/combine/store procedure. Only //
// positive x and y blts are accelerated (left to right), //
// top to bottom. //
// //
////////////////////////////////////////////////////////////////
if ((pBlt->xDir > 0) && (pBlt->yDir > 0)) {
//
// Mask Blt
//
if ((pBlt->rop3 == 0xCC) &&
pBlt->bNeedMsk &&
(pBlt->pdioSrc->iFormat() == pBlt->pdioDst->iFormat()) &&
(pBlt->pxlo->bIsIdentity()))
{
//
// customize DstCopyBltInfo for MaskBlt 0xAACC or 0xCCAA will
// reach this point with a rop3 of CC. Color translations use the
// normal path.
//
DstCopyBltInfo.pjDst = pjDst;
DstCopyBltInfo.pjSrc = pjSrc;
DstCopyBltInfo.xDir = 1;
DstCopyBltInfo.yDir = pBlt->yDir;
DstCopyBltInfo.cx = PixelCount;
DstCopyBltInfo.cy = cy;
DstCopyBltInfo.lDeltaSrc = pBlt->lDeltaSrcDir;
DstCopyBltInfo.lDeltaDst = pBlt->lDeltaDstDir;
DstCopyBltInfo.xSrcStart = pBlt->xSrcStart;
DstCopyBltInfo.xSrcEnd = pBlt->xSrcStart + PixelCount;
DstCopyBltInfo.xDstStart = prcl->left;
DstCopyBltInfo.yDstStart = 0;
DstCopyBltInfo.pxlo = &xloIdent;
(*pfnCopyMask)(&DstCopyBltInfo,&bmskMaskInfo,&SrcBuffer[0],&DstBuffer[0]);
return;
}
//
// ROP B8B8, src = 1bpp, translate to 00,ff. this is a src of 1bpp used as a mask
// to blt a solid color to dst as Dst = (Src & Dst) | (~Src & Pat)
//
// Also accelerate ROP E2E2 which is the opposite of B8B8 ie:
//
// Dst = (~Src & Dst) | (Src & Pat)
//
if ( ((pBlt->rop3 == 0xB8) || (pBlt->rop3 == 0xE2)) &&
(!pBlt->bNeedMsk) &&
(pBlt->iSolidColor != 0xffffffff) &&
(pBlt->pdioSrc->iFormat() == BMF_1BPP) &&
((pBlt->pdioDst->iFormat() >= BMF_8BPP) &&
(pBlt->pdioDst->iFormat() <= BMF_32BPP)) )
{
PFN_PATMASKCOPY pfnCopy;
ULONG colormask;
switch (pBlt->pdioDst->iFormat())
{
//
// BltLnkPatMaskCopy4 (and probably BltLnkPatMaskCopy1) are
// broken, so don't use them for now.
//
case BMF_8BPP:
pfnCopy = BltLnkPatMaskCopy8;
colormask = 0x0000ff;
break;
case BMF_16BPP:
pfnCopy = BltLnkPatMaskCopy16;
colormask = 0x00ffff;
break;
case BMF_24BPP:
pfnCopy = BltLnkPatMaskCopy24;
colormask = 0xffffff;
break;
case BMF_32BPP:
pfnCopy = BltLnkPatMaskCopy32;
colormask = 0xffffff;
break;
default:
RIP("Unexpected case.");
}
PULONG pulTranslate = pBlt->pxlo->pulXlate;
if ( ((pulTranslate[1] & colormask) == colormask) &&
((pulTranslate[0] & colormask) == 0))
{
BYTE Invert = 0x00;
if (pBlt->rop3 == 0xE2) {
Invert = 0xFF;
}
//
// set up blt info
//
DstCopyBltInfo.pjDst = pjDst;
DstCopyBltInfo.pjSrc = pjSrc;
DstCopyBltInfo.xDir = 1;
DstCopyBltInfo.yDir = pBlt->yDir;
DstCopyBltInfo.cx = PixelCount;
DstCopyBltInfo.cy = cy;
DstCopyBltInfo.lDeltaSrc = pBlt->lDeltaSrcDir;
DstCopyBltInfo.lDeltaDst = pBlt->lDeltaDstDir;
DstCopyBltInfo.xSrcStart = pBlt->xSrcStart;
DstCopyBltInfo.xSrcEnd = pBlt->xSrcStart + PixelCount;
DstCopyBltInfo.xDstStart = prcl->left;
DstCopyBltInfo.yDstStart = 0;
DstCopyBltInfo.pxlo = pBlt->pxlo;
(*pfnCopy)(&DstCopyBltInfo,pBlt->iSolidColor,&SrcBuffer[0],Invert);
return;
}
}
//
// accelerators for VGA 256 special cases
//
if ((!pBlt->bNeedMsk) &&
(pBlt->bNeedSrc) &&
(pBlt->bNeedDst) &&
(pBlt->pdioDst->iFormat() == BMF_8BPP) &&
(pBlt->pdioSrc->iFormat() == BMF_8BPP) &&
(pBlt->pxlo->bIsIdentity())
)
{
//
// ROP 6666 DSx
//
if (pBlt->rop3 == 0x66)
{
BltLnkAccel6666(
pjSrc + pBlt->xSrcStart,
pjDst + prcl->left,
pBlt->lDeltaSrcDir,
pBlt->lDeltaDstDir,
PixelCount,
cy
);
return;
}
//
// ROP 8888 DSa
//
if (pBlt->rop3 == 0x88)
{
BltLnkAccel8888(
pjSrc + pBlt->xSrcStart,
pjDst + prcl->left,
pBlt->lDeltaSrcDir,
pBlt->lDeltaDstDir,
PixelCount,
cy
);
return;
}
//
// ROP EEEE DSo
//
if (pBlt->rop3 == 0xEE)
{
BltLnkAccelEEEE(
pjSrc + pBlt->xSrcStart,
pjDst + prcl->left,
pBlt->lDeltaSrcDir,
pBlt->lDeltaDstDir,
PixelCount,
cy
);
return;
}
}
//
// END OF ACCELERATORS
//
}
////////////////////////////////////////////////////////////////
// //
// Non-accelerated cases //
// //
////////////////////////////////////////////////////////////////
if (pBlt->bNeedSrc)
{
//
// fill out the SrcCopyBltInfo structure to be used by SrcBltxxx routine
// to read the src bitmap and copy it to dst format and alignment
//
SrcCopyBltInfo.pjDst = (PBYTE)(&SrcBuffer[0]) + ByteOffset24Bpp;
SrcCopyBltInfo.pjSrc = pjSrc;
SrcCopyBltInfo.xDir = 1;
SrcCopyBltInfo.yDir = pBlt->yDir;
SrcCopyBltInfo.cx = PixelCount;
SrcCopyBltInfo.cy = 1;
SrcCopyBltInfo.lDeltaSrc = 1;
SrcCopyBltInfo.lDeltaDst = 1;
SrcCopyBltInfo.xSrcStart = pBlt->xSrcStart;
SrcCopyBltInfo.xSrcEnd = pBlt->xSrcStart + SrcCopyBltInfo.cx;
SrcCopyBltInfo.xDstStart = PixelOffset;
SrcCopyBltInfo.yDstStart = 1;
SrcCopyBltInfo.pxlo = pBlt->pxlo;
//
// select SrcCopy routine based on bitmap formats and color translation
//
Index = (pBlt->pdioDst->iFormat() << 5) | (pBlt->pdioSrc->iFormat() << 2);
if (pBlt->pxlo->bIsIdentity())
{
Index += 1;
}
pfnSrcCopy = SrcCopyFunctionTable[Index];
}
//
// fill out the DstCopyBltInfo structure to be used by SrcBltxxx routine
// to copy the dst scan line to the actual destination
//
DstCopyBltInfo.pjDst = pjDst;
DstCopyBltInfo.pjSrc = (PBYTE)&DstBuffer[0] + ByteOffset24Bpp;
DstCopyBltInfo.xDir = 1;
DstCopyBltInfo.yDir = pBlt->yDir;
DstCopyBltInfo.cx = PixelCount;
DstCopyBltInfo.cy = 1;
DstCopyBltInfo.lDeltaSrc = 1;
DstCopyBltInfo.lDeltaDst = 1;
DstCopyBltInfo.xSrcStart = PixelOffset;
DstCopyBltInfo.xSrcEnd = PixelOffset + DstCopyBltInfo.cx;
DstCopyBltInfo.xDstStart = prcl->left;
DstCopyBltInfo.yDstStart = 0;
DstCopyBltInfo.pxlo = &xloIdent;
//
// select DstCopy routine based on bitmap formats and color translation,
// only need SrcCopy routine selection if not using mask
//
if (!pBlt->bNeedMsk)
{
Index = (pBlt->pdioDst->iFormat() << 5) | (pBlt->pdioDst->iFormat() << 2);
//
// color translation already done
//
Index += 1;
pfnDstCopy = SrcCopyFunctionTable[Index];
}
//
// define the ROP function, there are 4 possible ROP functions:
//
// if Pat is not need then it is a ROP 2 without Pat
//
// if Dst is not need then it is a ROP 2 without Dst
//
// if Src is not need then it is a ROP 2 without Src
//
// If src,dst and pat are needed to calculate the new dest then it is a
// full ROP3
//
//
if (!pBlt->bNeedPat)
{
rop2 = pBlt->rop3 & 0x0F;
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" Select no pat rop, rop2 function = %li\n",rop2);
}
#endif
//
// ROP without Pat
//
pfnRop1 = RopFunctionTable[rop2];
//
// blt each scan line
//
Index = cy;
while (Index--)
{
if (pBlt->bNeedSrc)
{
//
// get src scan line if offset or
// color translation are needed
//
(*pfnSrcCopy)(&SrcCopyBltInfo);
//
// update pointer for next src line
//
SrcCopyBltInfo.pjSrc += pBlt->lDeltaSrcDir;
}
//
// ROP the buffers together
//
(*pfnRop1)(&DstBuffer[0],(PULONG)pjDst + ulDstStart,&SrcBuffer[0],DwordCount);
//
// copy the buffer to the dest
//
if (!pBlt->bNeedMsk)
{
(*pfnDstCopy)(&DstCopyBltInfo);
} else {
//
// call store routine with mask
//
(*pfnCopyMask)(&DstCopyBltInfo,&bmskMaskInfo,&RopBuffer0[0],NULL);
//
// increment to the next mask scan line,
// check for going off the edge. This must
// be done for pos and neg blts
//
// should be an inline function!
//
if (pBlt->yDir > 0) {
iyMsk++;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
if (iyMsk >= pBlt->cyMsk)
{
iyMsk = 0;
bmskMaskInfo.pjMsk = pBlt->pjMsk;
}
} else {
if (iyMsk == 0)
{
iyMsk = pBlt->cyMsk - 1;
bmskMaskInfo.pjMsk = pBlt->pjMsk +
(pBlt->lDeltaMsk * (pBlt->cyMsk - 1));
}
else
{
iyMsk--;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
}
}
}
//
// increment to the next scan line
//
pjDst += pBlt->lDeltaDstDir;
DstCopyBltInfo.pjDst = pjDst;
}
//
// ROP that doesn't require Dst
//
} else if (!pBlt->bNeedDst) {
rop2 = pBlt->RopDst & 0x0f;
pfnRop1 = RopFunctionTable[rop2];
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" Select no dst rop, rop2 function = %lx\n",rop2);
}
#endif
//
// fill in solid color if there is no pjPat;
//
if (pjPat == (PBYTE) NULL)
{
if (pBlt->pdioDst->iFormat() != BMF_24BPP)
{
//
// fill in RopBuffer1 with the 32 bit solid color.
// Number of DWORDS = Number of BYTES/4
//
ulIndex = DwordCount;
while (ulIndex > 0)
{
RopBuffer1[--ulIndex] = iSolidColor;
}
} else {
PBYTE pjSolidPat = (PBYTE)(&RopBuffer1[0]) + ByteOffset24Bpp;
//
// read in 24bpp solid color
//
ulIndex = PixelCount;
while (ulIndex > 0)
{
*pjSolidPat = (BYTE)(iSolidColor & 0x0000FF);
*(pjSolidPat+1) = (BYTE)((iSolidColor >> 8) & 0x0000FF);
*(pjSolidPat+2) = (BYTE)((iSolidColor >> 16) & 0x0000FF);
pjSolidPat+=3;
ulIndex--;
}
}
}
//
// ROP without Dst
//
while (cy--)
{
if (pBlt->bNeedSrc)
{
//
// get src scan line
//
(*pfnSrcCopy)(&SrcCopyBltInfo);
//
// update pointer for next src line
//
SrcCopyBltInfo.pjSrc += pBlt->lDeltaSrcDir;
}
if (pjPat != (PBYTE) NULL)
{
if (pjPat != (PBYTE) NULL)
{
(*pfnReadPat)((PBYTE)&RopBuffer1[0]+ByteOffset,PixelOffset,pjPat,cxPat,ixPat,PixelCount,BytesPerPixel);
if (pBlt->yDir == 1) {
iyPat++;
pjPat += pBlt->lDeltaPatDir;
if (iyPat >= cyPat)
{
iyPat = 0;
pjPat = pBlt->pjPat;
}
} else {
if (iyPat == 0)
{
iyPat = cyPat - 1;
pjPat = pBlt->pjPat +
(pBlt->lDeltaPat * (cyPat - 1));
}
else
{
iyPat--;
pjPat -= pBlt->lDeltaPat;
}
}
}
}
//
// ROP the buffers together
//
(*pfnRop1)(&DstBuffer[0],&RopBuffer1[0],&SrcBuffer[0],DwordCount);
//
// copy the result to the screen
//
if (!pBlt->bNeedMsk)
{
(*pfnDstCopy)(&DstCopyBltInfo);
} else {
//
// call store routine with mask
//
(*pfnCopyMask)(&DstCopyBltInfo,&bmskMaskInfo,&SrcBuffer[0],NULL);
//
// increment to the next mask scan line,
// check for going off the edge. This must
// be done for pos and neg blts
//
// should be an inline function!
//
if (pBlt->yDir > 0) {
iyMsk++;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
if (iyMsk >= pBlt->cyMsk)
{
iyMsk = 0;
bmskMaskInfo.pjMsk = pBlt->pjMsk;
}
} else {
if (iyMsk == 0)
{
iyMsk = pBlt->cyMsk - 1;
bmskMaskInfo.pjMsk = pBlt->pjMsk +
(pBlt->lDeltaMsk * (pBlt->cyMsk - 1));
}
else
{
iyMsk--;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
}
}
}
//
// increment to the next scan line
//
pjDst += pBlt->lDeltaDstDir;
DstCopyBltInfo.pjDst = pjDst;
}
//
// ROP that doesn't require Src
//
} else if (!pBlt->bNeedSrc) {
//
// fill in solid color if there is no pjPat;
//
if (pjPat == (PBYTE) NULL)
{
if (pBlt->pdioDst->iFormat() != BMF_24BPP)
{
//
// Replicate solid pattern to buffer
// Number of DWORDS = Number of BYTES/4
//
ulIndex = DwordCount;
while (ulIndex > 0)
{
RopBuffer1[--ulIndex] = iSolidColor;
}
} else {
PBYTE pjSolidPat = (PBYTE)(&RopBuffer1[0]) + ByteOffset24Bpp;
ulIndex = PixelCount;
//
// read in 24bpp solid color
//
while (ulIndex > 0)
{
*pjSolidPat = (BYTE)(iSolidColor & 0x0000FF);
*(pjSolidPat+1) = (BYTE)((iSolidColor >> 8) & 0x0000FF);
*(pjSolidPat+2) = (BYTE)((iSolidColor >> 16) & 0x0000FF);
pjSolidPat+=3;
ulIndex--;
}
}
}
//
// Rop without SRC
//
rop2 = pBlt->RopSrc & 0x0f;
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" Select no src rop, rop2 function = %lx\n",rop2);
}
#endif
pfnRop1 = RopFunctionTable[rop2];
//
// blt each scan line
//
Index = cy;
while (Index--)
{
//
// will need pat for sure
//
if (pBlt->bNeedPat)
{
if (pjPat != (PBYTE) NULL)
{
(*pfnReadPat)((PBYTE)&RopBuffer1[0]+ByteOffset,PixelOffset,pjPat,cxPat,ixPat,PixelCount,BytesPerPixel);
if (pBlt->yDir == 1) {
iyPat++;
pjPat += pBlt->lDeltaPatDir;
if (iyPat >= cyPat)
{
iyPat = 0;
pjPat = pBlt->pjPat;
}
} else {
if (iyPat == 0)
{
iyPat = cyPat - 1;
pjPat = pBlt->pjPat +
(pBlt->lDeltaPat * (cyPat - 1));
}
else
{
iyPat--;
pjPat -= pBlt->lDeltaPat;
}
}
}
}
//
// ROP the memory buffers together
//
(*pfnRop1)(&DstBuffer[0],(PULONG)pjDst + ulDstStart,&RopBuffer1[0],DwordCount);
//
// copy the result to the dest
//
if (!pBlt->bNeedMsk)
{
(*pfnDstCopy)(&DstCopyBltInfo);
} else {
//
// call store routine with mask
//
(*pfnCopyMask)(&DstCopyBltInfo,&bmskMaskInfo,&SrcBuffer[0],NULL);
//
// increment to the next mask scan line,
// check for going off the edge. This must
// be done for pos and neg blts
//
// should be an inline function!
//
if (pBlt->yDir > 0) {
iyMsk++;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
if (iyMsk >= pBlt->cyMsk)
{
iyMsk = 0;
bmskMaskInfo.pjMsk = pBlt->pjMsk;
}
} else {
if (iyMsk == 0)
{
iyMsk = pBlt->cyMsk - 1;
bmskMaskInfo.pjMsk = pBlt->pjMsk +
(pBlt->lDeltaMsk * (pBlt->cyMsk - 1));
}
else
{
iyMsk--;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
}
}
}
//
// increment to next dest
//
pjDst += pBlt->lDeltaDstDir;
DstCopyBltInfo.pjDst = pjDst;
}
//
// FULL rop3
//
} else {
PULONG pTmpDstBuffer;
PULONG pTmpRopBuffer0;
PULONG pTmpRopBuffer1;
PULONG pTmpSrcBuffer;
ULONG SrcColor;
//
// full ROP 3, perform in 2 passes through ROP 2, 1 for
// not Pat and one for Pat. This rop will need src,dst and pat
//
rop2 = pBlt->rop3;
#if DBG_BLTLNK
if (DbgBltLnk >= 2)
{
DbgPrint(" Select full rop, rop2 function = %lx\n",rop2 & 0x0f);
DbgPrint(" rop2 function = %lx\n",(rop2 & 0xf0) >> 4);
}
#endif
pfnRop1 = RopFunctionTable[ rop2 & 0x0f ];
pfnRop2 = RopFunctionTable[ ( rop2 & 0xf0 ) >> 4 ];
Index = cy;
while (Index--)
{
//
// get src scan line
//
(*pfnSrcCopy)(&SrcCopyBltInfo);
//
// update pointer for next src line
//
SrcCopyBltInfo.pjSrc += pBlt->lDeltaSrcDir;
//
// set dst buffer pointer to dst
//
pTmpDstBuffer = (PULONG)pjDst + ulDstStart;
//
// perform both rop passes
//
(*pfnRop1)(&RopBuffer0[0],pTmpDstBuffer,&SrcBuffer[0],DwordCount);
(*pfnRop2)(&RopBuffer1[0],pTmpDstBuffer,&SrcBuffer[0],DwordCount);
if (pjPat != (PBYTE) NULL)
{
//
// fill up a buffer with the pattern
//
(*pfnReadPat)((PBYTE)&SrcBuffer[0] + ByteOffset,PixelOffset,pjPat,cxPat,ixPat,PixelCount,BytesPerPixel);
if (pBlt->yDir == 1) {
iyPat++;
pjPat += pBlt->lDeltaPatDir;
if (iyPat >= cyPat)
{
iyPat = 0;
pjPat = pBlt->pjPat;
}
} else {
if (iyPat == 0)
{
iyPat = cyPat - 1;
pjPat = pBlt->pjPat +
(pBlt->lDeltaPat * (cyPat - 1));
}
else
{
iyPat--;
pjPat -= pBlt->lDeltaPat;
}
}
//
// combine ROPs based on pat
//
pTmpDstBuffer = &DstBuffer[0];
pTmpRopBuffer0 = &RopBuffer0[0];
pTmpRopBuffer1 = &RopBuffer1[0];
pTmpSrcBuffer = &SrcBuffer[0];
ulIndex = DwordCount;
while (ulIndex > 0)
{
SrcColor = *pTmpSrcBuffer;
*pTmpDstBuffer = (*pTmpRopBuffer1 & SrcColor |
*pTmpRopBuffer0 & ~SrcColor);
pTmpSrcBuffer++;
pTmpDstBuffer++;
pTmpRopBuffer0++;
pTmpRopBuffer1++;
ulIndex--;
}
} else {
//
// solid pattern
//
if (pBlt->pdioDst->iFormat() != BMF_24BPP)
{
pTmpDstBuffer = &DstBuffer[0];
pTmpRopBuffer0 = &RopBuffer0[0];
pTmpRopBuffer1 = &RopBuffer1[0];
ulIndex = DwordCount;
while (ulIndex > 0)
{
*pTmpDstBuffer = (*pTmpRopBuffer1 & iSolidColor |
*pTmpRopBuffer0 & ~iSolidColor);
pTmpDstBuffer++;
pTmpRopBuffer0++;
pTmpRopBuffer1++;
ulIndex--;
}
} else {
//
// fill up a buffer with 24bpp solid pat
//
PBYTE pjSolidPat = (PBYTE)(&SrcBuffer[0]) + ByteOffset24Bpp;
//
// read in 24bpp solid color
//
ulIndex = PixelCount;
while (ulIndex>0)
{
*pjSolidPat = (BYTE)(iSolidColor & 0x0000FF);
*(pjSolidPat+1) = (BYTE)((iSolidColor >> 8) & 0x0000FF);
*(pjSolidPat+2) = (BYTE)((iSolidColor >> 16) & 0x0000FF);
pjSolidPat+=3;
ulIndex--;
}
//
// combine ROPs based on pat
//
pTmpDstBuffer = &DstBuffer[0];
pTmpRopBuffer0 = &RopBuffer0[0];
pTmpRopBuffer1 = &RopBuffer1[0];
pTmpSrcBuffer = &SrcBuffer[0];
ulIndex = DwordCount;
while (ulIndex > 0)
{
SrcColor = *pTmpSrcBuffer;
*pTmpDstBuffer = (*pTmpRopBuffer1 & SrcColor |
*pTmpRopBuffer0 & ~SrcColor);
pTmpSrcBuffer++;
pTmpDstBuffer++;
pTmpRopBuffer0++;
pTmpRopBuffer1++;
ulIndex--;
}
}
}
//
// write out temp buffer to destination
//
if (!pBlt->bNeedMsk)
{
(*pfnDstCopy)(&DstCopyBltInfo);
} else {
//
// call store routine with mask
//
(*pfnCopyMask)(&DstCopyBltInfo,&bmskMaskInfo,&SrcBuffer[0],NULL);
//
// increment to the next mask scan line,
// check for going off the edge. This must
// be done for pos and neg blts
//
// should be an inline function!
//
if (pBlt->yDir > 0) {
iyMsk++;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
if (iyMsk >= pBlt->cyMsk)
{
iyMsk = 0;
bmskMaskInfo.pjMsk = pBlt->pjMsk;
}
} else {
if (iyMsk == 0)
{
iyMsk = pBlt->cyMsk - 1;
bmskMaskInfo.pjMsk = pBlt->pjMsk +
(pBlt->lDeltaMsk * (pBlt->cyMsk - 1));
}
else
{
iyMsk--;
bmskMaskInfo.pjMsk += pBlt->lDeltaMskDir;
}
}
}
//
// increment Dst to next scan line
//
pjDst += pBlt->lDeltaDstDir;
DstCopyBltInfo.pjDst = pjDst;
}
}
}