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