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