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.
 
 
 
 
 
 

5715 lines
188 KiB

/******************************Module*Header*******************************\
* Module Name: multi.cxx
*
* Supports splitting of request over multiple PDEVs
*
* Copyright (c) 1995-1999 Microsoft Corporation
\**************************************************************************/
#include "precomp.hxx"
extern PPALETTE DrvRealizeHalftonePalette(HDEV hdevPalette, BOOL bForce);
BOOL gbMultiMonMismatchColor = FALSE;
RECTL grclEmpty; // Implicitly initialized to (0,0,0,0)
BYTE gaMixNeedsPattern[] = { 0, 0, 1, 1, 1, 1, 0, 1,
1, 1, 1, 0, 1, 1, 1, 1 };
#define ROP4_NEEDS_PATTERN(rop4) ((((rop4) >> 4) ^ (rop4)) & 0x0f0f)
// Work around for bug #362287
// #define MIX_NEEDS_PATTERN(mix) (gaMixNeedsPattern[mix & 0xf])
#define MIX_NEEDS_PATTERN(mix) (TRUE)
#define REALIZE_HALFTONE_PALETTE(hdev) (DrvRealizeHalftonePalette((hdev),FALSE))
typedef struct _MULTIFONTINFO
{
PVDEV pvdev;
PVOID pv[1];
} MULTIFONTINFO, *PMULTIFONTINFO;
class MULTIFONT {
private:
FONTOBJ* pfoOrg;
PMULTIFONTINFO pMultiFontInfo;
public:
MULTIFONT(FONTOBJ *pfo, LONG csurf, PVDEV pvdev)
{
/********************************************************************
*********************************************************************
MulDestroyFont calls this constructor with csurf of -1 and a
pvdev of NULL if and only if pfo->pvConsumer != NULL. It needs to
call the pvdev() method. csurf and pvdev are ONLY referenced if
pfo->pvConsumer == NULL.
*** KEEP IT THAT WAY***
*********************************************************************
********************************************************************/
pfoOrg = pfo;
if (pfoOrg)
{
if (pfoOrg->pvConsumer == NULL)
{
pfoOrg->pvConsumer = (PVOID)EngAllocMem(FL_ZERO_MEMORY,
(sizeof(MULTIFONTINFO) + ((csurf-1) *
sizeof(PVOID))), 'lumG');
pMultiFontInfo = (PMULTIFONTINFO)pfoOrg->pvConsumer;
if (pMultiFontInfo)
{
pMultiFontInfo->pvdev = pvdev;
}
else
{
KdPrint(("MULTIFONT::MULTIFONT failed table allocation\n"));
}
}
else
{
pMultiFontInfo = (PMULTIFONTINFO)pfoOrg->pvConsumer;
}
}
}
~MULTIFONT()
{
if (pfoOrg)
{
pfoOrg->pvConsumer = pMultiFontInfo;
}
}
BOOL Valid()
{
return (pMultiFontInfo ? TRUE : FALSE);
}
VOID DestroyTable()
{
if (pfoOrg && (pMultiFontInfo != NULL))
{
EngFreeMem(pMultiFontInfo);
pMultiFontInfo = NULL;
}
}
VOID LoadElement(LONG i)
{
if (pfoOrg)
{
pfoOrg->pvConsumer = pMultiFontInfo->pv[i];
}
}
VOID StoreElement(LONG i)
{
if (pfoOrg)
{
pMultiFontInfo->pv[i] = pfoOrg->pvConsumer;
}
}
PVDEV pvdev()
{
return pMultiFontInfo->pvdev;
}
};
typedef struct _MULTIREALIZEDBRUSH
{
PVOID pvD;
PVOID pvE;
} MULTIREALIZEDBRUSH;
typedef struct _MULTIBRUSHINFO
{
ULONG cSurfaces;
MULTIREALIZEDBRUSH aBrush[1];
} MULTIBRUSHINFO, *PMULTIBRUSHINFO;
class MULTIBRUSH {
private:
BOOL bValid;
EBRUSHOBJ* pboOrg;
SURFACE* psurfOrg;
XEPALOBJ palSurfOrg;
PMULTIBRUSHINFO pMultiBrushInfo;
ULONG iSolidColorOrg;
PENGBRUSH pengbrushOrg;
public:
MULTIBRUSH(BRUSHOBJ *pbo,
LONG csurf,
PVDEV pvdev,
SURFOBJ *pso,
BOOL bPatternNeeded)
{
bValid = TRUE;
// This function is monstrous and should probably be moved out of
// line. But beware that 'bPatternNeeded' is often passed in as
// a constant 'FALSE', meaning that for those case this currently
// expands to nothing.
pboOrg = (EBRUSHOBJ*) pbo;
// pso might be NULL, so we make sure to check psurfOrg
// whenever we use it.
psurfOrg = SURFOBJ_TO_SURFACE(pso);
// Invalidate other fields.
pMultiBrushInfo = NULL;
iSolidColorOrg = 0xffffffff;
pengbrushOrg = (PENGBRUSH)-1;
if (pboOrg)
{
// Early out for solid brush.
if ((!bPatternNeeded) || (pboOrg->iSolidColor != 0xffffffff))
{
// Keep original color index for iSolidColor.
iSolidColorOrg = pboOrg->iSolidColor;
return;
}
// Save the original palette for the surface (since we will switch the surface)
palSurfOrg = pboOrg->palSurf();
if (pboOrg->pvRbrush == NULL)
{
LONG cj = (sizeof(MULTIBRUSHINFO) + ((csurf-1) * sizeof(MULTIREALIZEDBRUSH)));
pboOrg->pvRbrush = BRUSHOBJ_pvGetRbrush(pboOrg);
// It is possible that BRUSHOBJ_pvGetRbrush will fail because
// the hatch type of the brush is NULL. In this case we have
// pMultiBrushInfo == NULL even though there is a brush. This will
// be ok because the pvRbrush will not be accessed for such a
// brush.
pMultiBrushInfo = (PMULTIBRUSHINFO)pboOrg->pvRbrush;
if (pMultiBrushInfo)
{
memset (pMultiBrushInfo, 0, cj);
pMultiBrushInfo->cSurfaces = pvdev->cSurfaces;
PRBRUSH prbrush = (PDBRUSH)DBRUSHSTART(pboOrg->pvRbrush);
prbrush->bMultiBrush(TRUE);
}
else
{
bValid = FALSE;
}
}
else
{
pMultiBrushInfo = (PMULTIBRUSHINFO)pboOrg->pvRbrush;
}
}
}
~MULTIBRUSH()
{
}
BOOL Valid()
{
return (bValid);
}
VOID DestroyTable()
{
// NOTE: This routine MUST NOT access any data in from 'pvdev',
// as the DDML may already be disabled, and 'pvdev' freed, when
// this brush is deleted.
if (pboOrg && (pMultiBrushInfo != NULL))
{
ULONG csurf = pMultiBrushInfo->cSurfaces;
ASSERTGDI((csurf > 0), "Expected at least one surface in the list.");
while (csurf)
{
csurf--;
// Free the driver's DBRUSH if there is one
PVOID pvRbrush;
if (pvRbrush = pMultiBrushInfo->aBrush[csurf].pvD)
{
PRBRUSH prbrush = (PDBRUSH) DBRUSHSTART(pvRbrush);
// point to DBRUSH (pvRbrush points to
// realization, which is at the end of DBRUSH)
prbrush->vRemoveRef(RB_DRIVER);
// decrement the reference count on the
// realization and free the brush if
// this is the last reference
pMultiBrushInfo->aBrush[csurf].pvD = NULL;
}
if (pvRbrush = pMultiBrushInfo->aBrush[csurf].pvE)
{
PRBRUSH prbrush = (PENGBRUSH) pvRbrush;
// point to engine brush realization
prbrush->vRemoveRef(RB_ENGINE);
// decrement the reference count on the
// realization and free the brush if
// this is the last reference
pMultiBrushInfo->aBrush[csurf].pvE = NULL;
}
}
}
}
VOID LoadElement(DISPSURF *pds, SURFACE *psurf)
{
if (pboOrg)
{
// If psurf == NULL, we were called from MulDestroyBrush.
// We just leave the brush associated with the multi layer.
// Otherwise, associate it with the driver we're about to call.
if (psurf != NULL)
{
if (pds->iCompatibleColorFormat != 0)
{
PDEVOBJ pdo(pds->hdev);
PPALETTE ppalDC = ppalDefault;
//
// If this is palette managed device, use halftone palette.
//
if (pdo.bIsPalManaged())
{
ppalDC = REALIZE_HALFTONE_PALETTE(pdo.hdev());
}
//
// If current device has higher color depth than primary
// and this dithered brush. we don't use dithered brush
// on this, just use solid color here... since this device
// should be able to produce much colors...
//
if ((pds->iCompatibleColorFormat > 0) &&
(pboOrg->iSolidColor == 0xffffffff) &&
(pboOrg->crDCPalColor() != 0xffffffff))
{
// Try to map the solid color from surface palette.
pboOrg->iSolidColor = ulGetNearestIndexFromColorref(
psurf->ppal(),
ppalDC,
pboOrg->crDCPalColor());
// Behave as solid color brush.
pboOrg->pvRbrush = NULL;
}
//
// If this is solid color, map color index in destination
// device palette. we can not use the color index from
// meta device when this is different color depth than
// primary.
//
else if (pboOrg->iSolidColor != 0xffffffff)
{
// Try to map the solid color from surface palette.
pboOrg->iSolidColor = ulGetNearestIndexFromColorref(
psurf->ppal(),
ppalDC,
pboOrg->crDCPalColor());
// ASSERTGDI(pboOrg->pvRbrush == NULL,
// "MBRUSH:LoadElement(): solid brush, but Rbrush != NULL\n");
}
else if (pMultiBrushInfo)
{
// Save the original engine brush, then replace with device specific one.
pengbrushOrg = pboOrg->pengbrush();
pboOrg->pengbrush((ENGBRUSH *)(pMultiBrushInfo->aBrush[pds->iDispSurf].pvE));
// Get device specifc Dbrush.
pboOrg->pvRbrush = pMultiBrushInfo->aBrush[pds->iDispSurf].pvD;
}
}
else if (pMultiBrushInfo)
{
// Get device specifc Dbrush.
pboOrg->pvRbrush = pMultiBrushInfo->aBrush[pds->iDispSurf].pvD;
}
if (pMultiBrushInfo)
{
pboOrg->psoTarg(psurf);
if (psurf->ppal())
{
pboOrg->palSurf(psurf->ppal());
}
}
}
}
}
VOID StoreElement(LONG i)
{
if (pboOrg)
{
if (pMultiBrushInfo)
{
// Restore engine brush (if saved)
if (pengbrushOrg != (PENGBRUSH)-1)
{
#if DBG
if (pengbrushOrg)
{
// Make sure the engbrush is not freed.
// If freed, this might causes bugcheck.
pengbrushOrg->vAddRef();
pengbrushOrg->vRemoveRef(RB_ENGINE);
}
#endif
pMultiBrushInfo->aBrush[i].pvE = pboOrg->pengbrush();
pboOrg->pengbrush(pengbrushOrg);
pengbrushOrg = (PENGBRUSH)-1;
}
// Restore device brush.
pMultiBrushInfo->aBrush[i].pvD = pboOrg->pvRbrush;
if (psurfOrg)
{
pboOrg->psoTarg(psurfOrg);
}
if (palSurfOrg.bValid())
{
pboOrg->palSurf(palSurfOrg);
}
}
pboOrg->iSolidColor = iSolidColorOrg;
pboOrg->pvRbrush = pMultiBrushInfo;
}
}
};
/******************************Public*Routine******************************\
* BOOL GreIsPaletteDisplay
*
* Return TRUE if the display is palettized
*
* History:
* 1-Jan-1997 -by- Vadim Gorokhovsky [vadimg]
\**************************************************************************/
BOOL GreIsPaletteDisplay(HDEV hdev)
{
PDEVOBJ po(hdev);
ASSERTGDI(po.bValid(), "Invalid PDEV");
return (po.GdiInfoNotDynamic()->flRaster & RC_PALETTE);
}
/******************************Public*Routine******************************\
* BOOL bIntersect
*
* If 'prcl1' and 'prcl2' intersect, has a return value of TRUE and returns
* the intersection in 'prclResult'. If they don't intersect, has a return
* value of FALSE, and 'prclResult' is undefined.
*
\**************************************************************************/
BOOL FASTCALL bIntersect(
CONST RECTL* prcl1,
CONST RECTL* prcl2,
RECTL* prclResult)
{
prclResult->left = max(prcl1->left, prcl2->left);
prclResult->right = min(prcl1->right, prcl2->right);
if (prclResult->left < prclResult->right)
{
prclResult->top = max(prcl1->top, prcl2->top);
prclResult->bottom = min(prcl1->bottom, prcl2->bottom);
if (prclResult->top < prclResult->bottom)
{
return(TRUE);
}
}
return(FALSE);
}
/******************************Public*Routine******************************\
* BOOL bIntersect
*
* Returns TRUE if 'prcl1' and 'prcl2' intersect.
*
\**************************************************************************/
BOOL FASTCALL bIntersect(
CONST RECTL* prcl1,
CONST RECTL* prcl2)
{
return((prcl1->left < prcl2->right) &&
(prcl1->top < prcl2->bottom) &&
(prcl1->right > prcl2->left) &&
(prcl1->bottom > prcl2->top));
}
/******************************Public*Routine******************************\
* BOOL bContains
*
* Returns TRUE if 'prcl1' contains 'prcl2'.
*
\**************************************************************************/
BOOL FASTCALL bContains(
CONST RECTL* prcl1,
CONST RECTL* prcl2)
{
return((prcl1->left <= prcl2->left) &&
(prcl1->right >= prcl2->right) &&
(prcl1->top <= prcl2->top) &&
(prcl1->bottom >= prcl2->bottom));
}
/******************************Public*Routine******************************\
* BOOL MSURF::bFindSurface
*
* Given the drawing bounds and clip object, this routine finds a surface
* that will be affected by the drawing. The child surface's driver should
* then be called using MSURF's public 'pso' surface and 'pco' clip object
* members.
*
* If no surface can be found (the drawing is occuring off-screen from all
* video cards), FALSE is returned.
*
\**************************************************************************/
BOOL MSURF::bFindSurface(
SURFOBJ* psoOriginal,
CLIPOBJ* pcoOriginal,
RECTL* prclDraw)
{
GDIFunctionID(MSURF::bFindSurface);
pvdev = (VDEV*) psoOriginal->dhpdev;
ASSERTGDI((prclDraw->left < prclDraw->right) &&
(prclDraw->top < prclDraw->bottom),
"Poorly ordered draw rectangle");
pmdsurf = NULL;
if (psoOriginal->iType == STYPE_DEVBITMAP)
{
PDEVOBJ pdo(psoOriginal->hdev);
ASSERTGDI(pdo.bValid() && pdo.bMetaDriver(), "Surface is not a valid Meta surface");
// Some drivers want to hook drawing calls to device bitmaps and
// DIBs. We handle those cases here.
pmdsurf = (MDSURF*) psoOriginal->dhsurf;
ASSERTGDI(pmdsurf != NULL, "Unexpected NULL dhsurf");
pco = pcoOriginal;
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
if (pmdsurf->apso[pds->iDispSurf] != NULL)
{
pso = pmdsurf->apso[pds->iDispSurf];
pOffset = &gptlZero;
return(TRUE);
}
}
}
else
{
// Okay, the drawing is to the screen:
if ((pcoOriginal == NULL) || (pcoOriginal->iDComplexity == DC_TRIVIAL))
{
pco = pvdev->pco;
iOriginalDComplexity = DC_TRIVIAL;
rclOriginalBounds = pco->rclBounds;
rclDraw = *prclDraw;
}
else
{
pco = pcoOriginal;
iOriginalDComplexity = pco->iDComplexity;
rclOriginalBounds = pco->rclBounds;
// Intersect the drawing bounds with the clipping bounds, because
// we touch pixels that intersect both:
if (!bIntersect(prclDraw, &rclOriginalBounds, &rclDraw))
{
return(FALSE);
}
}
// Find the first surface that is affected:
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
// WINBUG #340569 3-29-2001 jasonha
// Prevent access to screen during mode change / full screen mode
if (!pds->po.bDisabled())
{
// First, test for the trivial case where the drawing is
// contained entirely within this surface:
if ((iOriginalDComplexity == DC_TRIVIAL) &&
(rclDraw.left >= pds->rcl.left) &&
(rclDraw.top >= pds->rcl.top) &&
(rclDraw.right <= pds->rcl.right) &&
(rclDraw.bottom <= pds->rcl.bottom))
{
pco->iDComplexity = DC_TRIVIAL;
pco->rclBounds = rclDraw;
pso = pds->pso;
pOffset = &pds->Off;
return(TRUE);
}
else if (bIntersect(&rclDraw, &pds->rcl, &pco->rclBounds))
{
// Since the drawing is not contained entirely within this
// surface, then we don't have DC_TRIVIAL clipping:
pco->iDComplexity = (iOriginalDComplexity != DC_TRIVIAL)
? iOriginalDComplexity
: DC_RECT;
pso = pds->pso;
pOffset = &pds->Off;
return(TRUE);
}
}
}
// Restore everything originally passed in that we modified:
pco->rclBounds = rclOriginalBounds;
pco->iDComplexity = iOriginalDComplexity;
}
return(FALSE);
}
/******************************Public*Routine******************************\
* BOOL MSURF::bNextSurface
*
* Finds the next driver surface that is affected by the drawing call.
*
* Returns FALSE if no surface can be found.
*
\**************************************************************************/
BOOL MSURF::bNextSurface()
{
if (pmdsurf != NULL)
{
// Find the next driver that wants to hook drawing to device
// bitmaps and DIBs.
for (pds = pds->pdsNext; pds != NULL; pds = pds->pdsNext)
{
if (pmdsurf->apso[pds->iDispSurf] != NULL)
{
pso = pmdsurf->apso[pds->iDispSurf];
pOffset = &gptlZero;
return(TRUE);
}
}
}
else
{
// Find the next driver that is affected by this drawing to the
// screen.
for (pds = pds->pdsNext; pds != NULL; pds = pds->pdsNext)
{
// WINBUG #340569 3-29-2001 jasonha
// Prevent access to screen during mode change / full screen mode
if (!pds->po.bDisabled())
{
// First, test for the trivial case where the drawing is
// contained entirely within this surface:
if ((iOriginalDComplexity == DC_TRIVIAL) &&
(rclDraw.left >= pds->rcl.left) &&
(rclDraw.top >= pds->rcl.top) &&
(rclDraw.right <= pds->rcl.right) &&
(rclDraw.bottom <= pds->rcl.bottom))
{
pco->iDComplexity = DC_TRIVIAL;
pso = pds->pso;
pOffset = &pds->Off;
return(TRUE);
}
else if (bIntersect(&rclDraw, &pds->rcl, &pco->rclBounds))
{
// Since the drawing is not contained entirely within this
// surface, then we don't have DC_TRIVIAL clipping:
pco->iDComplexity = (iOriginalDComplexity != DC_TRIVIAL)
? iOriginalDComplexity
: DC_RECT;
pso = pds->pso;
pOffset = &pds->Off;
return(TRUE);
}
}
}
// Restore everything originally passed in that we modified:
pco->rclBounds = rclOriginalBounds;
pco->iDComplexity = iOriginalDComplexity;
}
return(FALSE);
}
/******************************Member*Routine******************************\
* MSURF::vRestore
*
* Restores state that may have been changed by bFindSurface/bNextSurface.
*
* Note: This must always be used when bFindSurface/bNextSurface return
* TRUE, but won't be called again. (Early loop termination.)
*
\**************************************************************************/
void MSURF::vRestore()
{
// WINBUG: 451121 pravins 08/07/2001 Should be checking for non DEVBITMAP case here. For time being just check the PCO.
if (pmdsurf != NULL && pco != NULL)
{
// Restore everything originally passed in that we modified:
pco->rclBounds = rclOriginalBounds;
pco->iDComplexity = iOriginalDComplexity;
}
}
/*****************************Private*Routine******************************\
* MULTISURF::vInit
*
* Initializes members and prepares default source surface values
*
\**************************************************************************/
void
MULTISURF::vInit(
SURFOBJ *psoOriginal,
RECTL *prclOriginal
)
{
GDIFunctionID(MULTISURF::vInit);
pso = psoOriginal;
prcl = &rclOrg;
fl = 0;
pmdsurf = NULL;
if (psoOriginal != NULL)
{
rclOrg = *prclOriginal;
dhpdevOrg = psoOriginal->dhpdev;
// Is this a device associated bitmap?
if (dhpdevOrg != NULL)
{
// Save original source settings
psurfOrg = SURFOBJ_TO_SURFACE_NOT_NULL(psoOriginal);
dhsurfOrg = psurfOrg->dhsurf();
flagsOrg = psurfOrg->flags();
PDEVOBJ pdo(psurfOrg->hdev());
ASSERTGDI(pdo.bValid(), "Source doesn't have a valid HDEV");
// Setup up source
if (psurfOrg->iType() == STYPE_DEVBITMAP && pdo.bMetaDriver())
{
pmdsurf = (MDSURF*) dhsurfOrg;
ASSERTGDI(psurfOrg->pvBits() != NULL, "Meta DEVBITMAP doesn't have pvBits");
// Unmark source to make it look like a DIB
fl = MULTISURF_SET_AS_DIB;
psurfOrg->iType(STYPE_BITMAP);
psurfOrg->dhsurf(NULL);
psurfOrg->dhpdev(NULL);
psurfOrg->flags(0);
}
else
{
// Is the surface opaque or does it live in video memory?
if (psurfOrg->iType() != STYPE_BITMAP ||
pso->fjBitmap & BMF_NOTSYSMEM)
{
fl = MULTISURF_USE_COPY;
}
}
}
}
else
{
dhpdevOrg = NULL;
}
}
/*****************************Private*Routine******************************\
* MULTISURF::bCreateDIB
*
* Creates a DIB copy of the original surface and computes an adjusted
* rectangle/origin for the surface.
*
\**************************************************************************/
BOOL
MULTISURF::bCreateDIB()
{
GDIFunctionID(MULTISURF::bCreateDIB);
ASSERTGDI(!SurfDIB.bValid(), "SurfDIB already created");
PDEVOBJ pdo(psurfOrg->hdev());
ERECTL erclTrim(0L,
0L,
psurfOrg->sizl().cx,
psurfOrg->sizl().cy);
// Find intersection of surface and area needed
erclTrim *= rclOrg;
ERECTL erclTmp(0L,
0L,
erclTrim.right - erclTrim.left,
erclTrim.bottom - erclTrim.top);
DEVBITMAPINFO dbmi;
dbmi.iFormat = psurfOrg->iFormat();
dbmi.cxBitmap = erclTmp.right;
dbmi.cyBitmap = erclTmp.bottom;
dbmi.hpal = psurfOrg->ppal() ? (HPALETTE)psurfOrg->ppal()->hGet() : 0;
ASSERTGDI(!psurfOrg->bUMPD(), "UMPD surface");
dbmi.fl = BMF_TOPDOWN;
if (!SurfDIB.bCreateDIB(&dbmi, NULL))
{
WARNING("Failed SurfDIB memory allocation\n");
return FALSE;
}
(*PPFNDRV(pdo,CopyBits)) (SurfDIB.pSurfobj(),
&psurfOrg->so,
(CLIPOBJ *) NULL,
NULL,
(PRECTL) &erclTmp,
(POINTL *) &erclTrim);
rclDIB.left = prcl->left - erclTrim.left;
rclDIB.top = prcl->top - erclTrim.top;
rclDIB.right = prcl->right - erclTrim.left;
rclDIB.bottom = prcl->bottom - erclTrim.top;
return TRUE;
}
/*****************************Public*Members*******************************\
* BOOL MULTISURF::bLoadSource (2 versions)
*
* Prepares the next source surface for the given destination as follows:
*
* For a non-device BITMAP (dhpdev = NULL), the orignal surface is used.
*
* For a Meta DEVBITMAP, a matching device surface is used or if there
* isn't a match the backing DIB is used (unmarked during vInit).
*
* For other surfaces, if the destination device is different the original
* surface is unmarked to look like a DIB when the bits are present in
* system memory or a DIB copy is created.
*
* Returns FALSE if no surface can be prepared.
*
\**************************************************************************/
BOOL MULTISURF::bLoadSource(
DISPSURF* pdsDst
)
{
GDIFunctionID(MULTISURF::bLoadSource);
BOOL bRet = TRUE;
// If this is a device bitmap, there is work to do.
if (dhpdevOrg != NULL)
{
if (pmdsurf != NULL)
{
// Meta DEVBITMAP:
// Use device managed bitmap for source, else go for the DIB
pso = pmdsurf->apso[pdsDst->iDispSurf];
if (pso == NULL)
{
pso = &psurfOrg->so;
}
}
else
{
bRet = bLoadSourceNotMetaDEVBITMAP(pdsDst->hdev);
}
}
return bRet;
}
BOOL MULTISURF::bLoadSource(
HDEV hdevDst
)
{
GDIFunctionID(MULTISURF::bLoadSource);
BOOL bRet = TRUE;
// If this is a device bitmap, there is work to do.
if (dhpdevOrg != NULL)
{
if (pmdsurf != NULL)
{
// Meta DEVBITMAP:
// Use device managed bitmap for source, else go for the DIB
VDEV *pvdev = pmdsurf->pvdev;
DISPSURF *pds;
ASSERTGDI(pvdev != NULL, "pvdev is NULL.\n");
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
if (pds->hdev == hdevDst)
{
pso = pmdsurf->apso[pds->iDispSurf];
break;
}
}
if (pso == NULL)
{
pso = &psurfOrg->so;
}
}
else
{
bRet = bLoadSourceNotMetaDEVBITMAP(hdevDst);
}
}
return bRet;
}
/*****************************Private*Member*******************************\
* BOOL MULTISURF::bLoadSourceNotMetaDEVBITMAP
*
* If the destination device is different the original surface is unmarked
* to look like a DIB when the bits are present in system memory or a DIB
* copy is created.
*
* Returns FALSE if no surface can be prepared.
*
* NOTE: This routine assumes BITMAPs and Meta DEVBITMAPs have already been
* handled and won't come here. See bLoadSource members.
*
\**************************************************************************/
BOOL MULTISURF::bLoadSourceNotMetaDEVBITMAP(
HDEV hdevDst
)
{
GDIFunctionID(MULTISURF::bLoadSourceNotMetaDEVBITMAP);
if (fl & MULTISURF_USE_COPY)
{
// Opaque or video memory surface:
// Use a DIB copy if destination doesn't match the source
if (psurfOrg->hdev() != hdevDst)
{
// Do we already have a DIB copy?
if (!SurfDIB.bValid())
{
// Allocate an intermediate DIB for a source
if (!bCreateDIB())
{
return FALSE;
}
}
// Make pso and prcl point to the copy
pso = SurfDIB.pSurfobj();
prcl = &rclDIB;
}
else
{
// Just use original surface
pso = &psurfOrg->so;
prcl = &rclOrg;
}
}
else
{
// BITMAP in system memory:
// Unmark to appear as DIB if destination doesn't match the source
if (psurfOrg->hdev() != hdevDst)
{
if (!(fl & MULTISURF_SET_AS_DIB))
{
if (!(fl & MULTISURF_SYNCHRONIZED))
{
PDEVOBJ pdo(psurfOrg->hdev());
pdo.vSync(pso, prcl, 0);
fl |= MULTISURF_SYNCHRONIZED;
}
// Unset fields to look like a DIB
fl |= MULTISURF_SET_AS_DIB;
psurfOrg->dhpdev(NULL);
psurfOrg->dhsurf(NULL);
psurfOrg->flags(0);
}
}
else
{
if (fl & MULTISURF_SET_AS_DIB)
{
// Restore original settings
fl &= ~MULTISURF_SET_AS_DIB;
psurfOrg->dhpdev(dhpdevOrg);
psurfOrg->dhsurf(dhsurfOrg);
psurfOrg->flags(flagsOrg);
}
}
}
return TRUE;
}
/******************************Public*Routine******************************\
* BOOL MulEnableDriver
*
* Standard driver DrvEnableDriver function
*
\**************************************************************************/
BOOL MulEnableDriver(
ULONG iEngineVersion,
ULONG cj,
DRVENABLEDATA* pded)
{
pded->pdrvfn = gadrvfnMulti;
pded->c = gcdrvfnMulti;
pded->iDriverVersion = DDI_DRIVER_VERSION_NT5;
return(TRUE);
}
/******************************Public*Routine******************************\
* DHPDEV MulEnablePDEV
*
* Creates a single large VDEV that will represent the combination of other
* smaller PDEVs
*
* This function creates an internal structure that keeps the location of
* the various cards, and also keeps the appropriate data structures to
* be passed down to each driver.
*
\**************************************************************************/
DHPDEV MulEnablePDEV(
DEVMODEW *pdm,
LPWSTR pwszLogAddress,
ULONG cPat,
HSURF *phsurfPatterns,
ULONG cjCaps,
GDIINFO *pdevcaps,
ULONG cjDevInfo,
DEVINFO *pdi,
HDEV hdev,
LPWSTR pwszDeviceName,
HANDLE hDriver)
{
PMDEV pmdev = (PMDEV) pdm;
PVDEV pvdev;
DISPSURF dsAnchor;
DISPSURF* pds;
DISPSURF* pdsPrev;
DISPSURF* pdsTmp;
HDEV* paHdev;
ULONG i,j;
ULONG flGraphicsCaps = 0xffffffff;
ULONG flGraphicsCaps2 = 0xffffffff;
HDEV hdevPrimary = NULL;
BOOL bPrimaryPalManaged = FALSE;
pdsPrev = &dsAnchor;
// Create the main multi dispsurf structure.
LONG cjAlloc = ((sizeof(VDEV)) + (sizeof(DISPSURF) * pmdev->chdev));
pvdev = (VDEV*) EngAllocMem(FL_ZERO_MEMORY, cjAlloc, 'vdVG');
if (pvdev == NULL)
return(NULL);
paHdev = (HDEV*) EngAllocMem(FL_ZERO_MEMORY, sizeof(HDEV) * pmdev->chdev, 'sdvG');
if (paHdev == NULL)
{
EngFreeMem(pvdev);
return(NULL);
}
pds = (DISPSURF*) ((BYTE*)pvdev + sizeof(VDEV));
pvdev->cSurfaces = pmdev->chdev;
pvdev->hdev = hdev;
// Loop through the list of MDEVs passed in.
pvdev->rclBounds.left = 0x7fffffff;
pvdev->rclBounds.top = 0x7fffffff;
pvdev->rclBounds.right = 0x80000000;
pvdev->rclBounds.bottom = 0x80000000;
ASSERTGDI((pmdev->chdev > 0), "Expected at least one surface in the list.");
for (i = 0; i < pmdev->chdev; i++)
{
// Set this PDEV as parent to each of the PDEVs that we'll manage.
PDEVOBJ pdo(pmdev->Dev[i].hdev);
#if TEXTURE_DEMO
if ((pmdev->Dev[i].rect.left == 0) && (pmdev->Dev[i].rect.top == 0))
#else
if (pdo.ppdev->pGraphicsDevice->stateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)
#endif
{
ASSERTGDI(!hdevPrimary, "2 or more primary devices in MulEnablePDEV");
ASSERTGDI(pmdev->Dev[i].rect.left == 0, "mispositioned primary");
ASSERTGDI(pmdev->Dev[i].rect.top == 0, "mispositioned primary");
hdevPrimary = pdo.hdev();
bPrimaryPalManaged = pdo.bIsPalManaged();
*pdevcaps = *pdo.GdiInfo();
*pdi = *pdo.pdevinfo();
}
// Take the intersection of flags that are capabilities.
flGraphicsCaps &= pdo.pdevinfo()->flGraphicsCaps;
flGraphicsCaps2 &= pdo.pdevinfo()->flGraphicsCaps2;
pdsPrev->pdsNext = pds;
pdsPrev->pdsBltNext = pds;
pds->iDispSurf = i;
pds->rcl = *((PRECTL) &(pmdev->Dev[i].rect));
pds->hdev = pmdev->Dev[i].hdev;
pds->po.vInit(pds->hdev);
pds->po.vReferencePdev();
pds->Off.x = -pdo.pptlOrigin()->x;
pds->Off.y = -pdo.pptlOrigin()->y;
pds->pso = pdo.pSurface()->pSurfobj();
// Primary (readable) surfaces are always first in the MDEV structure;
// Secondary (non-readable) surfaces are always second. So if this
// surfaces overlaps a previous one, this surface must be non-readable:
pds->bIsReadable = TRUE;
for (pdsTmp = dsAnchor.pdsNext; pdsTmp != pds; pdsTmp = pdsTmp->pdsNext)
{
if (bIntersect(&pdsTmp->rcl, &pds->rcl))
pds->bIsReadable = FALSE;
}
// Adjust bounding rectangle:
pvdev->rclBounds.left = min(pvdev->rclBounds.left, pds->rcl.left);
pvdev->rclBounds.top = min(pvdev->rclBounds.top, pds->rcl.top);
pvdev->rclBounds.right = max(pvdev->rclBounds.right, pds->rcl.right);
pvdev->rclBounds.bottom = max(pvdev->rclBounds.bottom, pds->rcl.bottom);
pdsPrev = pds;
pds++;
}
ASSERTGDI(hdevPrimary, "No primary devices found in MulEnablePDEV");
// Make these numbers negative since we don't want them scaled again
// by GDI.
pdevcaps->ulHorzSize = (ULONG) -((LONG)pdevcaps->ulHorzSize);
pdevcaps->ulVertSize = (ULONG) -((LONG)pdevcaps->ulVertSize);
// Plug in the intersection of the GCAPS:
flGraphicsCaps &= ~(GCAPS_ASYNCMOVE | GCAPS_ASYNCCHANGE | GCAPS_PANNING);
// If primary is palette managed device, make it Meta device palette managed, too.
if (bPrimaryPalManaged)
pdi->flGraphicsCaps = (flGraphicsCaps | GCAPS_PALMANAGED | GCAPS_COLOR_DITHER);
else
pdi->flGraphicsCaps = flGraphicsCaps;
pdi->flGraphicsCaps2 = flGraphicsCaps2;
pvdev->iBitmapFormat = pdi->iDitherFormat;
// Set the root of the list of dispsurfs
pvdev->pds = dsAnchor.pdsNext;
pvdev->pdsBlt = dsAnchor.pdsNext;
// Set hdev primary
pvdev->hdevPrimary = hdevPrimary;
PDEVOBJ poMeta(hdev);
// Walk through pds list to check each device's colour depth and format
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
PDEVOBJ poThis(pds->hdev);
if (poThis.hdev() == hdevPrimary)
{
// This is primary PDEV. 0 means compatible.
pds->iCompatibleColorFormat = 0;
KdPrint(("GDI DDML: %ws - iDitherFormat is %d, and this is primary.\n",
((PDEV *)(poThis.hdev()))->pGraphicsDevice->szWinDeviceName,
poThis.iDitherFormat()));
}
else
{
// Compare colour depth primary and this device.
//
// iCompatibleColorFormat will be ...
// 0 - same as the primary
// Plus value - higher colour depth than primary
// Minus value - lower colour depth than primary
pds->iCompatibleColorFormat = (poThis.iDitherFormat() - pvdev->iBitmapFormat);
KdPrint(("GDI DDML: %ws - iDitherFormat is %d.\n",
((PDEV *)(poThis.hdev()))->pGraphicsDevice->szWinDeviceName,
poThis.iDitherFormat()));
KdPrint(("GDI DDML: %ws - PalManaged - %s\n",
((PDEV *)(poThis.hdev()))->pGraphicsDevice->szWinDeviceName,
(poThis.bIsPalManaged() ? "Yes" : "No")));
// If colour depth is same check palette format.
if (pds->iCompatibleColorFormat == 0)
{
EPALOBJ palMeta(pdi->hpalDefault);
EPALOBJ palThis(poThis.pdevinfo()->hpalDefault);
// Compare the palette type.
//
// If not equal, treat it as 1 (this is higher colour depth than primary)
pds->iCompatibleColorFormat =
((palMeta.iPalMode() == palThis.iPalMode()) ? 0 : 1);
KdPrint(("GDI DDML: %ws - iPalMode is %d.\n",
((PDEV *)(poThis.hdev()))->pGraphicsDevice->szWinDeviceName,
palThis.iPalMode()));
if ((pds->iCompatibleColorFormat == 0) &&
(palMeta.iPalMode() == PAL_BITFIELDS))
{
// If the palette is bitfields, should check R, G, B assignment.
//
// If not equal, treat it as 1 (this is higher colour depth than primary)
pds->iCompatibleColorFormat =
(((palMeta.flRed() == palThis.flRed()) &&
(palMeta.flGre() == palThis.flGre()) &&
(palMeta.flBlu() == palThis.flBlu())) ? 0 : 1);
}
}
// Mark in global variable if one of device is not same as Meta.
if (pds->iCompatibleColorFormat != 0)
{
// mark hdev in this mdev does not have same color depth.
pmdev->ulFlags |= MDEV_MISMATCH_COLORDEPTH;
gbMultiMonMismatchColor = TRUE;
KdPrint(("GDI DDML: %ws is NOT compatible as primary.\n",
((PDEV *)(poThis.hdev()))->pGraphicsDevice->szWinDeviceName));
}
else
{
// This flag should not be back to FALSE, if system once became mismatch
// color depth mode. This flag only can be FALSE, when system NEVER experience
// mismatch color depth mode since system booted.
//
// gbMultiMonMismatchColor = FALSE;
KdPrint(("GDI DDML: %ws is compatible as primary.\n",
((PDEV *)(poThis.hdev()))->pGraphicsDevice->szWinDeviceName));
}
}
}
// Set the origin in the meta-PDEV. Note that we do NOT set 'ptlOffset'
// in the surface, as that would cause all our drawing to the meta-surface
// to be offset by that amount, which is NOT what we want.
poMeta.ppdev->ptlOrigin.x = pvdev->rclBounds.left;
poMeta.ppdev->ptlOrigin.y = pvdev->rclBounds.top;
poMeta.ppdev->sizlMeta.cx = pvdev->rclBounds.right - pvdev->rclBounds.left;
poMeta.ppdev->sizlMeta.cy = pvdev->rclBounds.bottom - pvdev->rclBounds.top;
// Mark this as Meta-PDEV.
poMeta.bMetaDriver(TRUE);
KdPrint(("GDI DDML: %li devices at (%li, %li, %li, %li).\n",
pmdev->chdev, pvdev->rclBounds.left, pvdev->rclBounds.top,
pvdev->rclBounds.right, pvdev->rclBounds.bottom));
#if TEXTURE_DEMO
if (ghdevTextureParent)
{
paHdev[0] = ghdevTextureParent;
vSpEnableMultiMon(hdev, 1, paHdev); // References 'paHdev'
return((DHPDEV) pvdev);
}
#endif
// Initialize Sprite stuff.
// (Put Mirroring device first, then other drivers).
j = 0;
for (i = 0; i < pmdev->chdev; i++)
{
PDEVOBJ pdoTmp(pmdev->Dev[i].hdev);
if (pdoTmp.flGraphicsCaps() & GCAPS_LAYERED)
{
paHdev[j++] = pmdev->Dev[i].hdev;
}
}
for (i = 0; i < pmdev->chdev; i++)
{
PDEVOBJ pdoTmp(pmdev->Dev[i].hdev);
if (!(pdoTmp.flGraphicsCaps() & GCAPS_LAYERED))
{
paHdev[j++] = pmdev->Dev[i].hdev;
}
}
vSpEnableMultiMon(hdev, pmdev->chdev, paHdev); // References 'paHdev'
return((DHPDEV) pvdev);
}
/******************************Public*Routine******************************\
* VOID MulDisablePDEV
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
VOID MulDisablePDEV(DHPDEV dhpdev)
{
PVDEV pvdev;
DISPSURF* pds;
pvdev = (PVDEV) dhpdev;
vSpDisableMultiMon(pvdev->hdev); // Frees 'paHdev'
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
pds->po.vUnreferencePdev();
}
EngFreeMem(pvdev);
}
/******************************Public*Routine******************************\
* VOID MulCompletePDEV
*
* This function informs us of the 'hdev' that GDI has assigned us.
* We already got that initially information from MulEnablePDEV, but
* GDI reassigns 'hdev's during some mode changes.
*
* WINBUG #289937 01-23-2001 jasonha
* PDEV still has a reference after removing a monitor
*
* If we are being assigned an 'hdev' that was previously assigned to
* one of the children, then that child is taking over our previously
* assigned 'hdev'. We update our 'hdev's accordingly.
* NOTE: We must be able to grab ghsemDriverMgmt to successfully
* reference and unreference PDEV's.
*
* All of the layered drivers that have hdev changes have their
* DrvCompletePDEV functions called directly by GDI.
*
\**************************************************************************/
VOID MulCompletePDEV(
DHPDEV dhpdev,
HDEV hdev)
{
GDIFunctionID(MulCompletePDEV);
PVDEV pvdev = (PVDEV) dhpdev;
HDEV hdevPrev = pvdev->hdev;
DISPSURF* pds;
if (hdevPrev != hdev)
{
// Update hdevPrimary
if (pvdev->hdevPrimary == hdev)
{
pvdev->hdevPrimary = hdevPrev;
}
// Update child 'hdev's
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
if (pds->po.hdev() == hdev)
{
ASSERTGDI(pds->po.cPdevRefs() > 1, "Incorrect PDEV reference count.\n");
pds->po.vUnreferencePdev();
pds->hdev = hdevPrev;
pds->po.vInit(hdevPrev);
pds->po.vReferencePdev();
}
}
pvdev->hdev = hdev;
}
}
/******************************Public*Routine******************************\
* HSURF MulEnableSurface
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
HSURF MulEnableSurface(DHPDEV dhpdev)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
SIZEL sizlVirtual;
HSURF hsurfVirtual;
HSURF hsurf;
CLIPOBJ* pco;
SURFACE *psurf;
pvdev = (VDEV*) dhpdev;
// Note that we don't hook SYNCHRONIZE because we always return a
// device managed surface to GDI.
pvdev->flHooks = (HOOK_BITBLT
| HOOK_TEXTOUT
| HOOK_STROKEPATH
| HOOK_FILLPATH
| HOOK_STROKEANDFILLPATH
| HOOK_LINETO
| HOOK_COPYBITS
| HOOK_STRETCHBLT
| HOOK_GRADIENTFILL
| HOOK_TRANSPARENTBLT
| HOOK_ALPHABLEND);
// Now create the surface which the engine will use to refer to our
// entire multi-board virtual screen:
sizlVirtual.cx = pvdev->rclBounds.right - pvdev->rclBounds.left;
sizlVirtual.cy = pvdev->rclBounds.bottom - pvdev->rclBounds.top;
hsurfVirtual = EngCreateDeviceSurface((DHSURF) pvdev,
sizlVirtual,
pvdev->iBitmapFormat);
if (hsurfVirtual == 0)
goto ReturnFailure;
pvdev->hsurf = hsurfVirtual;
if (!EngAssociateSurface(hsurfVirtual, pvdev->hdev, pvdev->flHooks))
goto ReturnFailure;
// Get and save a pointer to the SURFOBJ for the DDML
pvdev->pso = EngLockSurface(hsurfVirtual);
if (!pvdev->pso)
goto ReturnFailure;
// Create a temporary clip object that we can use when a drawing
// operation spans multiple boards:
pco = EngCreateClip();
if (pco == NULL)
goto ReturnFailure;
pco->rclBounds = pvdev->rclBounds;
((ECLIPOBJ*) pco)->vSet(&pco->rclBounds);
pvdev->pco = pco;
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
PDEVOBJ poThis(pds->hdev);
if (poThis.flGraphicsCaps() & GCAPS_LAYERED)
{
poThis.pSurface()->hMirrorParent = hsurfVirtual;
}
}
// We're done!
return(hsurfVirtual);
ReturnFailure:
KdPrint(("Failed MulEnableSurface\n"));
MulDisableSurface((DHPDEV) pvdev);
return(0);
}
/******************************Public*Routine******************************\
* VOID MulDisableSurface
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
VOID MulDisableSurface(DHPDEV dhpdev)
{
PVDEV pvdev;
HSURF hsurf;
HOBJ hobj;
SURFACE* pSurface;
pvdev = (VDEV*) dhpdev;
PDEVOBJ po(pvdev->hdev);
ASSERTGDI(po.bValid(), "Invalid PDEV");
EngDeleteClip(pvdev->pco);
EngUnlockSurface(pvdev->pso);
EngDeleteSurface(pvdev->hsurf);
}
/******************************Public*Routine******************************\
* BOOL MulSetPalette
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulSetPalette(
DHPDEV dhpdev,
PALOBJ *ppalo,
FLONG fl,
ULONG iStart,
ULONG cColors)
{
PVDEV pvdev;
PDISPSURF pds;
BOOL bRet = TRUE;
pvdev = (VDEV*) dhpdev;
pds = pvdev->pds;
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
PDEVOBJ pdo(pds->hdev);
if (pdo.bIsPalManaged() && PPFNVALID(pdo,SetPalette))
{
bRet &= (*PPFNDRV(pdo,SetPalette)) (pdo.dhpdev(),
ppalo,
fl,
iStart,
cColors);
}
}
return (bRet);
}
/******************************Public*Routine******************************\
* BOOL MulIcmSetDeviceGammaRamp
*
* History:
* 19-Feb-1998 -by- Hideyuki Nagase [hideyukn]
* Wrote it.
*
\**************************************************************************/
ULONG MulIcmSetDeviceGammaRamp(
DHPDEV dhpdev,
ULONG iFormat,
LPVOID lpRamp)
{
PVDEV pvdev;
PDISPSURF pds;
BOOL bRet = FALSE;
pvdev = (VDEV*) dhpdev;
pds = pvdev->pds;
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
PDEVOBJ pdo(pds->hdev);
if ((PPFNVALID(pdo, IcmSetDeviceGammaRamp)) &&
(pdo.flGraphicsCaps2() & GCAPS2_CHANGEGAMMARAMP))
{
bRet &= (*PPFNDRV(pdo,IcmSetDeviceGammaRamp))
(pdo.dhpdev(),
iFormat,
lpRamp);
}
}
return (bRet);
}
/******************************Public*Routine******************************\
* BOOL MulRealizeBrush
*
* This function's only job is to handle the call caused by the pvGetRbrush
* in the MULTIBRUSH object. It should just allocate enough memory for the
* object, and return.
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulRealizeBrush(
BRUSHOBJ *pbo,
SURFOBJ *psoDst,
SURFOBJ *psoPat,
SURFOBJ *psoMask,
XLATEOBJ *pxlo,
ULONG iHatch)
{
PVDEV pvdev;
LONG cj;
pvdev = (VDEV*) psoDst->dhpdev;
ASSERTGDI(pbo->pvRbrush == NULL, "MulRealizeBrush has a memory leak.\n"
"Called with pbo->pvRbrush != NULL");
cj = sizeof(MULTIBRUSHINFO) +
(pvdev->cSurfaces - 1) * sizeof(MULTIREALIZEDBRUSH);
return(BRUSHOBJ_pvAllocRbrush(pbo, cj) != NULL);
}
/******************************Public*Routine******************************\
* ULONG MulEscape
*
* History:
* 12-Jul-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
ULONG MulEscape(
SURFOBJ *pso,
ULONG iEsc,
ULONG cjIn,
PVOID pvIn,
ULONG cjOut,
PVOID pvOut)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
ULONG ulRet = 0;
ASSERTGDI((pso->dhsurf != NULL), "Expected device dest.");
// OpenGL ExtEscapes from the ICD (and MCD) can still
// end up here at DeletContext time when the original
// DC has been lost and they try to communicate to the
// driver with a DC they got by GetDC(NULL).
//
// This routine really shouldn't do anything but return 0.
if ((iEsc == OPENGL_CMD) || (iEsc == OPENGL_GETINFO) ||
(iEsc == MCDFUNCS) || (iEsc == WNDOBJ_SETUP))
{
return (0);
}
pvdev = (VDEV*) pso->dhpdev;
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
ASSERTGDI((csurf > 0), "Expected at least one surface in the list.");
while (csurf--)
{
PDEVOBJ pdo(pds->hdev);
if (PPFNVALID(pdo,Escape))
{
ULONG ulTmp;
ulTmp = pdo.Escape(pds->pso, iEsc, cjIn, pvIn, cjOut, pvOut);
// set ulRet to last non-zero value returned
if (ulTmp != 0)
{
ulRet = ulTmp;
}
}
pds = pds->pdsNext;
}
return(ulRet);
}
/******************************Public*Routine******************************\
* VOID MulDestroyFont
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
VOID MulDestroyFont(
FONTOBJ* pfo)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
BOOL bRet = TRUE;
if (pfo->pvConsumer != NULL)
{
MULTIFONT MFONT(pfo, -1, NULL);
pvdev = MFONT.pvdev();
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
ASSERTGDI((csurf > 0), "Expected at least one surface in the list.");
while (csurf--)
{
PDEVOBJ pdo(pds->hdev);
if (PPFNVALID(pdo,DestroyFont))
{
MFONT.LoadElement(pds->iDispSurf);
pdo.DestroyFont(pfo);
MFONT.StoreElement(pds->iDispSurf);
}
pds = pds->pdsNext;
}
MFONT.DestroyTable();
}
}
/******************************Public*Routine******************************\
* VOID MulDestroyBrushInternal
*
* Internal brush destruction routine. This is called to delete our
* private information associated with multi brushes.
*
* History:
* 9-July-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
VOID MulDestroyBrushInternal(
PVOID pvRbrush)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
BOOL bRet = TRUE;
if (pvRbrush != NULL)
{
BRUSHOBJ boTmp;
boTmp.iSolidColor = 0xffffffff;
boTmp.pvRbrush = pvRbrush;
boTmp.flColorType = 0;
MULTIBRUSH MBRUSH(&boTmp, -1, NULL, NULL, TRUE);
MBRUSH.DestroyTable();
}
}
/******************************Public*Routine******************************\
* ULONG ulSimulateSaveScreenBits
*
* This function simulates SaveScreenBits for those drivers that do not
* hook it, by using a temporary bitmap and copying in and out of that.
*
\**************************************************************************/
ULONG_PTR ulSimulateSaveScreenBits(
SURFOBJ* psoScreen,
ULONG iMode,
ULONG_PTR ulIdent,
RECTL* prcl) // Already in device's coordinates
{
SIZEL sizl;
HSURF hsurf;
SURFOBJ* psoSave;
SURFACE* psurfSave;
SURFACE* psurfScreen;
ULONG_PTR ulRet;
RECTL rclDst;
POINTL ptlSrc;
PDEVOBJ pdo(psoScreen->hdev);
if (iMode == SS_SAVE)
{
sizl.cx = prcl->right - prcl->left;
sizl.cy = prcl->bottom - prcl->top;
ASSERTGDI((sizl.cx > 0) && (sizl.cy > 0), "Empty rectangle on save");
// First, try to create the temporary save bitmap as a Device-Format-
// Bitmap, and if that fails try it as a normal DIB. (Many display
// drivers support off-screen bitmaps via CreateDeviceBitmap, so this
// is often the fastest way to do it.)
hsurf = 0;
if (PPFNVALID(pdo, CreateDeviceBitmap))
{
hsurf = (HSURF) (*PPFNDRV(pdo, CreateDeviceBitmap))
(psoScreen->dhpdev,
sizl,
psoScreen->iBitmapFormat);
}
if (hsurf == 0)
{
hsurf = (HSURF) EngCreateBitmap(sizl,
0,
psoScreen->iBitmapFormat,
BMF_TOPDOWN,
NULL);
}
psoSave = EngLockSurface(hsurf);
if (psoSave)
{
rclDst.left = 0;
rclDst.top = 0;
rclDst.right = sizl.cx;
rclDst.bottom = sizl.cy;
psurfSave = SURFOBJ_TO_SURFACE(psoSave);
// Copy the screen to the temporary bitmap. Note that
// we do not use OffCopyBits as the coordinates have
// already been offset to take into account the monitor's
// origin:
(*PPFNGET(pdo, CopyBits, psurfSave->flags()))(psoSave,
psoScreen,
NULL,
NULL,
&rclDst,
(POINTL*) prcl);
}
ulRet = (ULONG_PTR) psoSave;
}
else
{
psoSave = (SURFOBJ*) ulIdent;
if (iMode == SS_RESTORE)
{
ptlSrc.x = 0;
ptlSrc.y = 0;
psurfScreen = SURFOBJ_TO_SURFACE(psoScreen);
// Copy the temporary bitmap back to the screen:
(*PPFNGET(pdo, CopyBits, psurfScreen->flags()))(psoScreen,
psoSave,
NULL,
NULL,
prcl,
&ptlSrc);
}
// Free the bitmap, remembering to retrieve any data from the
// SURFOBJ before we unlock it. Note that EngDeleteSurface
// handles calling DrvDeleteDeviceBitmap if it's a device
// format bitmap:
hsurf = psoSave->hsurf;
EngUnlockSurface(psoSave);
EngDeleteSurface(hsurf);
ulRet = TRUE;
}
return(ulRet);
}
/******************************Public*Routine******************************\
* ULONG MulSaveScreenBits
*
* It's important for the DDML to hook SaveScreenBits even if some of the
* underlying drivers do not, for scenarios such as NetMeeting. This is
* because if SaveScreenBits is not hooked, USER goes and simulates by
* creating a temporary bitmap and saving and restoring the bits into that
* bitmap via CopyBits -- meaning that for NetMeeting the temporary bitmap
* is sent in full both ways over the wire. NetMeeting much prefers to be
* able to hook SaveScreenBits so that it can send a small token over the wire
* representing the save or restore. The problem is that most drivers do
* not support SaveScreenBits, and so for those drivers we simply emulate
* ourselves (thus allowing us to hook SaveScreenBits even if all the
* drivers do not hook SaveScreenBits).
*
* Note also that NetMeeting likes to be able to fail its SS_RESTORE call so
* that it can force a repaint if it wants to.
*
\**************************************************************************/
#define SS_GDI_ENGINE 1
#define SS_GDI_DRIVER 2
typedef struct _MULTISAVEBITS {
FLONG flType;
ULONG_PTR ulBits;
} MULTISAVEBITS, *PMULTISAVEBITS;
ULONG_PTR MulSaveScreenBits(
SURFOBJ* pso,
ULONG iMode,
ULONG_PTR ulIdent,
RECTL* prcl)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
ULONG_PTR ulRet;
ULONG_PTR ulThisBits;
FLONG flThisType;
MULTISAVEBITS* pulIdent;
RECTL rclThis;
PFN_DrvSaveScreenBits pfnSaveScreenBits;
pvdev = (VDEV*) pso->dhpdev;
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
if (iMode == SS_SAVE)
{
pulIdent = (MULTISAVEBITS*)
EngAllocMem(FL_ZERO_MEMORY, csurf * sizeof(MULTISAVEBITS), 'vdVG');
ulRet = (ULONG_PTR)pulIdent;
if (pulIdent)
{
do {
ulThisBits = 0;
if (bIntersect(prcl, &pds->rcl, &rclThis))
{
rclThis.left -= pds->rcl.left;
rclThis.right -= pds->rcl.left;
rclThis.top -= pds->rcl.top;
rclThis.bottom -= pds->rcl.top;
PDEVOBJ pdoThis(pds->hdev);
pfnSaveScreenBits = PPFNVALID(pdoThis, SaveScreenBits)
? PPFNDRV(pdoThis, SaveScreenBits)
: ulSimulateSaveScreenBits;
ulThisBits = pfnSaveScreenBits(pds->pso,
SS_SAVE,
0,
&rclThis);
if (ulThisBits == 0)
{
// Ack, this driver failed to save its screenbits.
//
// Try the software simulation (if we haven't tried)
if (pfnSaveScreenBits != ulSimulateSaveScreenBits)
{
pfnSaveScreenBits = ulSimulateSaveScreenBits;
ulThisBits = pfnSaveScreenBits(pds->pso,
SS_SAVE,
0,
&rclThis);
}
if (ulThisBits == 0)
{
// We have to free any screenbits that any earlier
// driver saved:
MulSaveScreenBits(pso,
SS_FREE,
ulRet,
&grclEmpty);
return(0);
}
}
}
if ((pulIdent[pds->iDispSurf].ulBits = ulThisBits) != 0)
{
pulIdent[pds->iDispSurf].flType =
(pfnSaveScreenBits == ulSimulateSaveScreenBits)
? SS_GDI_ENGINE : SS_GDI_DRIVER;
}
pds = pds->pdsNext;
} while (--csurf);
}
}
else
{
pulIdent = (MULTISAVEBITS*)ulIdent;
ulRet = TRUE; // Assume success
do {
ulThisBits = pulIdent[pds->iDispSurf].ulBits;
flThisType = pulIdent[pds->iDispSurf].flType;
if (ulThisBits)
{
PDEVOBJ pdoThis(pds->hdev);
if (bIntersect(prcl, &pds->rcl, &rclThis))
{
rclThis.left -= pds->rcl.left;
rclThis.right -= pds->rcl.left;
rclThis.top -= pds->rcl.top;
rclThis.bottom -= pds->rcl.top;
}
else
{
rclThis = grclEmpty;
}
if ((flThisType == SS_GDI_DRIVER) &&
(PPFNVALID(pdoThis, SaveScreenBits)))
{
pfnSaveScreenBits = PPFNDRV(pdoThis, SaveScreenBits);
}
else
{
pfnSaveScreenBits = ulSimulateSaveScreenBits;
}
ulThisBits = pfnSaveScreenBits(pds->pso,
iMode,
ulThisBits,
&rclThis);
if ((ulThisBits == 0) && (iMode == SS_RESTORE))
{
// Ack, this driver failed to restore its screenbits.
// We'll have to tell USER that we failed, too. But
// first, we have to continue to free the screenbits of
// any drivers following in the DDML list:
ulRet = FALSE;
iMode = SS_FREE;
prcl = &grclEmpty;
}
}
pds = pds->pdsNext;
} while (--csurf);
EngFreeMem((VOID*) ulIdent);
}
return(ulRet);
}
/******************************Public*Routine******************************\
* VOID MulDeleteDeviceBitmap
*
* If the surface has been hooked by the DDML, do any clean-up required
* so that the surface can be deleted.
*
\**************************************************************************/
VOID MulDeleteDeviceBitmap(
DHSURF dhsurf)
{
MDSURF* pmdsurf;
VDEV* pvdev;
DISPSURF* pds;
SURFOBJ* psoMirror;
HSURF hsurfMirror;
pmdsurf = (MDSURF*) dhsurf;
pvdev = pmdsurf->pvdev;
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
psoMirror = pmdsurf->apso[pds->iDispSurf];
if (psoMirror != NULL)
{
// Note that EngDeleteSurface takes care of calling
// DrvDeleteDeviceBitmap:
hsurfMirror = psoMirror->hsurf;
EngUnlockSurface(psoMirror);
EngDeleteSurface(hsurfMirror);
}
}
// Note that GDI handles the freeing of the hsurfDevice bitmap.
EngFreeMem(pmdsurf);
}
/******************************Public*Routine******************************\
* HBITMAP MulCreateDeviceBitmap
*
* Screen readers and other clients of the DDML have to be able to watch
* all drawing calls to compatible bitmaps.
*
\**************************************************************************/
HBITMAP MulCreateDeviceBitmap(
DHPDEV dhpdev,
SIZEL sizl,
ULONG iFormat)
{
GDIFunctionID(MulCreateDeviceBitmap);
HSURF hsurfDevice;
HSURF hsurfMirror;
MDSURF* pmdsurf;
VDEV* pvdev;
DISPSURF* pds;
SURFOBJ* psoMirror;
SURFACE* psurfMirror;
FLONG flHooks;
pvdev = (VDEV*) dhpdev;
flHooks = 0;
pmdsurf = NULL;
hsurfDevice = NULL;
// First, pass the call to every mirrored driver and see if they
// want to create a Mirrored version:
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
PDEVOBJ poThis(pds->hdev);
if ((poThis.flGraphicsCaps() & GCAPS_LAYERED) &&
PPFNDRV(poThis, CreateDeviceBitmap))
{
// We compare to TRUE to allow for the possibility that
// in the future we'll change the return value to be
// something other than BOOL.
hsurfMirror = (HSURF) PPFNDRV(poThis, CreateDeviceBitmap)
(poThis.dhpdev(),
sizl,
iFormat);
if (hsurfMirror)
psoMirror = EngLockSurface(hsurfMirror);
else
psoMirror = NULL;
if (psoMirror)
{
if (pmdsurf == NULL)
{
hsurfDevice = (HSURF) EngCreateBitmap(sizl, 0, iFormat, BMF_TOPDOWN, NULL);
pmdsurf = (MDSURF*) EngAllocMem(
FL_ZERO_MEMORY,
sizeof(MDSURF) + pvdev->cSurfaces * sizeof(SURFOBJ*),
'fsVG');
if ((pmdsurf == NULL) || (hsurfDevice == NULL))
{
if (pmdsurf != NULL)
{
EngFreeMem(pmdsurf);
}
// Failure, so we're outta here...
EngUnlockSurface(psoMirror);
EngDeleteSurface(hsurfDevice);
return((HBITMAP) NULL);
}
pmdsurf->apso = (SURFOBJ**)
((BYTE*)pmdsurf + sizeof(MDSURF));
}
pmdsurf->pvdev = pvdev;
pmdsurf->apso[pds->iDispSurf] = psoMirror;
psurfMirror = SURFOBJ_TO_SURFACE_NOT_NULL(psoMirror);
psurfMirror->vSetMirror();
psurfMirror->hMirrorParent = hsurfDevice;
if (!poThis.bIsPalManaged())
{
// Dev bitmap will have device palette.
HPALETTE hpalDevice = (HPALETTE) poThis.ppalSurf()->hGet();
EPALOBJ palDeviceSurf(hpalDevice);
ASSERTGDI(palDeviceSurf.bValid(), "ERROR invalid palette\n");
psurfMirror->ppal(palDeviceSurf.ppalGet());
// Reference count it by making it not unlocked.
palDeviceSurf.ppalSet((PPALETTE)NULL);
}
}
}
}
// If any layering driver hooked the call, make our surface opaque
// so that we can catch all drawing calls.
if (pmdsurf != NULL)
{
SURFREF sr(hsurfDevice);
if (sr.bValid())
{
sr.ps->vSetEngCreateDeviceBitmap();
sr.ps->iType(STYPE_DEVBITMAP);
sr.ps->so.dhsurf = (DHSURF)pmdsurf;
flHooks = pvdev->flHooks;
// DrvCreateDeviceBitmap calls must always 'EngAssociateSurface'
// the returned bitmap:
EngAssociateSurface(hsurfDevice, pvdev->hdev, flHooks);
}
}
return((HBITMAP) hsurfDevice);
}
#ifdef OPENGL_MM
// ICD calls directly dispatch to real driver in API level, so it bypass DDML.
#else
/******************************Public*Routine******************************\
* BOOL MulSetPixelFormat
*
*
\**************************************************************************/
BOOL MulSetPixelFormat(
SURFOBJ* pso,
LONG iPixelFormat,
HWND hwnd)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
BOOL bRet = FALSE;
pvdev = (VDEV*) pso->dhpdev;
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
do {
PDEVOBJ pdo(pds->hdev);
if (PPFNVALID(pdo, SetPixelFormat))
{
bRet = (*PPFNDRV(pdo, SetPixelFormat))(pds->pso,
iPixelFormat,
hwnd);
}
pds = pds->pdsNext;
} while (--csurf != 0);
return(bRet);
}
/******************************Public*Routine******************************\
* LONG MulDescribePixelFormat
*
*
\**************************************************************************/
LONG MulDescribePixelFormat(
DHPDEV dhpdev,
LONG iPixelFormat,
ULONG cjpfd,
PIXELFORMATDESCRIPTOR* ppfd)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
DHPDEV dhpdevDriver;
LONG lRet = 0;
pvdev = (VDEV*) dhpdev;
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
do {
PDEVOBJ pdo(pds->hdev);
if (PPFNVALID(pdo, DescribePixelFormat))
{
dhpdevDriver = pds->pso->dhpdev;
lRet = (*PPFNDRV(pdo, DescribePixelFormat))(dhpdevDriver,
iPixelFormat,
cjpfd,
ppfd);
}
pds = pds->pdsNext;
} while (--csurf != 0);
return(lRet);
}
/******************************Public*Routine******************************\
* BOOL MulSwapBuffers
*
*
\**************************************************************************/
BOOL MulSwapBuffers(
SURFOBJ* pso,
WNDOBJ* pwo)
{
PVDEV pvdev;
PDISPSURF pds;
LONG csurf;
BOOL bRet = FALSE;
pvdev = (VDEV*) pso->dhpdev;
pds = pvdev->pds;
csurf = pvdev->cSurfaces;
do {
PDEVOBJ pdo(pds->hdev);
if (PPFNVALID(pdo, SwapBuffers))
{
bRet = (*PPFNDRV(pdo, SwapBuffers))(pds->pso,
pwo);
}
pds = pds->pdsNext;
} while (--csurf != 0);
return(bRet);
}
#endif // #ifdef OPENGL_MM
/******************************Public*Routine******************************\
* BOOL MulTextOut
*
* WARNING - WHEN OPTIMIZING
*
* When optimizing for one driver, remember that you'll still
* have to set the psurf on brushes to the driver's surface.
* Otherwise, you'll get a callback for DrvRealizeBrush.
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulTextOut(
SURFOBJ *pso,
STROBJ *pstro,
FONTOBJ *pfo,
CLIPOBJ *pco,
RECTL *prclExtra,
RECTL *prclOpaque,
BRUSHOBJ *pboFore,
BRUSHOBJ *pboOpaque,
POINTL *pptlOrg,
MIX mix)
{
PVDEV pvdev = (VDEV*) pso->dhpdev;
BOOL bRet = TRUE;
MSURF msurf;
ULONG cgposCopied;
RECTL rclOpaque;
ASSERTGDI((pboFore->iSolidColor != (ULONG) -1) &&
(pboOpaque->iSolidColor != (ULONG) -1),
"Didn't expect patterned brush");
if (pso->iType == STYPE_DEVBITMAP)
{
// Handle drawing to 'master' device bitmap:
MULTISURF mDst(pso);
bRet = EngTextOut(mDst.pso, pstro, pfo, pco, prclExtra, prclOpaque, pboFore,
pboOpaque, pptlOrg, mix);
}
MULTIBRUSH MBRUSH_Fore(pboFore, pvdev->cSurfaces, pvdev, pvdev->pso, MIX_NEEDS_PATTERN(mix));
if (!MBRUSH_Fore.Valid())
{
return (FALSE);
}
MULTIBRUSH MBRUSH_Opaque(pboOpaque, pvdev->cSurfaces, pvdev, pvdev->pso, MIX_NEEDS_PATTERN(mix));
if (!MBRUSH_Opaque.Valid())
{
return (FALSE);
}
MULTIFONT MFONT(pfo, pvdev->cSurfaces, pvdev);
if (!MFONT.Valid())
{
return (FALSE);
}
RECTL* prclBounds = (prclOpaque != NULL)
? prclOpaque
: &pstro->rclBkGround;
cgposCopied = ((ESTROBJ*)pstro)->cgposCopied;
rclOpaque = *prclBounds;
if (msurf.bFindSurface(pso, pco, prclBounds))
{
do {
STROBJ_vEnumStart(pstro);
MFONT.LoadElement(msurf.pds->iDispSurf);
MBRUSH_Fore.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
MBRUSH_Opaque.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
((ESTROBJ*)pstro)->cgposCopied = cgposCopied;
// Some drivers modify 'prclOpaque', so always pass them a copy:
*prclBounds = rclOpaque;
bRet &= OffTextOut(PPFNMGET(msurf, TextOut),
msurf.pOffset,
msurf.pso,
pstro,
pfo,
msurf.pco,
prclExtra,
prclOpaque,
pboFore,
pboOpaque,
pptlOrg,
mix);
MBRUSH_Fore.StoreElement(msurf.pds->iDispSurf);
MBRUSH_Opaque.StoreElement(msurf.pds->iDispSurf);
MFONT.StoreElement(msurf.pds->iDispSurf);
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulStrokePath
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulStrokePath(
SURFOBJ *pso,
PATHOBJ *ppo,
CLIPOBJ *pco,
XFORMOBJ *pxo,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
LINEATTRS *pla,
MIX mix)
{
PVDEV pvdev = (VDEV*) pso->dhpdev;
BOOL bRet = TRUE;
FLOAT_LONG elStyleState = pla->elStyleState;
MSURF msurf;
if (pso->iType == STYPE_DEVBITMAP)
{
// Handle drawing to 'master' device bitmap:
MULTISURF mDst(pso);
bRet = EngStrokePath(mDst.pso, ppo, pco, pxo, pbo, pptlBrushOrg, pla, mix);
}
MULTIBRUSH MBRUSH(pbo, pvdev->cSurfaces, pvdev, pvdev->pso, MIX_NEEDS_PATTERN(mix));
if (!MBRUSH.Valid())
{
return FALSE;
}
// Get the path bounds and make it lower-right exclusive:
RECTL rclDst;
RECTFX rcfxBounds;
PATHOBJ_vGetBounds(ppo, &rcfxBounds);
rclDst.left = (rcfxBounds.xLeft >> 4);
rclDst.top = (rcfxBounds.yTop >> 4);
rclDst.right = (rcfxBounds.xRight >> 4) + 2;
rclDst.bottom = (rcfxBounds.yBottom >> 4) + 2;
if (msurf.bFindSurface(pso, pco, &rclDst))
{
do {
PATHOBJ_vEnumStart(ppo);
pla->elStyleState = elStyleState;
MBRUSH.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
bRet &= OffStrokePath(PPFNMGET(msurf, StrokePath),
msurf.pOffset,
msurf.pso,
ppo,
msurf.pco,
pxo,
pbo,
pptlBrushOrg,
pla,
mix);
MBRUSH.StoreElement(msurf.pds->iDispSurf);
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulFillPath
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulFillPath(
SURFOBJ *pso,
PATHOBJ *ppo,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
POINTL *pptlBrushOrg,
MIX mix,
FLONG flOptions)
{
PVDEV pvdev = (VDEV*) pso->dhpdev;
BOOL bRet = TRUE;
MSURF msurf;
if (pso->iType == STYPE_DEVBITMAP)
{
// Handle drawing to 'master' device bitmap:
MULTISURF mDst(pso);
bRet = EngFillPath(mDst.pso, ppo, pco, pbo, pptlBrushOrg, mix, flOptions);
}
MULTIBRUSH MBRUSH(pbo, pvdev->cSurfaces, pvdev, pvdev->pso, MIX_NEEDS_PATTERN(mix));
if (!MBRUSH.Valid())
{
return FALSE;
}
// Get the path bounds and make it lower-right exclusive:
RECTL rclDst;
RECTFX rcfxBounds;
PATHOBJ_vGetBounds(ppo, &rcfxBounds);
rclDst.left = (rcfxBounds.xLeft >> 4);
rclDst.top = (rcfxBounds.yTop >> 4);
rclDst.right = (rcfxBounds.xRight >> 4) + 2;
rclDst.bottom = (rcfxBounds.yBottom >> 4) + 2;
if (msurf.bFindSurface(pso, pco, &rclDst))
{
do {
PATHOBJ_vEnumStart(ppo);
MBRUSH.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
bRet &= OffFillPath(PPFNMGET(msurf, FillPath),
msurf.pOffset,
msurf.pso,
ppo,
msurf.pco,
pbo,
pptlBrushOrg,
mix,
flOptions);
MBRUSH.StoreElement(msurf.pds->iDispSurf);
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulStrokeAndFillPath
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulStrokeAndFillPath(
SURFOBJ *pso,
PATHOBJ *ppo,
CLIPOBJ *pco,
XFORMOBJ *pxo,
BRUSHOBJ *pboStroke,
LINEATTRS *pla,
BRUSHOBJ *pboFill,
POINTL *pptlBrushOrg,
MIX mixFill,
FLONG flOptions)
{
PVDEV pvdev = (VDEV*) pso->dhpdev;
BOOL bRet = TRUE;
FLOAT_LONG elSavedStyleState = pla->elStyleState;
MSURF msurf;
if (pso->iType == STYPE_DEVBITMAP)
{
// Handle drawing to 'master' device bitmap:
MULTISURF mDst(pso);
bRet = EngStrokeAndFillPath(mDst.pso, ppo, pco, pxo, pboStroke, pla, pboFill,
pptlBrushOrg, mixFill, flOptions);
}
MULTIBRUSH MBRUSH_Stroke(pboStroke, pvdev->cSurfaces, pvdev, pvdev->pso, FALSE);
if (!MBRUSH_Stroke.Valid())
{
return FALSE;
}
MULTIBRUSH MBRUSH_Fill(pboFill, pvdev->cSurfaces, pvdev, pvdev->pso, MIX_NEEDS_PATTERN(mixFill));
if (!MBRUSH_Fill.Valid())
{
return FALSE;
}
// Get the path bounds and make it lower-right exclusive:
RECTL rclDst;
RECTFX rcfxBounds;
PATHOBJ_vGetBounds(ppo, &rcfxBounds);
rclDst.left = (rcfxBounds.xLeft >> 4);
rclDst.top = (rcfxBounds.yTop >> 4);
rclDst.right = (rcfxBounds.xRight >> 4) + 2;
rclDst.bottom = (rcfxBounds.yBottom >> 4) + 2;
if (msurf.bFindSurface(pso, pco, &rclDst))
{
do {
pla->elStyleState = elSavedStyleState;
PATHOBJ_vEnumStart(ppo);
MBRUSH_Stroke.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
MBRUSH_Fill.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
bRet &= OffStrokeAndFillPath(PPFNMGET(msurf, StrokeAndFillPath),
msurf.pOffset,
msurf.pso,
ppo,
msurf.pco,
pxo,
pboStroke,
pla,
pboFill,
pptlBrushOrg,
mixFill,
flOptions);
MBRUSH_Stroke.StoreElement(msurf.pds->iDispSurf);
MBRUSH_Fill.StoreElement(msurf.pds->iDispSurf);
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulLineTo
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulLineTo(
SURFOBJ *pso,
CLIPOBJ *pco,
BRUSHOBJ *pbo,
LONG x1,
LONG y1,
LONG x2,
LONG y2,
RECTL *prclBounds,
MIX mix)
{
PVDEV pvdev = (VDEV*) pso->dhpdev;
BOOL bRet = TRUE;
MSURF msurf;
if (pso->iType == STYPE_DEVBITMAP)
{
// Handle drawing to 'master' device bitmap:
MULTISURF mDst(pso,prclBounds);
bRet = EngLineTo(mDst.pso, pco, pbo, x1, y1, x2, y2, mDst.prcl, mix);
}
MULTIBRUSH MBRUSH(pbo, pvdev->cSurfaces, pvdev, pvdev->pso, FALSE);
if (!MBRUSH.Valid())
{
return FALSE;
}
if (msurf.bFindSurface(pso, pco, prclBounds))
{
do {
MBRUSH.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
bRet &= OffLineTo(PPFNMGET(msurf, LineTo),
msurf.pOffset,
msurf.pso,
msurf.pco,
pbo,
x1,
y1,
x2,
y2,
prclBounds,
mix);
MBRUSH.StoreElement(msurf.pds->iDispSurf);
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulGradientFill
*
* History:
* 23-Apr-1998 -by- Hideyuki Nagase [hideyukn]
* Wrote it.
*
\**************************************************************************/
BOOL MulGradientFill(
SURFOBJ *pso,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
TRIVERTEX *pVertex,
ULONG nVertex,
PVOID pMesh,
ULONG nMesh,
RECTL *prclExtents,
POINTL *pptlDitherOrg,
ULONG ulMode)
{
PVDEV pvdev = (VDEV*) pso->dhpdev;
XLATEOBJ *pxloSave = pxlo;
BOOL bRet = TRUE;
MSURF msurf;
if (pso->iType == STYPE_DEVBITMAP)
{
// Handle drawing to 'master' device bitmap:
MULTISURF mDst(pso,prclExtents);
bRet = EngGradientFill(mDst.pso, pco, pxlo, pVertex, nVertex, pMesh, nMesh,
mDst.prcl, pptlDitherOrg, ulMode);
}
if (msurf.bFindSurface(pso, pco, prclExtents))
{
do {
PSURFACE pSurfDest = SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso);
EXLATEOBJ xloDevice;
// if the target surface is not compatible to primary surface,
// create XLATEOBJ for source surface to target. otherwise
// we can just use given XLATEOBJ.
if (pSurfDest->iFormat() > BMF_8BPP)
{
// 16bpp or above do not require a translation object.
pxlo = NULL;
}
else if (msurf.pds->iCompatibleColorFormat != 0)
{
XLATE *pxloM = (XLATE *) pxlo;
PPALETTE ppalDestDC = ppalDefault;
PPALETTE ppalSurfSrc = gppalRGB;
PDEVOBJ pdo(msurf.pds->hdev);
if (pdo.bIsPalManaged())
{
// Use halftone palette for pal-managed device.
ppalDestDC = REALIZE_HALFTONE_PALETTE(pdo.hdev());
}
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
ppalSurfSrc, // Source palette
pSurfDest->ppal(), // Destination palette
ppalDestDC, // Source DC palette
ppalDestDC, // Destination DC palette
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L),
0))
{
pxlo = xloDevice.pxlo();
}
}
bRet &= OffGradientFill(PPFNMGET(msurf, GradientFill),
msurf.pOffset,
msurf.pso,
msurf.pco,
pxlo,
pVertex,
nVertex,
pMesh,
nMesh,
prclExtents,
pptlDitherOrg,
ulMode);
// Restore XLATEOBJ
pxlo = pxloSave;
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulStretchBlt
*
* History:
* 1-May-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
BOOL MulStretchBlt(
SURFOBJ* psoDst,
SURFOBJ* psoSrc,
SURFOBJ* psoMask,
CLIPOBJ* pco,
XLATEOBJ* pxlo,
COLORADJUSTMENT* pca,
POINTL* pptlHTOrg,
RECTL* prclDst,
RECTL* prclSrc,
POINTL* pptlMask,
ULONG iMode)
{
GDIFunctionID(MulStretchBlt);
XLATEOBJ *pxloSave = pxlo;
//
// We cannot handle cases where the source is a meta,
// so make a copy in this case.
//
SURFMEM srcCopy;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc);
PDEVOBJ pdoSrc(pSurfSrc->hdev());
RECTL rclSrcCopy = *prclSrc;
if( psoSrc->iType == STYPE_DEVICE && pdoSrc.bValid() &&
pdoSrc.bMetaDriver())
{
if(!MulCopyDeviceToDIB( psoSrc, &srcCopy, &rclSrcCopy ))
return FALSE;
if(srcCopy.ps == NULL)
{
// We didn't get to the point of creating the surface
// becasue the rect was out of bounds.
return TRUE;
}
prclSrc = &rclSrcCopy;
psoSrc = srcCopy.pSurfobj();
pSurfSrc= SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc);
pdoSrc.vInit(pSurfSrc->hdev());
}
//
// Inverting stretches are a pain because 'bFindSurface' doesn't
// understand poorly ordered rectangles. So we'll make yet
// another copy of the source in this case.
//
SURFMEM srcInv;
RECTL rclDstCopy;
PPALETTE ppalSrc = pSurfSrc->ppal();
if ((prclDst->left >= prclDst->right) ||
(prclDst->top >= prclDst->bottom))
{
DEVBITMAPINFO dbmi;
RECTL rclSrcClip = *prclSrc;
if( rclSrcClip.left < 0 )
{
rclSrcClip.left = 0;
}
if( rclSrcClip.right > pSurfSrc->sizl().cx )
{
rclSrcClip.right = pSurfSrc->sizl().cx;
}
if( rclSrcClip.top < 0 )
{
rclSrcClip.top = 0;
}
if( rclSrcClip.bottom > pSurfSrc->sizl().cy )
{
rclSrcClip.bottom = pSurfSrc->sizl().cy;
}
if( (rclSrcClip.right <= rclSrcClip.left) ||
(rclSrcClip.bottom <= rclSrcClip.top ) )
{
return TRUE;
}
dbmi.cxBitmap = rclSrcClip.right - rclSrcClip.left;
dbmi.cyBitmap = rclSrcClip.bottom - rclSrcClip.top;
dbmi.hpal = ppalSrc ? ((HPALETTE) ppalSrc->hGet()) : 0;
dbmi.iFormat = pSurfSrc->iFormat();
dbmi.fl = pSurfSrc->bUMPD() ? UMPD_SURFACE : 0;
srcInv.bCreateDIB(&dbmi, (VOID *) NULL);
if (!srcInv.bValid())
return(FALSE);
rclSrcCopy.left -= rclSrcClip.left;
rclSrcCopy.right -= rclSrcClip.left;
rclSrcCopy.top -= rclSrcClip.top;
rclSrcCopy.bottom -= rclSrcClip.top;
RECTL rclInv;
// Setup for x-inversion
if( prclDst->left >= prclDst->right )
{
rclDstCopy.left = prclDst->right;
rclDstCopy.right= prclDst->left;
rclInv.left = rclSrcCopy.right;
rclInv.right = rclSrcCopy.left;
}
else
{
rclDstCopy.left = prclDst->left;
rclDstCopy.right= prclDst->right;
rclInv.left = rclSrcCopy.left;
rclInv.right = rclSrcCopy.right;
}
// Setup for y-inversion
if( prclDst->top >= prclDst->bottom )
{
rclDstCopy.top = prclDst->bottom;
rclDstCopy.bottom = prclDst->top;
rclInv.top = rclSrcCopy.bottom;
rclInv.bottom = rclSrcCopy.top;
}
else
{
rclDstCopy.top = prclDst->top;
rclDstCopy.bottom = prclDst->bottom;
rclInv.top = rclSrcCopy.top;
rclInv.bottom = rclSrcCopy.bottom;
}
// Do the actual inversion
if(!EngStretchBlt(srcInv.pSurfobj(), psoSrc, NULL, (CLIPOBJ *)NULL, &xloIdent, NULL,
NULL, &rclInv, prclSrc, NULL, COLORONCOLOR))
return FALSE;
prclSrc = &rclSrcCopy;
prclDst = &rclDstCopy;
psoSrc = srcInv.pSurfobj();
pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc);
pdoSrc.vInit(pSurfSrc->hdev());
}
PVDEV pvdev = (VDEV*) psoDst->dhpdev;
USHORT iDstType = psoDst->iType;
BOOL bMultiDst;
BOOL bRet = TRUE;
MSURF msurf;
RECTL rclDst;
RECTL rclSrc;
ASSERTGDI(iDstType != STYPE_BITMAP, "BITMAP destination\n");
bMultiDst = msurf.bFindSurface(psoDst, pco, prclDst);
// WINBUG #298689 4-4-2001 jasonha Handle multi-device stretches
MULTISURF mSrc(psoSrc, prclSrc);
//
// If the destination is a Device Bitmap, we must draw to
// the master DIB also.
//
if (iDstType == STYPE_DEVBITMAP)
{
MULTISURF mDst(psoDst,prclDst);
bRet = EngStretchBlt(mDst.pso, mSrc.pso, psoMask, pco, pxlo, pca,
pptlHTOrg, mDst.prcl, mSrc.prcl, pptlMask, iMode);
}
if (bMultiDst)
{
do {
BOOL bError;
EXLATEOBJ xloDevice;
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso);
bError = !mSrc.bLoadSource(msurf.pds);
if (bError == FALSE)
{
pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(mSrc.pso);
ppalSrc = pSurfSrc->ppal();
// if the target surface is not compatible to primary surface,
// create XLATEOBJ for source surface to target. otherwise
// we can just use given XLATEOBJ.
if (msurf.pds->iCompatibleColorFormat != 0)
{
XLATE *pxloM = (XLATE *) pxlo;
PPALETTE ppalDestDC = ppalDefault;
PDEVOBJ pdoDst(msurf.pds->hdev);
if (pdoDst.bIsPalManaged())
{
// Use halftone palette for pal-managed device.
ppalDestDC = REALIZE_HALFTONE_PALETTE(pdoDst.hdev());
}
if (!ppalSrc)
{
// Source surface does not have associated palette.
// (Source surface is compatible bitmap)
if (pxloM && pxloM->ppalSrc)
{
// if XLATEOBJ has source palette, use it.
ppalSrc = pxloM->ppalSrc;
}
else
{
PSURFACE pSurfTmp = SURFOBJ_TO_SURFACE_NOT_NULL(psoDst);
if ((pxloM == NULL) || pxloM->bIsIdentity())
{
// if translation is identity, we can use the palette for
// meta-destination surface as source. since it's trivial.
// WINBUG #396667 10-03-2001 jasonha A/V due to improper XLATE setup
if (mSrc.pso == psoSrc)
{
ppalSrc = pSurfTmp->ppal();
}
}
else if (pxloM->ppalDstDC)
{
// We are bitblting from compatible bitmap to a surface in
// meta-surface. but we are not in foreground.
ppalDestDC = pxloM->ppalDstDC;
// WINBUG #274637 02-12-2001 jasonha A/V due to improper XLATE setup
if (pSurfSrc->iFormat() == pSurfTmp->iFormat())
{
// We are bitblting from a compatible bitmap that is
// not palettized but is a the same format as the
// meta-surface, so we use the destination palette.
ppalSrc = pSurfTmp->ppal();
}
}
else
{
#if HIDEYUKN_DBG
DbgPrint("GDI DDML: MulStretchBlt(): ppalSrc is NULL\n");
DbgBreakPoint();
#endif
bError = TRUE;
}
}
}
if (bError == FALSE)
{
XEPALOBJ palSurfSrc(ppalSrc);
ULONG flFlags = 0;
if (palSurfSrc.bValid() && palSurfSrc.bIsPalManaged())
{
// Source is palette managed surface.
if (ppalDestDC == ppalDefault)
{
// We don't know DC palette here, but we know we are in foregroud,
// (since translation is trivial)
// so, we just map from source surface palette to destination
// surface palette directly (destination is at least higher color
// depth than source).
flFlags = XLATE_USE_SURFACE_PAL;
}
else
{
// We may not be in foreground. but map from foreground translation
// in source, so that we will not loose original color on secondary
// devices which can produce higher color depth then source.
flFlags = XLATE_USE_FOREGROUND;
}
}
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
palSurfSrc, // Source palette
pSurfDst->ppal(), // Destination palette
ppalDefault, // Source DC palette
ppalDestDC, // Destination DC palette
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L),
flFlags))
{
pxlo = xloDevice.pxlo();
}
else
{
bError = TRUE;
}
}
}
}
if (bError == FALSE)
{
PFN_DrvStretchBlt pfn = PPFNMGET(msurf, StretchBlt);
//
// If the source is also a device surface, it must correspond
// to one of the drivers. In this case, call Eng if the
// same driver does not manage the source and the destination
//
if( mSrc.pso->iType == STYPE_DEVICE &&
(pSurfSrc->hdev() != pSurfDst->hdev()))
{
pfn = (PFN_DrvStretchBlt)EngStretchBlt;
}
//
// If the driver does not support halftoning we call Eng
//
if( iMode == HALFTONE )
{
PDEVOBJ pdoTrg(pSurfDst->hdev());
if (!(pdoTrg.flGraphicsCapsNotDynamic() & GCAPS_HALFTONE))
pfn = (PFN_DrvStretchBlt)EngStretchBlt;
}
// Don't call the driver if the source rectangle exceeds the source
// surface. Some drivers punt using a duplicate of the source
// SURFOBJ, but without preserving its sizlBitmap member.
// This causes a source clipping bug (77102).
if((mSrc.prcl->left < 0) ||
(mSrc.prcl->top < 0) ||
(mSrc.prcl->right > mSrc.pso->sizlBitmap.cx) ||
(mSrc.prcl->bottom > mSrc.pso->sizlBitmap.cy))
{
pfn = (PFN_DrvStretchBlt)EngStretchBlt;
}
bRet &= OffStretchBlt(pfn,
msurf.pOffset,
msurf.pso,
&gptlZero,
mSrc.pso,
psoMask,
msurf.pco,
pxlo,
pca,
pptlHTOrg,
prclDst,
mSrc.prcl,
pptlMask,
iMode);
}
else
{
bRet = FALSE;
}
// Restore XLATEOBJ
pxlo = pxloSave;
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulAlphaBlend
*
* History:
* 17-dec-1998 -by- Andre Matos [amatos]
* Wrote it.
*
\**************************************************************************/
BOOL MulAlphaBlend(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
RECTL *prclSrc,
BLENDOBJ *pBlendObj)
{
GDIFunctionID(MulAlphaBlend);
XLATEOBJ *pxloSave = pxlo;
XLATEOBJ *pxloSaveDCto32 = ((EBLENDOBJ*)pBlendObj)->pxloDstTo32;
XLATEOBJ *pxloSave32toDC = ((EBLENDOBJ*)pBlendObj)->pxlo32ToDst;
XLATEOBJ *pxloSaveSrcTo32 = ((EBLENDOBJ*)pBlendObj)->pxloSrcTo32;
//
// We cannot handle cases where the source is a meta,
// so make a copy in this case.
//
SURFMEM srcCopy;
PDEVOBJ pdoSrc(SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc)->hdev());
RECTL rclCopy = *prclSrc;
if( psoSrc->iType == STYPE_DEVICE && pdoSrc.bValid() &&
pdoSrc.bMetaDriver())
{
if(!MulCopyDeviceToDIB( psoSrc, &srcCopy, &rclCopy ))
return FALSE;
if(srcCopy.ps == NULL )
{
// We didn't get to the point of creating the surface
// becasue the rect was out of bounds.
return TRUE;
}
prclSrc = &rclCopy;
psoSrc = srcCopy.pSurfobj();
pdoSrc.vInit(SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc)->hdev());
}
PVDEV pvdev = (VDEV*) psoDst->dhpdev;
USHORT iDstType = psoDst->iType;
BOOL bMultiDst;
BOOL bRet = TRUE;
MSURF msurf;
RECTL rclDst;
RECTL rclSrc;
ASSERTGDI(iDstType != STYPE_BITMAP, "BITMAP destination\n");
bMultiDst = msurf.bFindSurface(psoDst, pco, prclDst);
MULTISURF mSrc(psoSrc,prclSrc);
//
// If the destination is a Device Bitmap, we must draw to
// the master DIB also.
//
if (iDstType == STYPE_DEVBITMAP)
{
MULTISURF mDst(psoDst,prclDst);
bRet = EngAlphaBlend(mDst.pso, mSrc.pso, pco, pxlo, mDst.prcl,
mSrc.prcl, pBlendObj);
}
if (bMultiDst)
{
do {
BOOL bError = FALSE;
EXLATEOBJ xloDevice;
EXLATEOBJ xloDstDCto32;
EXLATEOBJ xlo32toDstDC;
EXLATEOBJ xloSrcTo32;
XEPALOBJ palRGB(gppalRGB);
bError = !mSrc.bLoadSource(msurf.pds);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso);
PSURFACE pSurfSrc;
if (bError == FALSE)
{
pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(mSrc.pso);
// if the target surface is not compatible to primary surface,
// create XLATEOBJ for source surface to target. otherwise
// we can just use given XLATEOBJ.
if (msurf.pds->iCompatibleColorFormat != 0)
{
XLATE *pxloM = (XLATE *) pxlo;
PPALETTE ppalSrc = pSurfSrc->ppal();
PPALETTE ppalDestDC = ppalDefault;
PDEVOBJ pdoDst(msurf.pds->hdev);
if (pdoDst.bIsPalManaged())
{
// Use halftone palette for pal-managed device.
ppalDestDC = REALIZE_HALFTONE_PALETTE(pdoDst.hdev());
}
if (!ppalSrc)
{
// Source surface does not have associated palette.
// (Source surface is compatible bitmap)
if (pxloM && pxloM->ppalSrc)
{
// if XLATEOBJ has source palette, use it.
ppalSrc = pxloM->ppalSrc;
}
else
{
PSURFACE pSurfTmp = SURFOBJ_TO_SURFACE_NOT_NULL(psoDst);
if ((pxloM == NULL) || pxloM->bIsIdentity())
{
// if translation is identity, we can use the palette for
// meta-destination surface as source. since it's trivial.
// WINBUG #396667 10-03-2001 jasonha A/V due to improper XLATE setup
if (mSrc.pso == psoSrc)
{
ppalSrc = pSurfTmp->ppal();
}
}
else if (pxloM->ppalDstDC)
{
// We are bitblting from compatible bitmap to a surface in
// meta-surface. but we are not in foreground.
ppalDestDC = pxloM->ppalDstDC;
// WINBUG #274637 02-12-2001 jasonha A/V due to improper XLATE setup
if (pSurfSrc->iFormat() == pSurfTmp->iFormat())
{
// We are bitblting from a compatible bitmap that is
// not palettized but is a the same format as the
// meta-surface, so we use the destination palette.
ppalSrc = pSurfTmp->ppal();
}
}
else
{
#if HIDEYUKN_DBG
DbgPrint("GDI DDML: MulAlphaBlend(): ppalSrc is NULL\n");
DbgBreakPoint();
#endif
bError = TRUE;
}
}
}
if (bError == FALSE)
{
XEPALOBJ palSurfSrc(ppalSrc);
ULONG flFlags = 0;
if (palSurfSrc.bValid() && palSurfSrc.bIsPalManaged())
{
// Source is palette managed surface.
if (ppalDestDC == ppalDefault)
{
// We don't know DC palette here, but we know we are in foregroud,
// (since translation is trivial)
// so, we just map from source surface palette to destination
// surface palette directly (destination is at least higher color
// depth than source).
flFlags = XLATE_USE_SURFACE_PAL;
}
else
{
// We may not be in foreground. but map from foreground translation
// in source, so that we will not loose original color on secondary
// devices which can produce higher color depth then source.
flFlags = XLATE_USE_FOREGROUND;
}
}
ULONG iForeDst;
if( pxloM )
{
iForeDst = pxloM->iForeDst;
}
else
{
iForeDst = 0x0L;
}
ULONG iBackDst;
if( pxloM )
{
iBackDst = pxloM->iBackDst;
}
else
{
iBackDst = 0x0L;
}
ULONG iBackSrc;
if( pxloM )
{
iBackSrc = pxloM->iBackSrc;
}
else
{
iBackSrc = 0x0L;
}
//
// Src to Dst
//
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
palSurfSrc, // Source palette
pSurfDst->ppal(), // Destination palette
ppalDefault, // Source DC palette
ppalDestDC, // Destination DC palette
iForeDst,
iBackDst,
iBackSrc,
flFlags))
{
pxlo = xloDevice.pxlo();
}
else
{
bError = TRUE;
}
//
// Dst to 32
//
if ((bError == FALSE) &&
xloDstDCto32.bInitXlateObj(
NULL,
DC_ICM_OFF,
pSurfDst->ppal(),
palRGB,
ppalDestDC,
ppalDestDC,
iForeDst,
iBackDst,
iBackSrc))
{
((EBLENDOBJ*)pBlendObj)->pxloDstTo32 = xloDstDCto32.pxlo();
}
else
{
bError = TRUE;
}
//
// 32 to Dst
//
if ((bError == FALSE) &&
xlo32toDstDC.bInitXlateObj(
NULL,
DC_ICM_OFF,
palRGB,
pSurfDst->ppal(),
ppalDestDC,
ppalDestDC,
iForeDst,
iBackDst,
iBackSrc))
{
((EBLENDOBJ*)pBlendObj)->pxlo32ToDst = xlo32toDstDC.pxlo();
}
else
{
bError = TRUE;
}
//
// Src to 32
//
if ((bError == FALSE) &&
(mSrc.pso != psoSrc))
{
if (xloSrcTo32.bInitXlateObj(
NULL,
DC_ICM_OFF,
pSurfSrc->ppal(),
palRGB,
ppalDefault,
ppalDestDC,
iForeDst,
iBackDst,
iBackSrc))
{
((EBLENDOBJ*)pBlendObj)->pxloSrcTo32 = xloSrcTo32.pxlo();
}
else
{
bError = TRUE;
}
}
}
}
}
if (bError == FALSE)
{
PFN_DrvAlphaBlend pfn = PPFNMGET(msurf, AlphaBlend);
//
// If the source is also a device surface, it must correspond
// to one of the drivers. In this case, call Eng if the
// same driver does not manage the source and the destination
//
if( mSrc.pso->iType == STYPE_DEVICE &&
(pSurfSrc->hdev() != pSurfDst->hdev()))
{
pfn = (PFN_DrvAlphaBlend)EngAlphaBlend;
}
bRet &= OffAlphaBlend(pfn,
msurf.pOffset,
msurf.pso,
&gptlZero,
mSrc.pso,
msurf.pco,
pxlo,
prclDst,
mSrc.prcl,
pBlendObj);
}
else
{
bRet = FALSE;
}
// Restore XLATEOBJ
pxlo = pxloSave;
((EBLENDOBJ*)pBlendObj)->pxloDstTo32 = pxloSaveDCto32;
((EBLENDOBJ*)pBlendObj)->pxlo32ToDst = pxloSave32toDC;
((EBLENDOBJ*)pBlendObj)->pxloSrcTo32 = pxloSaveSrcTo32;
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulTransparentBlt
*
* History:
* 22-Dec-1998 -by- Andre Matos [amatos]
* Wrote it.
*
\**************************************************************************/
BOOL MulTransparentBlt(
SURFOBJ* psoDst,
SURFOBJ* psoSrc,
CLIPOBJ* pco,
XLATEOBJ* pxlo,
RECTL* prclDst,
RECTL* prclSrc,
ULONG TransColor,
ULONG ulReserved)
{
GDIFunctionID(MulTransparentBlt);
XLATEOBJ *pxloSave = pxlo;
ULONG TransColorSave = TransColor;
//
// We cannot handle cases where the source is a meta,
// so make a copy in this case.
//
SURFMEM srcCopy;
PDEVOBJ pdoSrc(SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc)->hdev());
RECTL rclCopy = *prclSrc;
if( psoSrc->iType == STYPE_DEVICE && pdoSrc.bValid() &&
pdoSrc.bMetaDriver())
{
if(!MulCopyDeviceToDIB( psoSrc, &srcCopy, &rclCopy ))
return FALSE;
if(srcCopy.ps == NULL )
{
// We didn't get to the point of creating the surface
// becasue the rect was out of bounds.
return TRUE;
}
prclSrc = &rclCopy;
psoSrc = srcCopy.pSurfobj();
pdoSrc.vInit(SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc)->hdev());
}
PVDEV pvdev = (VDEV*) psoDst->dhpdev;
USHORT iDstType = psoDst->iType;
BOOL bMultiDst;
BOOL bRet = TRUE;
MSURF msurf;
RECTL rclDst;
RECTL rclSrc;
ASSERTGDI(iDstType != STYPE_BITMAP, "BITMAP destination\n");
bMultiDst = msurf.bFindSurface(psoDst, pco, prclDst);
MULTISURF mSrc(psoSrc,prclSrc);
//
// If the destination is a Device Bitmap, we must draw to
// the master DIB also.
//
if (iDstType == STYPE_DEVBITMAP)
{
MULTISURF mDst(psoDst,prclDst);
bRet = EngTransparentBlt(mDst.pso, mSrc.pso, pco, pxlo,
mDst.prcl, mSrc.prcl, TransColor, ulReserved);
}
if (bMultiDst)
{
do {
BOOL bError = FALSE;
EXLATEOBJ xloDevice;
bError = !mSrc.bLoadSource(msurf.pds);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso);
PSURFACE pSurfSrc;
if (bError == FALSE)
{
pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(mSrc.pso);
// if the target surface is not compatible to primary surface,
// create XLATEOBJ for source surface to target. otherwise
// we can just use given XLATEOBJ.
if (msurf.pds->iCompatibleColorFormat != 0)
{
XLATE *pxloM = (XLATE *) pxlo;
PPALETTE ppalSrc = pSurfSrc->ppal();
PPALETTE ppalDestDC = ppalDefault;
PDEVOBJ pdoDst(msurf.pds->hdev);
if (pdoDst.bIsPalManaged())
{
// Use halftone palette for pal-managed device.
ppalDestDC = REALIZE_HALFTONE_PALETTE(pdoDst.hdev());
}
if (!ppalSrc)
{
// Source surface does not have associated palette.
// (Source surface is compatible bitmap)
if (pxloM && pxloM->ppalSrc)
{
// if XLATEOBJ has source palette, use it.
ppalSrc = pxloM->ppalSrc;
}
else
{
PSURFACE pSurfTmp = SURFOBJ_TO_SURFACE_NOT_NULL(psoDst);
if ((pxloM == NULL) || pxloM->bIsIdentity())
{
// if translation is identity, we can use the palette for
// meta-destination surface as source. since it's trivial.
// WINBUG #396667 10-03-2001 jasonha A/V due to improper XLATE setup
if (mSrc.pso == psoSrc)
{
ppalSrc = pSurfTmp->ppal();
}
}
else if (pxloM->ppalDstDC)
{
// We are bitblting from compatible bitmap to a surface in
// meta-surface. but we are not in foreground.
ppalDestDC = pxloM->ppalDstDC;
// WINBUG #274637 02-12-2001 jasonha A/V due to improper XLATE setup
if (pSurfSrc->iFormat() == pSurfTmp->iFormat())
{
// We are bitblting from a compatible bitmap that is
// not palettized but is a the same format as the
// meta-surface, so we use the destination palette.
ppalSrc = pSurfTmp->ppal();
}
}
else
{
#if HIDEYUKN_DBG
DbgPrint("GDI DDML: MulTransparent(): ppalSrc is NULL\n");
DbgBreakPoint();
#endif
bError = TRUE;
}
}
}
if (bError == FALSE)
{
XEPALOBJ palSurfSrc(ppalSrc);
ULONG flFlags = 0;
if (palSurfSrc.bValid() && palSurfSrc.bIsPalManaged())
{
// Source is palette managed surface.
if (ppalDestDC == ppalDefault)
{
// We don't know DC palette here, but we know we are in foregroud,
// (since translation is trivial)
// so, we just map from source surface palette to destination
// surface palette directly (destination is at least higher color
// depth than source).
flFlags = XLATE_USE_SURFACE_PAL;
}
else
{
// We may not be in foreground. but map from foreground translation
// in source, so that we will not loose original color on secondary
// devices which can produce higher color depth then source.
flFlags = XLATE_USE_FOREGROUND;
}
}
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
palSurfSrc, // Source palette
pSurfDst->ppal(), // Destination palette
ppalDefault, // Source DC palette
ppalDestDC, // Destination DC palette
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L),
flFlags))
{
pxlo = xloDevice.pxlo();
}
else
{
bError = TRUE;
}
}
}
if (mSrc.pso != psoSrc)
{
PSURFACE pSurfSrcOrg = SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc);
TransColor =
ulGetNearestIndexFromColorref(
pSurfSrc->ppal(),
ppalDefault,
ulIndexToRGB(
pSurfSrcOrg->ppal(),
ppalDefault,
TransColor),
SE_DO_SEARCH_EXACT_FIRST);
}
}
if (bError == FALSE)
{
PFN_DrvTransparentBlt pfn = PPFNMGET(msurf, TransparentBlt);
//
// If the source is also a device surface, it must correspond
// to one of the drivers. In this case, call Eng if the
// same driver does not manage the source and the destination
//
if( mSrc.pso->iType == STYPE_DEVICE &&
(pSurfSrc->hdev() != pSurfDst->hdev()))
{
pfn = (PFN_DrvTransparentBlt)EngTransparentBlt;
}
bRet &= OffTransparentBlt(pfn,
msurf.pOffset,
msurf.pso,
&gptlZero,
mSrc.pso,
msurf.pco,
pxlo,
prclDst,
mSrc.prcl,
TransColor,
ulReserved);
}
else
{
bRet = FALSE;
}
// Restore XLATEOBJ
pxlo = pxloSave;
TransColor = TransColorSave;
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulDrawStream
*
* 1-27-2001 bhouse
* Wrote it.
*
\**************************************************************************/
BOOL MulDrawStream(
SURFOBJ* psoDst,
SURFOBJ* psoSrc,
CLIPOBJ* pco,
XLATEOBJ* pxlo,
RECTL* prclDstBounds,
POINTL* pptlDstOffset,
ULONG ulIn,
PVOID pvIn,
DSSTATE* pdss)
{
GDIFunctionID(MulDrawStream);
XLATEOBJ * pxloSave = pxlo;
PDRAWSTREAMINFO pdsi = (PDRAWSTREAMINFO) pdss;
XLATEOBJ * pxloSaveDstToBGRA = pdsi->pxloDstToBGRA;
XLATEOBJ * pxloSaveBGRAToDst = pdsi->pxloBGRAToDst;
XLATEOBJ * pxloSaveSrcToBGRA = pdsi->pxloSrcToBGRA;
COLORREF crSaveColorKey = pdsi->dss.crColorKey;
//
// We cannot handle cases where the source is a meta,
// so make a copy in this case.
//
PDEVOBJ pdoSrc(SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc)->hdev());
if( psoSrc->iType == STYPE_DEVICE && pdoSrc.bValid() &&
pdoSrc.bMetaDriver())
{
DbgPrint("MulDrawStream: this should never happen\n");
return TRUE;
}
PVDEV pvdev = (VDEV*) psoDst->dhpdev;
USHORT iDstType = psoDst->iType;
BOOL bMultiDst;
BOOL bRet = TRUE;
MSURF msurf;
RECTL rclDst;
RECTL rclSrc;
ASSERTGDI(iDstType != STYPE_BITMAP, "BITMAP destination\n");
bMultiDst = msurf.bFindSurface(psoDst, pco, prclDstBounds);
MULTISURF mSrc(psoSrc);
//
// If the destination is a Device Bitmap, we must draw to
// the master DIB also.
//
if (iDstType == STYPE_DEVBITMAP)
{
MULTISURF mDst(psoDst);
bRet = EngDrawStream(mDst.pso, mSrc.pso, pco, pxlo,
prclDstBounds, pptlDstOffset, ulIn, pvIn, pdss);
}
// TODO bhouse
// Need to fix translates in pdsi
if (bMultiDst)
{
do {
BOOL bError = FALSE;
EXLATEOBJ xloDevice;
EXLATEOBJ xloDstToBGRA;
EXLATEOBJ xloBGRAToDst;
EXLATEOBJ xloSrcToBGRA;
XEPALOBJ palRGB(gppalRGB);
bError = !mSrc.bLoadSource(msurf.pds);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso);
PSURFACE pSurfSrc;
if (bError == FALSE)
{
pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(mSrc.pso);
// if the target surface is not compatible to primary surface,
// create XLATEOBJ for source surface to target. otherwise
// we can just use given XLATEOBJ.
if (msurf.pds->iCompatibleColorFormat != 0)
{
XLATE *pxloM = (XLATE *) pxlo;
PPALETTE ppalSrc = pSurfSrc->ppal();
PPALETTE ppalDestDC = ppalDefault;
PDEVOBJ pdoDst(msurf.pds->hdev);
if (pdoDst.bIsPalManaged())
{
// Use halftone palette for pal-managed device.
ppalDestDC = REALIZE_HALFTONE_PALETTE(pdoDst.hdev());
}
if (!ppalSrc)
{
// Source surface does not have associated palette.
// (Source surface is compatible bitmap)
if (pxloM && pxloM->ppalSrc)
{
// if XLATEOBJ has source palette, use it.
ppalSrc = pxloM->ppalSrc;
}
else
{
PSURFACE pSurfTmp = SURFOBJ_TO_SURFACE_NOT_NULL(psoDst);
if ((pxloM == NULL) || pxloM->bIsIdentity())
{
// if translation is identity, we can use the palette for
// meta-destination surface as source. since it's trivial.
// WINBUG #396667 10-03-2001 jasonha A/V due to improper XLATE setup
if (mSrc.pso == psoSrc)
{
ppalSrc = pSurfTmp->ppal();
}
}
else if (pxloM->ppalDstDC)
{
// We are bitblting from compatible bitmap to a surface in
// meta-surface. but we are not in foreground.
ppalDestDC = pxloM->ppalDstDC;
// WINBUG #274637 02-12-2001 jasonha A/V due to improper XLATE setup
if (pSurfSrc->iFormat() == pSurfTmp->iFormat())
{
// We are bitblting from a compatible bitmap that is
// not palettized but is a the same format as the
// meta-surface, so we use the destination palette.
ppalSrc = pSurfTmp->ppal();
}
}
else
{
#if HIDEYUKN_DBG
DbgPrint("GDI DDML: MulDrawStream(): ppalSrc is NULL\n");
DbgBreakPoint();
#endif
bError = TRUE;
}
}
}
if (bError == FALSE)
{
XEPALOBJ palSurfSrc(ppalSrc);
ULONG flFlags = 0;
if (palSurfSrc.bValid() && palSurfSrc.bIsPalManaged())
{
// Source is palette managed surface.
if (ppalDestDC == ppalDefault)
{
// We don't know DC palette here, but we know we are in foregroud,
// (since translation is trivial)
// so, we just map from source surface palette to destination
// surface palette directly (destination is at least higher color
// depth than source).
flFlags = XLATE_USE_SURFACE_PAL;
}
else
{
// We may not be in foreground. but map from foreground translation
// in source, so that we will not loose original color on secondary
// devices which can produce higher color depth then source.
flFlags = XLATE_USE_FOREGROUND;
}
}
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
palSurfSrc, // Source palette
pSurfDst->ppal(), // Destination palette
ppalDefault, // Source DC palette
ppalDestDC, // Destination DC palette
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L),
flFlags))
{
pxlo = xloDevice.pxlo();
}
else
{
bError = TRUE;
}
if ((bError == FALSE) &&
xloDstToBGRA.bInitXlateObj(
NULL,
DC_ICM_OFF,
pSurfDst->ppal(),
palRGB,
ppalDestDC,
ppalDestDC,
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L)))
{
pdsi->pxloDstToBGRA = xloDstToBGRA.pxlo();
}
else
{
bError = TRUE;
}
//
// 32 to Dst
//
if ((bError == FALSE) &&
xloBGRAToDst.bInitXlateObj(
NULL,
DC_ICM_OFF,
palRGB,
pSurfDst->ppal(),
ppalDestDC,
ppalDestDC,
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L)))
{
pdsi->pxloBGRAToDst = xloBGRAToDst.pxlo();
}
else
{
bError = TRUE;
}
if ((bError == FALSE) &&
(mSrc.pso != psoSrc))
{
//
// Src to 32
//
if (xloSrcToBGRA.bInitXlateObj(
NULL,
DC_ICM_OFF,
pSurfSrc->ppal(),
palRGB,
ppalDefault,
ppalDestDC,
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L)))
{
pdsi->pxloSrcToBGRA = xloSrcToBGRA.pxlo();
}
else
{
bError = TRUE;
}
if (bError == FALSE)
{
PSURFACE pSurfSrcOrg = SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc);
pdsi->dss.crColorKey =
ulGetNearestIndexFromColorref(
pSurfSrc->ppal(),
ppalDefault,
ulIndexToRGB(
pSurfSrcOrg->ppal(),
ppalDefault,
pdsi->dss.crColorKey),
SE_DO_SEARCH_EXACT_FIRST);
}
}
}
}
}
if (bError == FALSE)
{
PFN_DrvDrawStream pfn = PPFNDRVENG(msurf.pds->po, DrawStream);
//
// If the source is also a device surface, it must correspond
// to one of the drivers. In this case, call Eng if the
// same driver does not manage the source and the destination
//
if( mSrc.pso->iType == STYPE_DEVICE &&
(pSurfSrc->hdev() != pSurfDst->hdev()))
{
pfn = (PFN_DrvDrawStream) EngDrawStream;
}
bRet &= OffDrawStream(pfn,
msurf.pOffset,
msurf.pso,
mSrc.pso,
msurf.pco,
pxlo,
prclDstBounds,
pptlDstOffset,
ulIn,
pvIn,
pdss);
}
else
{
bRet = FALSE;
}
// Restore XLATEOBJ
pxlo = pxloSave;
pdsi->pxloBGRAToDst = pxloSaveBGRAToDst;
pdsi->pxloDstToBGRA = pxloSaveDstToBGRA;
pdsi->pxloSrcToBGRA = pxloSaveSrcToBGRA;
pdsi->dss.crColorKey = crSaveColorKey;
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL bSrcBeforeDst
*
* This function determines if the source rectangle, offset by dx and dy,
* will intersect the destination rectangle. In other words, the source
* will be required to do the blt to the destination. This means that the
* blt must be done to the destination before the blt to the source so that
* the source bits are not overwritten before they're used.
*
* History:
* 25-Apr-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
inline BOOL bSrcBeforeDst(
RECTL* prclDst,
RECTL* prclSrc,
LONG dx,
LONG dy)
{
return((prclDst->left < dx + prclSrc->right) &&
(prclDst->right > dx + prclSrc->left) &&
(prclDst->top < dy + prclSrc->bottom) &&
(prclDst->bottom > dy + prclSrc->top));
}
/******************************Public*Routine******************************\
* VOID vSortBltOrder
*
* This function sorts the list of surfaces for the correct ordering on
* screen-to-screen blts that span boards.
*
* When this routine is done, 'pvdev->pdsBlt' will point to the first
* surface that should be processed, and each surface's 'pdsBltNext'
* field will point to the next one in order.
*
* History:
* 25-Apr-1996 -by- Tom Zakrajsek [tomzak]
* Wrote it.
*
\**************************************************************************/
VOID vSortBltOrder(
VDEV* pvdev,
LONG dx,
LONG dy)
{
DISPSURF* pdsBltHeadOld = pvdev->pdsBlt;
DISPSURF* pdsBltHeadNew = pdsBltHeadOld;
pdsBltHeadOld = pdsBltHeadOld->pdsBltNext;
pdsBltHeadNew->pdsBltNext = NULL;
while (pdsBltHeadOld)
{
DISPSURF * pdsBltInsert = pdsBltHeadOld;
DISPSURF * pdsBltPrev = pdsBltHeadNew;
DISPSURF * pdsBltCur = pdsBltHeadNew;
pdsBltInsert = pdsBltHeadOld;
pdsBltHeadOld = pdsBltHeadOld->pdsBltNext;
while((pdsBltCur) &&
(!bSrcBeforeDst(&pdsBltInsert->rcl, // Dst
&pdsBltCur->rcl, // Src
dx,
dy)))
{
pdsBltPrev = pdsBltCur;
pdsBltCur = pdsBltCur->pdsBltNext;
}
if (pdsBltCur == pdsBltHeadNew)
{
pdsBltHeadNew = pdsBltInsert;
pdsBltInsert->pdsBltNext = pdsBltCur;
}
else
{
pdsBltPrev->pdsBltNext = pdsBltInsert;
pdsBltInsert->pdsBltNext = pdsBltCur;
}
}
pvdev->pdsBlt = pdsBltHeadNew;
}
/******************************Public*Routine******************************\
* BOOL bBitBltScreenToScreen
*
* Handles screen-to-screen blts that may possibly span multiple displays.
*
\**************************************************************************/
BOOL bBitBltScreenToScreen(
SURFOBJ *pso,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
POINTL *pptlMask,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
ROP4 rop4)
{
VDEV* pvdev;
LONG dx;
LONG dy;
DISPSURF* pdsDst;
DISPSURF* pdsSrc;
SURFOBJ* psoDst;
SURFOBJ* psoSrc;
POINTL* pOffDst;
POINTL* pOffSrc;
RECTL rclDst;
POINTL ptlSrc;
#if _MSC_VER < 1300
DHSURF dhsurfSave;
DHPDEV dhpdevSave;
#endif
SIZEL sizl;
HSURF hsurfTmp;
SURFOBJ* psoTmp;
RECTL rclDstTmp;
BOOL bRet;
RECTL rclSaveBounds;
bRet = TRUE;
pvdev = (VDEV*) pso->dhpdev;
dx = prclDst->left - pptlSrc->x;
dy = prclDst->top - pptlSrc->y;
vSortBltOrder(pvdev, dx, dy);
XLATEOBJ *pxloSave = pxlo;
MULTIBRUSH MBRUSH(pbo, pvdev->cSurfaces, pvdev, pvdev->pso, ROP4_NEEDS_PATTERN(rop4));
if (!MBRUSH.Valid())
{
return FALSE;
}
if (pco != NULL)
{
rclSaveBounds = pco->rclBounds;
}
BOOL bWndBltNotify = (pso != NULL) && (pso->fjBitmap & BMF_WINDOW_BLT);
for (pdsDst = pvdev->pdsBlt; pdsDst != NULL; pdsDst = pdsDst->pdsBltNext)
{
for (pdsSrc = pdsDst; pdsSrc != NULL; pdsSrc = pdsSrc->pdsBltNext)
{
rclDst.left = dx + pdsSrc->rcl.left;
rclDst.right = dx + pdsSrc->rcl.right;
rclDst.top = dy + pdsSrc->rcl.top;
rclDst.bottom = dy + pdsSrc->rcl.bottom;
if (bIntersect(prclDst, &rclDst, &rclDst) &&
bIntersect(&rclDst, &pdsDst->rcl, &rclDst))
{
ptlSrc.x = rclDst.left - dx;
ptlSrc.y = rclDst.top - dy;
psoSrc = pdsSrc->pso;
psoDst = pdsDst->pso;
pOffSrc = &pdsSrc->Off;
pOffDst = &pdsDst->Off;
#if _MSC_VER < 1300
dhpdevSave = NULL;
#endif
hsurfTmp = NULL;
if (psoSrc == psoDst)
{
// This simply amounts to a screen-to-screen blt on
// the same surface.
}
else if ((!pdsSrc->bIsReadable) ||
(bIntersect(&pdsSrc->rcl, &pdsDst->rcl)))
{
// If the source surface isn't readable, or if the two
// surfaces overlap (such as can happen when two display
// cards are echoing the same output), don't use the
// source as a destination for updating the display. We
// need to do this otherwise when we do a screen-to-
// screen blt with a mirroring driver in the background,
// we'll think that the mirrored surface has to be blt
// to the screen -- but the read of the surface will
// fail and we'll end up blting blackness.
psoSrc = NULL;
}
else
{
// This blt has to happen across boards, and the source
// bits aren't directly readable. We'll have to create
// a temporary buffer and make a copy:
sizl.cx = rclDst.right - rclDst.left;
sizl.cy = rclDst.bottom - rclDst.top;
PDEVOBJ pdoSrc(pdsSrc->hdev);
hsurfTmp = (HSURF) EngCreateBitmap(sizl,
0,
pdoSrc.iDitherFormat(),
0,
NULL);
psoTmp = EngLockSurface(hsurfTmp);
if (psoTmp)
{
rclDstTmp.left = 0;
rclDstTmp.top = 0;
rclDstTmp.right = sizl.cx;
rclDstTmp.bottom = sizl.cy;
bRet &= OffCopyBits(*PPFNGET(pdoSrc,
CopyBits,
pdoSrc.pSurface()->flags()),
&gptlZero,
psoTmp,
&pdsSrc->Off,
psoSrc,
NULL,
NULL,
&rclDstTmp,
&ptlSrc);
}
psoSrc = psoTmp;
pOffSrc = &gptlZero;
ptlSrc.x = 0;
ptlSrc.y = 0;
}
// Do the blt:
if (psoSrc)
{
BOOL bError = FALSE;
PDEVOBJ pdoSrc(pdsSrc->hdev);
PDEVOBJ pdoDst(pdsDst->hdev);
EXLATEOBJ xloDevice;
if ((psoDst != psoSrc) &&
((pdsDst->iCompatibleColorFormat != 0) ||
(pdsSrc->iCompatibleColorFormat != 0)))
{
XLATE *pxloM = (XLATE *) pxlo;
PSURFACE pSurfSrc = pdsSrc->po.pSurface();
PSURFACE pSurfDst = pdsDst->po.pSurface();
PPALETTE ppalSrcDC = ppalDefault;
PPALETTE ppalDstDC = ppalDefault;
// If destination surface is not compatible as primary
// and pal-managed device, then use halftone palette
// (source is higher then destination).
if ((pdsDst->iCompatibleColorFormat != 0) &&
pdoDst.bIsPalManaged())
{
ppalDstDC = REALIZE_HALFTONE_PALETTE(pdoDst.hdev());
}
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
pSurfSrc->ppal(), // Source palette
pSurfDst->ppal(), // Destination palette
ppalSrcDC, // Source DC palette
ppalDstDC, // Destination DC palette
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L),
(pdsSrc->po.bIsPalManaged() ? XLATE_USE_SURFACE_PAL : 0)))
{
pxlo = xloDevice.pxlo();
}
else
{
bError = TRUE;
}
}
if (bError == FALSE)
{
// If we have a clipobj,
// We must ensure that pco->rclBounds is never bigger than
// prclDst on the CopyBits call.
if ((pco == NULL) ||
bIntersect(&rclSaveBounds, &rclDst, &pco->rclBounds))
{
if (rop4 == 0xcccc)
{
// If window blt notification is needed (i.e.,
// destination meta-surface has BMF_WINDOW_BLT bit
// set), setthe notification bit in the destination
// surfobj.
USHORT fjBitmapSave = psoDst->fjBitmap;
if (bWndBltNotify)
psoDst->fjBitmap |= BMF_WINDOW_BLT;
bRet &= OffCopyBits(PPFNGET(pdoDst,
CopyBits,
pdoDst.pSurface()->flags()),
pOffDst,
psoDst,
pOffSrc,
psoSrc,
pco,
pxlo,
&rclDst,
&ptlSrc);
// Restore the surfobj flagss.
psoDst->fjBitmap = fjBitmapSave;
}
else
{
MBRUSH.LoadElement(pdsDst, SURFOBJ_TO_SURFACE_NOT_NULL(psoDst));
bRet &= OffBitBlt(PPFNGET(pdoDst,
BitBlt,
pdoDst.pSurface()->flags()),
pOffDst,
psoDst,
pOffSrc,
psoSrc,
psoMask,
pco,
pxlo,
&rclDst,
&ptlSrc,
pptlMask,
pbo,
pptlBrush,
rop4);
MBRUSH.StoreElement(pdsDst->iDispSurf);
}
}
}
else
{
bRet = FALSE;
}
// Restore XLATEOBJ.
pxlo = pxloSave;
}
// Now undo everything:
#if _MSC_VER < 1300
if (dhpdevSave)
{
psoSrc->dhsurf = dhsurfSave;
psoSrc->dhpdev = dhpdevSave;
}
else
#endif
if (hsurfTmp)
{
EngUnlockSurface(psoTmp);
EngDeleteSurface(hsurfTmp);
}
}
}
}
if (pco != NULL)
{
pco->rclBounds = rclSaveBounds;
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL bBitBltFromScreen
*
* Handles screen-to-bitmap blts that may possibly span multiple displays.
*
\**************************************************************************/
BOOL bBitBltFromScreen(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
POINTL *pptlMask,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
ROP4 rop4)
{
GDIFunctionID(bBitBltFromScreen);
VDEV* pvdev;
DHPDEV dhpdevDst;
RECTL rclDraw;
MSURF msurf;
POINTL ptlSrc;
RECTL rclDst;
SURFOBJ* psoDstTmp;
LONG dx;
LONG dy;
XLATEOBJ *pxloSave = pxlo;
BOOL bRet = TRUE;
pvdev = (VDEV*) psoSrc->dhpdev;
MULTISURF mDst(psoDst,prclDst);
dx = prclDst->left - pptlSrc->x;
dy = prclDst->top - pptlSrc->y;
// Trim the destination rectangle to what's specified in the CLIPOBJ's
// 'rclBounds':
rclDraw = *prclDst;
if ((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL))
{
if (!bIntersect(&pco->rclBounds, &rclDraw, &rclDraw))
return(TRUE);
}
// Convert 'rclDraw' from destination coordinates to source coordinates:
rclDraw.left -= dx;
rclDraw.right -= dx;
rclDraw.top -= dy;
rclDraw.bottom -= dy;
MULTIBRUSH MBRUSH(pbo, pvdev->cSurfaces, pvdev, pvdev->pso, ROP4_NEEDS_PATTERN(rop4));
if (!MBRUSH.Valid())
{
return FALSE;
}
// Source is screen.
if (msurf.bFindSurface(psoSrc, NULL, &rclDraw))
{
do {
PDEVOBJ poSrc(msurf.pso->hdev);
// for DIB we blit once from each screen. For device managed bitmaps, we blit
// once to the master compatible bitmap and once to the device managed bitmap
// for each screen.
if (poSrc.flGraphicsCaps() & GCAPS_LAYERED)
{
if (mDst.pmdsurf == NULL || mDst.pmdsurf->apso[msurf.pds->iDispSurf] == NULL)
continue;
psoDstTmp = mDst.pmdsurf->apso[msurf.pds->iDispSurf];
}
else
psoDstTmp = mDst.pso;
do {
BOOL bError = FALSE;
EXLATEOBJ xloDevice;
// if the source surface is not compatible to primary surface,
// create XLATEOBJ for source surface to target. otherwise
// we can just use given XLATEOBJ.
if (msurf.pds->iCompatibleColorFormat != 0)
{
XLATE *pxloM = (XLATE *) pxlo;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE_NOT_NULL(psoDstTmp);
PPALETTE ppalDst = pSurfDst->ppal();
if (!ppalDst)
{
// Destination surface does not have associated palette.
// (Destination surface is compatible bitmap)
if (pxloM && pxloM->ppalDst)
{
// if XLATEOBJ has destination palette, use it.
ppalDst = pxloM->ppalDst;
}
else
{
if ((pxloM == NULL) || pxloM->bIsIdentity())
{
PSURFACE pSurfTmp = SURFOBJ_TO_SURFACE_NOT_NULL(psoSrc);
// if translation is identity, we can use the palette for
// meta-source surface as destination. since it's trivial.
// WINBUG #396667 10-03-2001 jasonha A/V due to improper XLATE setup
if (psoDstTmp == psoDst)
{
ppalDst = pSurfTmp->ppal();
}
}
else
{
#if HIDEYUKN_DBG
DbgPrint("GDI DDML: bBitBltFromScreen(): ppalDst is NULL\n");
DbgBreakPoint();
#endif
bError = TRUE;
}
}
}
if (bError == FALSE)
{
// WINBUG #365408 4-10-2001 jasonha Need to investigate old comment in bBitBltFromScreen
//
// We need to investigate the following old comment:
// make sure that when the target surface is paletee managed we should
// foreground realization to copy bits from non-primary surface.
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
pSurfSrc->ppal(), // Source (device surface) palette
ppalDst, // Destination palette
ppalDefault, // Source DC palette
ppalDefault, // Destination DC palette
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L),
XLATE_USE_SURFACE_PAL))
{
pxlo = xloDevice.pxlo();
}
else
{
bError = TRUE;
}
}
}
if (bError == FALSE)
{
if (msurf.pco->iDComplexity == DC_TRIVIAL)
{
// Since bFindSurface/bNextSurface specified no clipping,
// the entire source surface is readable in one shot:
ptlSrc = *pptlSrc;
rclDst = *prclDst;
}
else
{
// Since the screen is the source, but the clip bounds
// apply to the destination, we have to convert our surface
// clipping information to destination coordinates:
ptlSrc.x = msurf.pco->rclBounds.left;
ptlSrc.y = msurf.pco->rclBounds.top;
rclDst.left = msurf.pco->rclBounds.left + dx;
rclDst.right = msurf.pco->rclBounds.right + dx;
rclDst.top = msurf.pco->rclBounds.top + dy;
rclDst.bottom = msurf.pco->rclBounds.bottom + dy;
}
if (rop4 == 0xcccc)
{
bRet &= OffCopyBits(
PPFNMGET(msurf, CopyBits),
&gptlZero,
psoDstTmp,
msurf.pOffset,
msurf.pso,
pco, // Note that this is the original 'pco'
pxlo,
&rclDst,
&ptlSrc);
}
else
{
MBRUSH.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
bRet &= OffBitBlt(
PPFNMGET(msurf, BitBlt),
&gptlZero,
psoDstTmp,
msurf.pOffset,
msurf.pso,
psoMask,
pco, // Note that this is the original 'pco'
pxlo,
&rclDst,
&ptlSrc,
pptlMask,
pbo,
pptlBrush,
rop4);
MBRUSH.StoreElement(msurf.pds->iDispSurf);
}
}
else
{
bRet = FALSE;
}
// Restore XLATEOBJ.
pxlo = pxloSave;
#if 1
ASSERTGDI(!((mDst.pmdsurf != NULL) &&
(psoDstTmp == mDst.pso) &&
(mDst.pmdsurf->apso[msurf.pds->iDispSurf] != NULL)),
"Non-Layered device is part of Meta DEVBITMAP.\n");
psoDstTmp = NULL;
#else
if ((mDst.pmdsurf != NULL) && (psoDstTmp == mDst.pso))
psoDstTmp = mDst.pmdsurf->apso[msurf.pds->iDispSurf];
else
psoDstTmp = NULL;
#endif
} while (psoDstTmp != NULL);
} while (msurf.bNextSurface());
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulBitBlt
*
\**************************************************************************/
BOOL MulBitBlt(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
SURFOBJ *psoMask,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc,
POINTL *pptlMask,
BRUSHOBJ *pbo,
POINTL *pptlBrush,
ROP4 rop4)
{
GDIFunctionID(MulBitBlt);
BOOL bFromScreen;
BOOL bToScreen;
VDEV* pvdev;
USHORT iDstType;
BOOL bMultiDst;
MDSURF* pmdsurfSrc;
DHPDEV dhpdevSrc;
RECTL rclDst;
MSURF msurf;
BOOL bRet;
BOOL bError;
XLATEOBJ *pxloSave = pxlo;
bFromScreen = ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE));
bToScreen = (psoDst->iType == STYPE_DEVICE);
// We copy the prclDst rectangle here because sometimes GDI will
// simply point prclDst to the same rectangle in pco->rclBounds,
// and we'll be mucking with pco->rclBounds...
rclDst = *prclDst;
if (bToScreen && bFromScreen)
{
return(bBitBltScreenToScreen(psoDst, psoMask, pco, pxlo,
&rclDst, pptlSrc, pptlMask, pbo,
pptlBrush, rop4));
}
else if (bFromScreen)
{
return(bBitBltFromScreen(psoDst, psoSrc, psoMask, pco, pxlo,
&rclDst, pptlSrc, pptlMask, pbo,
pptlBrush, rop4));
}
else // if (bToScreen)
{
bRet = TRUE;
pvdev = (VDEV*) psoDst->dhpdev;
// WINBUG #380128 05-04-2001 jasonha Initialize MSURF before MULTISURF
// WINBUG #402896 05-24-2001 jasonha Initialize MULTIBURSH before MULTISURF
// MULTIBRUSH and MSURF must be intialized before the destination
// SURFACE might be modified. The destination SURFACE may be changed
// when the source and destination are the same.
iDstType = psoDst->iType;
bMultiDst = (iDstType != STYPE_BITMAP) && msurf.bFindSurface(psoDst, pco, prclDst);
// MBRUSH is only needed for the bMultiDst case, therefore pass
// a NULL pbo, to reduce unnecessary setup.
MULTIBRUSH MBRUSH(((bMultiDst) ? pbo : NULL),
((bMultiDst) ? pvdev->cSurfaces : 0),
((bMultiDst) ? pvdev: NULL),
((bMultiDst) ? pvdev->pso : NULL),
((bMultiDst) ? ROP4_NEEDS_PATTERN(rop4) : FALSE));
MULTISURF mSrc(psoSrc, pptlSrc, rclDst.right - rclDst.left, rclDst.bottom - rclDst.top);
if (iDstType != STYPE_DEVICE)
{
// For STYPE_BITMAP, we only blit to the DIB.
// For STYPE_DEVBITMAP, we then blit to each device bitmap.
MULTISURF mDst(psoDst,prclDst);
bRet = EngBitBlt(mDst.pso, mSrc.pso, psoMask, pco, pxlo, mDst.prcl,
mSrc.pptl(), pptlMask, pbo, pptlBrush, rop4);
}
if (bMultiDst)
{
if (!MBRUSH.Valid())
{
msurf.vRestore();
return FALSE;
}
do {
bError = !mSrc.bLoadSource(msurf.pds);
EXLATEOBJ xloDevice;
// if the target surface is not compatible to primary surface,
// create XLATEOBJ for source surface to target. otherwise
// we can just use given XLATEOBJ.
if ((bError == FALSE) &&
(mSrc.pso != NULL) &&
(msurf.pds->iCompatibleColorFormat != 0))
{
XLATE *pxloM = (XLATE *) pxlo;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE_NOT_NULL(mSrc.pso);
PSURFACE pSurfDst = SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso);
PPALETTE ppalSrc = pSurfSrc->ppal();
PPALETTE ppalDestDC = ppalDefault;
PDEVOBJ pdoDst(msurf.pds->hdev);
if (pdoDst.bIsPalManaged())
{
// Use halftone palette for pal-managed device.
ppalDestDC = REALIZE_HALFTONE_PALETTE(pdoDst.hdev());
}
if (!ppalSrc)
{
// Source surface does not have associated palette.
// (Source surface is compatible bitmap)
if (pxloM && pxloM->ppalSrc)
{
// if XLATEOBJ has source palette, use it.
ppalSrc = pxloM->ppalSrc;
}
else
{
PSURFACE pSurfTmp = SURFOBJ_TO_SURFACE_NOT_NULL(psoDst);
if ((pxloM == NULL) || pxloM->bIsIdentity())
{
// if translation is identity, we can use the palette for
// meta-destination surface as source. since it's trivial.
// WINBUG #396667 10-03-2001 jasonha A/V due to improper XLATE setup
if (mSrc.pso == psoSrc)
{
ppalSrc = pSurfTmp->ppal();
}
}
else if (pxloM->ppalDstDC)
{
// We are bitblting from compatible bitmap to a surface in
// meta-surface. but we are not in foreground.
ppalDestDC = pxloM->ppalDstDC;
// WINBUG #274637 02-12-2001 jasonha A/V due to improper XLATE setup
if (pSurfSrc->iFormat() == pSurfTmp->iFormat())
{
// We are bitblting from a compatible bitmap that is
// not palettized but is a the same format as the
// meta-surface, so we use the destination palette.
ppalSrc = pSurfTmp->ppal();
}
}
else
{
#if HIDEYUKN_DBG
DbgPrint("GDI DDML: MulBitBlt(): ppalDst is NULL\n");
DbgBreakPoint();
#endif
bError = TRUE;
}
}
}
if (bError == FALSE)
{
XEPALOBJ palSurfSrc(ppalSrc);
ULONG flFlags = 0;
if (palSurfSrc.bValid() && palSurfSrc.bIsPalManaged())
{
// Source is palette managed surface.
if (ppalDestDC == ppalDefault)
{
// We don't know DC palette here, but we know we are in foregroud,
// (since translation is trivial)
// so, we just map from source surface palette to destination
// surface palette directly (destination is at least higher color
// depth than source).
flFlags = XLATE_USE_SURFACE_PAL;
}
else
{
// We may not be in foreground. but map from foreground translation
// in source, so that we will not loose original color on secondary
// devices which can produce higher color depth then source.
flFlags = XLATE_USE_FOREGROUND;
}
}
if (xloDevice.bInitXlateObj(
(pxloM ? pxloM->hcmXform : NULL),
(pxloM ? pxloM->lIcmMode : DC_ICM_OFF),
palSurfSrc, // Source palette
pSurfDst->ppal(), // Destination palette
ppalDefault, // Source DC palette
ppalDestDC, // Destination DC palette
(pxloM ? pxloM->iForeDst : 0x0L),
(pxloM ? pxloM->iBackDst : 0x0L),
(pxloM ? pxloM->iBackSrc : 0x0L),
flFlags))
{
pxlo = xloDevice.pxlo();
}
else
{
bError = TRUE;
}
}
}
if (bError == FALSE)
{
if (0) // (bHalftone)
{
MBRUSH.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
bRet &= OffStretchBltROP(EngStretchBltROP,
msurf.pOffset,
msurf.pso,
&gptlZero,
mSrc.pso,
psoMask,
msurf.pco,
pxlo,
NULL,
&gptlZero,
&rclDst,
mSrc.prcl,
pptlMask,
HALFTONE,
pbo,
rop4);
MBRUSH.StoreElement(msurf.pds->iDispSurf);
}
else if (rop4 == 0xcccc)
{
bRet &= OffCopyBits(PPFNMGET(msurf, CopyBits),
msurf.pOffset,
msurf.pso,
&gptlZero,
mSrc.pso,
msurf.pco,
pxlo,
&rclDst,
mSrc.pptl());
}
else
{
MBRUSH.LoadElement(msurf.pds, SURFOBJ_TO_SURFACE_NOT_NULL(msurf.pso));
bRet &= OffBitBlt(PPFNMGET(msurf, BitBlt),
msurf.pOffset,
msurf.pso,
&gptlZero,
mSrc.pso,
psoMask,
msurf.pco,
pxlo,
&rclDst,
mSrc.pptl(),
pptlMask,
pbo,
pptlBrush,
rop4);
MBRUSH.StoreElement(msurf.pds->iDispSurf);
}
}
else
{
bRet = FALSE;
}
// Restore XLATEOBJ.
pxlo = pxloSave;
} while (msurf.bNextSurface());
}
}
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulCopyBits
*
\**************************************************************************/
BOOL MulCopyBits(
SURFOBJ *psoDst,
SURFOBJ *psoSrc,
CLIPOBJ *pco,
XLATEOBJ *pxlo,
RECTL *prclDst,
POINTL *pptlSrc)
{
return(MulBitBlt(psoDst, psoSrc, NULL, pco, pxlo, prclDst,
pptlSrc, NULL, NULL, NULL, 0xcccc));
}
/******************************Public*Routine******************************\
* BOOL MulUpdateColors
*
* History:
* 18-Aug-1998 -by- Hideyuki Nagase [hideyukn]
* Wrote it.
*
\**************************************************************************/
BOOL MulUpdateColors(
SURFOBJ *pso,
CLIPOBJ *pco,
XLATEOBJ *pxlo)
{
VDEV* pvdev;
DISPSURF* pdsDst;
SURFOBJ* psoDst;
POINTL* pOffDst;
RECTL rclDst;
POINTL ptlSrc;
RECTL rclBounds;
BOOL bRet;
bRet = TRUE;
pvdev = (VDEV*) pso->dhpdev;
ASSERTGDI(pco,"MulUpdateColors(): pco is null\n");
//
// Save bounds rectangle to updates.
//
rclBounds = pco->rclBounds;
//
// Walk through all devices.
//
for (pdsDst = pvdev->pds; pdsDst != NULL; pdsDst = pdsDst->pdsNext)
{
PDEVOBJ pdo(pdsDst->hdev);
//
// Check the device is palette managed or not.
//
// + If this is not palette managed device, we don't need to
// do anything.
//
// + Palette is shared with all palette devices, so we can
// use exactly same XLATEOBJ for all palette devices.
//
if (pdo.bIsPalManaged())
{
//
// Clip the rectangle to monitor.
//
if (bIntersect(&rclBounds, &pdsDst->rcl, &rclDst))
{
//
// We must ensure that pco->rclBounds is never bigger than
// prclDst on the CopyBits call.
//
pco->rclBounds = rclDst;
//
// Source points is same as destination upper-left.
//
ptlSrc.x = rclDst.left;
ptlSrc.y = rclDst.top;
psoDst = pdsDst->pso;
pOffDst = &pdsDst->Off;
//
// Update each pixel with correct color (by XLATEOBJ).
//
bRet &= OffCopyBits(PPFNGET(pdo,
CopyBits,
pdo.pSurface()->flags()),
pOffDst, psoDst,
pOffDst, psoDst,
pco, pxlo,
&rclDst, &ptlSrc);
}
}
}
//
// Restore original.
//
pco->rclBounds = rclBounds;
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL MulCopyDeviceToDIB
*
* Copies the specified rectangle of a multimon device surface to a DIB
* updating the rectangle to be relativeto the DIB's origin (0,0)
*
* The surface is not actually created if the rectangle is
* out of bounds, so the caller has to check if the value
* of pDibSurface.ps was modified at all.
*
* History:
* 16-Dec-1998 -by- Andre Matos [amatos]
* Wrote it.
*
\**************************************************************************/
BOOL MulCopyDeviceToDIB(
SURFOBJ *pso,
SURFMEM *pDibSurf,
RECTL *prclSrc)
{
DEVBITMAPINFO dbmi;
PSURFACE pSurfSrc = SURFOBJ_TO_SURFACE(pso);
PDEVOBJ pdoSrc(pSurfSrc->hdev());
RECTL rclSrcClip = *prclSrc;
if(rclSrcClip.left < pdoSrc.pptlOrigin()->x)
{
rclSrcClip.left = pdoSrc.pptlOrigin()->x;
}
if(rclSrcClip.right >
(pdoSrc.pptlOrigin()->x + pSurfSrc->sizl().cx))
{
rclSrcClip.right =
pdoSrc.pptlOrigin()->x + pSurfSrc->sizl().cx;
}
if(rclSrcClip.top < pdoSrc.pptlOrigin()->y)
{
rclSrcClip.top = pdoSrc.pptlOrigin()->y;
}
if(rclSrcClip.bottom >
(pdoSrc.pptlOrigin()->y + pSurfSrc->sizl().cy))
{
rclSrcClip.bottom =
pdoSrc.pptlOrigin()->y + pSurfSrc->sizl().cy;
}
// If the source rectangle was outside of the source
// surface, we can return.
if((rclSrcClip.top >= rclSrcClip.bottom) ||
(rclSrcClip.left >= rclSrcClip.right ))
{
return TRUE;
}
RECTL rclDst = {0, 0, rclSrcClip.right - rclSrcClip.left,
rclSrcClip.bottom - rclSrcClip.top};
POINTL srcOrigin = { rclSrcClip.left, rclSrcClip.top };
PPALETTE ppalSrc = pSurfSrc->ppal();
dbmi.cxBitmap = rclDst.right;
dbmi.cyBitmap = rclDst.bottom;
dbmi.hpal = ppalSrc ? ((HPALETTE) ppalSrc->hGet()) : 0;
dbmi.iFormat = pSurfSrc->iFormat();
dbmi.fl = pSurfSrc->bUMPD() ? UMPD_SURFACE : 0;
pDibSurf->bCreateDIB(&dbmi, (VOID *) NULL);
if (!pDibSurf->bValid())
return(FALSE);
if (!MulBitBlt(pDibSurf->pSurfobj(), pso, NULL, (CLIPOBJ *) NULL,
&xloIdent, &rclDst, &srcOrigin, NULL, NULL, NULL, 0xcccc))
return FALSE;
prclSrc->left -= rclSrcClip.left;
prclSrc->right -= rclSrcClip.left;
prclSrc->top -= rclSrcClip.top;
prclSrc->bottom -= rclSrcClip.top;
return TRUE;
}
/******************************Public*Structure****************************\
* DRVFN gadrvfnMulti[]
*
* Build the driver function table gadrvfnMulti with function index/address
* pairs. This table tells GDI which DDI calls we support, and their
* location (GDI does an indirect call through this table to call us).
*
\**************************************************************************/
DRVFN gadrvfnMulti[] = {
// Effectively required by all drivers:
{ INDEX_DrvEnablePDEV , (PFN) MulEnablePDEV },
{ INDEX_DrvCompletePDEV , (PFN) MulCompletePDEV },
{ INDEX_DrvDisablePDEV , (PFN) MulDisablePDEV },
{ INDEX_DrvEnableSurface , (PFN) MulEnableSurface },
{ INDEX_DrvDisableSurface , (PFN) MulDisableSurface },
{ INDEX_DrvSetPalette , (PFN) MulSetPalette },
{ INDEX_DrvRealizeBrush , (PFN) MulRealizeBrush },
//
// The DDML is special in that it does not manage any physical device.
// GDI and USER should handle all calls involing modes, and those calls
// should never get to the DDML.
//
// { INDEX_DrvAssertMode , (PFN) MulAssertMode },
// { INDEX_DrvGetModes , (PFN) MulGetModes },
// Required for device-managed surfaces:
{ INDEX_DrvTextOut , (PFN) MulTextOut },
{ INDEX_DrvStrokePath , (PFN) MulStrokePath },
{ INDEX_DrvCopyBits , (PFN) MulCopyBits },
// Optional, must be supported by "Eng" backup calls:
{ INDEX_DrvBitBlt , (PFN) MulBitBlt },
{ INDEX_DrvLineTo , (PFN) MulLineTo },
{ INDEX_DrvFillPath , (PFN) MulFillPath },
{ INDEX_DrvStrokeAndFillPath , (PFN) MulStrokeAndFillPath },
{ INDEX_DrvStretchBlt , (PFN) MulStretchBlt },
{ INDEX_DrvAlphaBlend , (PFN) MulAlphaBlend },
{ INDEX_DrvTransparentBlt , (PFN) MulTransparentBlt },
{ INDEX_DrvGradientFill , (PFN) MulGradientFill },
{ INDEX_DrvDrawStream , (PFN) MulDrawStream },
// For handling device bitmaps with layered drivers:
{ INDEX_DrvCreateDeviceBitmap , (PFN) MulCreateDeviceBitmap },
{ INDEX_DrvDeleteDeviceBitmap , (PFN) MulDeleteDeviceBitmap },
// These calls only go to drivers that specifically need to get them.
// DrvDestroyFont is only called for the specific drivers that hooked
// it. I checked it out, and the engine calls DrvDestroyFont regardless
// of whether or not pvConsumer is NULL. Therefore, I do the same for
// each of the drivers.
{ INDEX_DrvDestroyFont , (PFN) MulDestroyFont },
{ INDEX_DrvEscape , (PFN) MulEscape },
{ INDEX_DrvSaveScreenBits , (PFN) MulSaveScreenBits },
#ifdef OPENGL_MM
// ICD calls directly dispatch to real driver in API level, so it bypass DDML.
#else
{ INDEX_DrvSetPixelFormat , (PFN) MulSetPixelFormat },
{ INDEX_DrvDescribePixelFormat , (PFN) MulDescribePixelFormat },
{ INDEX_DrvSwapBuffers , (PFN) MulSwapBuffers },
#endif // OPENGL_MM
// Image Color Management - DeviceGammaRamp control:
{ INDEX_DrvIcmSetDeviceGammaRamp , (PFN) MulIcmSetDeviceGammaRamp},
};
ULONG gcdrvfnMulti = sizeof(gadrvfnMulti) / sizeof(DRVFN);
#ifdef OPENGL_MM
/******************************Public*Routine******************************\
* HDEV hdevFindDeviceHDEV
*
* OpenGL calls should only go to one driver and not the meta device.
* Try to find the appropriate hdev and return it.
*
* History:
* 28-Jan-1998 -by- Robert Tray [v-rotray]
* First pass.
*
\**************************************************************************/
HDEV hdevFindDeviceHdev(
HDEV hdevMeta,
RECTL rect,
PEWNDOBJ pwo) // OPTIONAL
{
//
// *PixelFormat, SwapBuffers, & OGL Escape calls should
// only go to one device. Which one?
// If there is a valid WNDOBJ then it will tell us
// which surface is the right one.
// If the extents of the window are completely contained
// on one monitor then return the hdev of that device.
// If the window straddles monitors then .... how about
// we return 0 and hopefully in that case the app will
// fall back to software rendering. By the time the app
// is serious about rendering he has a WNDOBJ. So hopefully
// we will only hit these ambiguous situations while the
// app is doing a DescribePixelFormat.
//
PDEVOBJ pdo(hdevMeta);
ASSERTGDI(pdo.bMetaDriver(),"hdevFindDeviceHDEV(): hdevMeta is not meta-PDEV\n");
PVDEV pvdev = (VDEV*) pdo.dhpdev();
PDISPSURF pds;
HDEV hdevMatch = NULL;
//
// If WNDOBJ is given and the HDEV for the WNDOBJ
// is one of child of this meta-PDEV. use it.
//
if (pwo && pwo->bValid())
{
hdevMatch = pwo->pto->pSurface->hdev();
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
if (hdevMatch == pds->hdev)
{
// found the match
return (hdevMatch);
}
}
}
ULONG intersectMon = 0;
for (pds = pvdev->pds; pds != NULL; pds = pds->pdsNext)
{
if (bContains(&pds->rcl,&rect))
{
// The window is contained on this device
return (pds->hdev);
}
if (bIntersect(&pds->rcl,&rect))
{
// The window is intersected with this device.
PDEVOBJ pdoDevice(pds->hdev);
// If this device has GCAPS2_ICD_MULTIMON flag, they
// wants us to call them with any OpenGL window intersect
// with thier device.
if (pdoDevice.flGraphicsCaps2() & GCAPS2_ICD_MULTIMON)
{
return (pds->hdev);
}
intersectMon++;
hdevMatch = pds->hdev;
}
}
//
// If the window is not contained on one monitor but
// it only intersects one then that might mean that it's
// hanging off the outside edge of a monitor.
//
if (intersectMon == 1)
{
return hdevMatch;
}
//
// I suppose you could possibly return the hdev for the
// primary monitor in some of these ambiguous cases but
// until I think of them I'll just return NULL
//
return NULL;
}
#endif // OPENGL_MM