/******************************Module*Header*******************************\ * Module Name: surfddi.cxx * * Surface DDI callback routines * * Created: 23-Aug-1990 * Author: Greg Veres [w-gregv] * * Copyright (c) 1990-1999 Microsoft Corporation \**************************************************************************/ #include "precomp.hxx" /******************************Public*Routine******************************\ * EngMarkBandingSurface * * DDI entry point to mark a surface as a banding surface meaning we should * capture all output to it in a metafile. * * History: * 10-Mar-1993 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ BOOL EngMarkBandingSurface(HSURF hsurf) { SURFREF so; so.vAltCheckLockIgnoreStockBit(hsurf); ASSERTGDI(so.bValid(), "ERROR EngMarkBandingSurfae invalid HSURF passed in\n"); so.ps->vSetBanding(); return(TRUE); } /******************************Public*Routine******************************\ * hbmCreateDriverSurface * * Common entry point for creating DDI surfaces. * * History: * 11-Feb-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ HBITMAP hbmCreateDriverSurface(ULONG iType, DHSURF dhsurf, SIZEL sizl, LONG lWidth, ULONG iFormat, FLONG fl, PVOID pvBits) { DEVBITMAPINFO dbmi; ULONG cjWidth = (ULONG) lWidth; dbmi.iFormat = iFormat & ~UMPD_FLAG; dbmi.cxBitmap = sizl.cx; dbmi.cyBitmap = sizl.cy; dbmi.hpal = (HPALETTE) 0; dbmi.fl = fl; // // convert from bytes to pels if given a buffer and cjWidth. If either // of these are set to 0 use what DIBMEMOBJ computes. // if ((pvBits) && (cjWidth)) { switch (dbmi.iFormat) { case BMF_1BPP: dbmi.cxBitmap = cjWidth * 8; break; case BMF_4BPP: dbmi.cxBitmap = cjWidth * 2; break; case BMF_8BPP: dbmi.cxBitmap = cjWidth; break; case BMF_16BPP: dbmi.cxBitmap = cjWidth / 2; break; case BMF_24BPP: dbmi.cxBitmap = cjWidth / 3; break; case BMF_32BPP: dbmi.cxBitmap = cjWidth / 4; break; } } SURFMEM SurfDimo; SurfDimo.bCreateDIB(&dbmi, pvBits); if (!SurfDimo.bValid()) { // // Constructor logs error code. // return((HBITMAP) 0); } // // We have to mark the surface with a special flag indicating it was // created via EngCreateDeviceBitmap, instead of just looking for // STYPE_DEVBITMAP, because EngModifySurface can change the type to // STYPE_BITMAP yet we still want to cleanup the surface by calling // DrvDeleteDeviceBitmap. // if (iType == STYPE_DEVBITMAP) { SurfDimo.ps->vSetEngCreateDeviceBitmap(); } if (iType != STYPE_BITMAP) { SurfDimo.ps->lDelta(0); SurfDimo.ps->pvScan0(NULL); SurfDimo.ps->pvBits(NULL); } SurfDimo.ps->vSetDriverCreated(); SurfDimo.ps->sizl(sizl); SurfDimo.ps->dhsurf(dhsurf); SurfDimo.ps->iType(iType); SurfDimo.vKeepIt(); // // charge the surface from umpd driver against the process // so we can clean it up afterwards // if (!(iFormat & UMPD_FLAG)) SurfDimo.vSetPID(OBJECT_OWNER_PUBLIC); else SurfDimo.ps->vSetUMPD(); return((HBITMAP) SurfDimo.ps->hsurf()); } /******************************Public*Routine******************************\ * EngCreateBitmap * * DDI entry point to create a engine bitmap surface. * * History: * 11-Feb-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ HBITMAP EngCreateBitmap(SIZEL sizl, LONG lWidth, ULONG iFormat, FLONG fl, PVOID pvBits) { return(hbmCreateDriverSurface(STYPE_BITMAP, NULL, sizl, lWidth, iFormat, fl, pvBits)); } /******************************Public*Routine******************************\ * EngCreateDeviceBitmap * * DDI entry point to create device managed bitmap. * * History: * 10-Mar-1993 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ HBITMAP EngCreateDeviceBitmap(DHSURF dhsurf, SIZEL sizl, ULONG iFormat) { return(hbmCreateDriverSurface(STYPE_DEVBITMAP, dhsurf, sizl, 0, iFormat, 0, (PVOID)UIntToPtr( 0xdeadbeef ))); } /******************************Public*Routine******************************\ * EngCreateDeviceSurface * * DDI entry point to create device managed bitmap. * * History: * 10-Mar-1993 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ HSURF EngCreateDeviceSurface(DHSURF dhsurf, SIZEL sizl, ULONG iFormat) { // // [NT 4.0 compatible] // // EngCreateDeviceSurface in NT4, does not fail with invalid iFormat // (especially 0, Adobe Acrobat 3.01 - PDFKD.DLL calls with 0 at least). // So we replace the wrong data with something valid, here. // switch (iFormat & ~UMPD_FLAG) { case BMF_1BPP: case BMF_4BPP: case BMF_8BPP: case BMF_16BPP: case BMF_24BPP: case BMF_32BPP: break; default: // // UMPD_FLAG should be preserved. // iFormat = (iFormat & UMPD_FLAG) | BMF_1BPP; } return((HSURF) hbmCreateDriverSurface(STYPE_DEVICE, dhsurf, sizl, 0, iFormat, 0, (PVOID)UIntToPtr( 0xdeadbeef ))); } /******************************Public*Routine******************************\ * EngDeleteSurface * * DDI entry point to delete a surface. * * History: * Thu 12-Mar-1992 -by- Patrick Haluptzok [patrickh] * change to bool return. * * 11-Feb-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ BOOL EngDeleteSurface(HSURF hsurf) { BOOL bReturn = TRUE; if (hsurf != 0) { bReturn = bDeleteSurface(hsurf); } ASSERTGDI(bReturn, "ERROR EngDeleteSurface failed"); return(bReturn); } /******************************Public*Routine******************************\ * EngLockSurface * * DDI entry point to lock down a surface handle. * * History: * Thu 27-Aug-1992 -by- Patrick Haluptzok [patrickh] * Remove SURFOBJ accelerator allocation. * * 11-Feb-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ SURFOBJ *EngLockSurface(HSURF hsurf) { SURFREF so; so.vAltCheckLockIgnoreStockBit(hsurf); if (so.bValid()) { so.vKeepIt(); return(so.pSurfobj()); } else { WARNING("EngLockSurface failed to lock handle\n"); return((SURFOBJ *) NULL); } } /******************************Public*Routine******************************\ * EngUnlockSurface * * DDI entry point to unlock a surface that has been locked * with EngLockSurface. * * History: * Thu 27-Aug-1992 -by- Patrick Haluptzok [patrickh] * Remove SURFOBJ accelerator allocation. * * 11-Feb-1991 -by- Patrick Haluptzok patrickh * Wrote it. \**************************************************************************/ VOID EngUnlockSurface(SURFOBJ *pso) { if (pso != (SURFOBJ *) NULL) { SURFACE *ps = SURFOBJ_TO_SURFACE_NOT_NULL(pso); if (ps == HmgReferenceCheckLock((HOBJ)pso->hsurf,SURF_TYPE,FALSE)) { SURFREF su(pso); su.vUnreference(); } } } #if DBG BOOL PanCopyBits(SURFOBJ*, SURFOBJ*, CLIPOBJ*, XLATEOBJ*, RECTL*, POINTL*); VOID vAssertValidHookFlags(PDEVOBJ *pdo, SURFREF *pso) { FLONG flHooks; flHooks = pso->ps->flags(); // // Check to make sure we haven't disabled h/w accelerations and are now // using the panning driver (unaccelerated driver). // if(PPFNDRV(*pdo, CopyBits)!=PanCopyBits) { // // Assert that the driver provides a routine entry point to match each // Hooked flag. // // PPFNGET returns the driver routine if the appropriate flag is set. // if the flag is set and the routine is NULL, we ASSERT. // // if the flag is not set, then PPFNGET returns the Eng routine, which // better not be NULL, so we ASSERT if it is. // ASSERTGDI( (PPFNGET(*pdo, BitBlt, flHooks)), "HOOK_BITBLT specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, StretchBlt, flHooks)), "HOOK_STRETCHBLT specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, PlgBlt, flHooks)), "HOOK_PLGBLT specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, TextOut, flHooks)), "HOOK_TEXTOUT specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, Paint, flHooks)), "HOOK_PAINT specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, StrokePath, flHooks)), "HOOK_STROKEPATH specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, FillPath, flHooks)), "HOOK_FILLPATH specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, StrokeAndFillPath, flHooks)), "HOOK_STROKEANDFILLPATH specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, LineTo, flHooks)), "HOOK_LINETO specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, CopyBits, flHooks)), "HOOK_COPYBITS specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, StretchBltROP, flHooks)), "HOOK_STRETCHBLTROP specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, TransparentBlt, flHooks)), "HOOK_TRANSPARENTBLT specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, AlphaBlend, flHooks)), "HOOK_ALPHABLEND specified, but entry is NULL"); ASSERTGDI( (PPFNGET(*pdo, GradientFill, flHooks)), "HOOK_GRADIENTFILL specified, but entry is NULL"); ASSERTGDI( ((flHooks & HOOK_SYNCHRONIZE) == 0 || pdo->ppfn(INDEX_DrvSynchronize) != NULL || pdo->ppfn(INDEX_DrvSynchronizeSurface != NULL)), "HOOK_SYNCHRONIZE specified, but appropriate driver function" " (DrvSynchronize or DrvSynchronizeSurface) not available"); } } #endif /******************************Public*Routine******************************\ * EngAssociateSurface * * * * DDI entry point for assigning a surface a palette, associating it with * * a device. * * * * History: * * Mon 27-Apr-1992 16:36:38 -by- Charles Whitmer [chuckwh] * * Changed HPDEV to HDEV. * * * * Thu 12-Mar-1992 -by- Patrick Haluptzok [patrickh] * * change to bool return * * * * Mon 01-Apr-1991 -by- Patrick Haluptzok [patrickh] * * add pdev, dhpdev init, palette stuff * * * * 13-Feb-1991 -by- Patrick Haluptzok patrickh * * Wrote it. * \**************************************************************************/ BOOL EngAssociateSurface(HSURF hsurf, HDEV hdev, FLONG flHooks) { // // Remove any obsolete HOOK_ flags, so that we can overload them for // internal GDI purposes. // flHooks &= ~(HOOK_SYNCHRONIZEACCESS | HOOK_MOVEPANNING); ASSERTGDI((flHooks & (~HOOK_FLAGS)) == 0, "ERROR driver set high flags"); // // This call needs to associate this surface with the the HDEV given. // We can't stick the palette in here because for palette managed devices // the compatible bitmaps have a NULL palette. If we ever try and init // the palettes here we need to be careful not to do it for compatible // bitmaps on palette managed devices. // PDEVOBJ po(hdev); if (!po.bValid()) { WARNING("EngAssociateSurface: invalid PDEV passed in\n"); return FALSE; } SURFREF so; so.vAltCheckLockIgnoreStockBit(hsurf); if (!so.bValid()) { WARNING("EngAssociateSurface: invalid SURF passed in\n"); return FALSE; } // // EA Recovery support: If we are hooking the driver entry points for // EA recovery, we need to store away the surface and associated // LDEV so that when the DrvDeleteDeviceBitmap comes down, we can hook // up the "real" driver entry point. // // NOTE: We only create this node if EA recovery is currently enabled, and // DrvCreateDeviceBitmap (which will do the cleanup of the node) is present. // if (WatchdogIsFunctionHooked(po.pldev(), INDEX_DrvCreateDeviceBitmap)) { if (so.ps->bEngCreateDeviceBitmap()) { if (dhsurfAssociationIsNodeInList(so.ps->dhsurf(), hsurf) == FALSE) { PDHSURF_ASSOCIATION_NODE Node = dhsurfAssociationCreateNode(); if (Node) { Node->dhsurf = so.ps->dhsurf(); Node->hsurf = hsurf; Node->pldev = po.pldev(); dhsurfAssociationInsertNode(Node); } else { WARNING("EngAssociateSurface: failed to create association node\n"); return(FALSE); } } } } so.ps->pwo((EWNDOBJ *)NULL); so.ps->hdev(hdev); so.ps->dhpdev(po.dhpdevNotDynamic()); // Since we're being called from // the driver, we are implicitly // holding a dynamic mode change // lock, and so don't need to // check it -- hence 'NotDynamic' so.ps->flags(so.ps->flags() | flHooks); #if DBG vAssertValidHookFlags(&po, &so); #endif return(TRUE); } /******************************Public*Routine******************************\ * EngModifySurface * * DDI entry point for changing surface internals such as the type, * bits pointers, and the hooked flags. * 27-Apr-1998 -by- J. Andrew Goossen patrickh * Wrote it. \**************************************************************************/ BOOL EngModifySurface( HSURF hsurf, HDEV hdev, FLONG flHooks, FLONG flSurface, DHSURF dhsurf, VOID* pvScan0, LONG lDelta, VOID* pvReserved) { BOOL bRet = TRUE; // Assume success; SURFREF so; PDHSURF_ASSOCIATION_NODE Node = NULL; PDEVOBJ po(hdev); if (!po.bValid()) { WARNING("EngModifySurface: invalid PDEV passed in"); return(FALSE); } so.vAltLockIgnoreStockBit(hsurf); if (!so.bValid()) { WARNING("EngModifySurface: invalid surface handle passed in"); return(FALSE); } if (pvReserved != NULL) { WARNING("EngModifySurface: pvReserved not NULL"); bRet = FALSE; } if (flSurface & ~(MS_NOTSYSTEMMEMORY | MS_SHAREDACCESS)) { WARNING("EngModifySurface: invalid flSurface flag"); return(FALSE); } // // Only surfaces that were created via EngCreateDeviceBitmap or // EngCreateDeviceSurface are allowed to be modified. We do this // primarily for two reasons: // // 1. This prevents the driver from modifying willy-nilly // SURFOBJs that it sees; // 2. If solves some problems with bDeleteSurface calling // DrvDeleteDeviceBitmap (it was impossible to allow // an STYPE_BITMAP surface to have DrvDeleteDeviceBitmap // called, and still handle the DrvEnableSurface case // where a driver created its primary surface using // EngCreateSurface and modified the 'dhsurf' field -- // in this case DrvDeleteDeviceBitmap should not be called! // // Note that as a side effect of how we check for STYPE_DEVICE, // primary surfaces should only ever be called with EngModifySurface // once. Bitmap surfaces, however, can intentionally be modified by // EngModifySurface any number times. // if (!(so.ps->bEngCreateDeviceBitmap()) && (so.ps->iType() != STYPE_DEVICE)) { WARNING("EngModifySurface: surface not driver created"); bRet = FALSE; } if ((so.ps->hdev() != NULL) && (so.ps->hdev() != hdev)) { WARNING("EngModifySurface: surface associated with different hdev"); bRet = FALSE; } // // Remove any obsolete HOOK_ flags, so that we can overload them for // internal GDI purposes. // flHooks &= ~(HOOK_SYNCHRONIZEACCESS | HOOK_MOVEPANNING); ASSERTGDI((flHooks & (~HOOK_FLAGS)) == 0, "ERROR driver set high flags"); // // WINBUG #254444 bhouse 12-14-2000 Allow drivers to change primary using EngModifySurface // TODO: Additional code review of this change // Allow drivers to change primary surface attributes so long as they // are not changing the hooking flags and the PDEV is disabled. // if (so.ps->bPDEVSurface() && ((po.pSpriteState()->flOriginalSurfFlags & HOOK_FLAGS) != flHooks || !po.bDisabled())) { WARNING("EngModifySurface: can't modify PDEV surface once created"); bRet = FALSE; } // // EA Recovery support: If we are hooking the driver entry points for // EA recovery, we need to store away the surface and associated // LDEV so that when the DrvDeleteDeviceBitmap comes down, we can hook // up the "real" driver entry point. // // // NOTE: We only create this node if EA recovery is currently enabled, and // DrvCreateDeviceBitmap (which will do the cleanup of the node) is present. // if (WatchdogIsFunctionHooked(po.pldev(), INDEX_DrvCreateDeviceBitmap)) { if (so.ps->bEngCreateDeviceBitmap()) { if (dhsurfAssociationIsNodeInList(dhsurf, hsurf) == FALSE) { Node = dhsurfAssociationCreateNode(); if (Node) { Node->dhsurf = dhsurf; Node->hsurf = hsurf; Node->pldev = po.pldev(); } else { WARNING("EngAssociateSurface: failed to create association node\n"); bRet = FALSE; } } } } // // First, try changing the surface's type as appropriate: // if ((pvScan0 == NULL) || (lDelta == 0)) { // // Make the surface opaque, assuming they've hooked the minimum // number of calls to allow an opaque surface. // if ((flHooks & (HOOK_TEXTOUT | HOOK_BITBLT | HOOK_STROKEPATH)) != (HOOK_TEXTOUT | HOOK_BITBLT | HOOK_STROKEPATH)) { WARNING("EngModifySurface: opaque surfaces must hook textout, bitblt, strokepath"); bRet = FALSE; } if (!(flSurface & MS_NOTSYSTEMMEMORY)) { WARNING("EngModifySurface: why have opaque surface if system memory?"); bRet = FALSE; } if (dhsurf == NULL) { WARNING("EngModifySurface: opaque types must have a dhsurf"); bRet = FALSE; } // // If all systems are go, convert to an opaque surface: // if (bRet) { so.ps->pvScan0(NULL); so.ps->pvBits(NULL); so.ps->lDelta(0); // // We're making the surface opaque, and STYPE_DEVICE surfaces should // remain STYPE_DEVICE to denote the primary surface, and not become // STYPE_DEVBITMAP. // if (so.ps->iType() != STYPE_DEVICE) { so.ps->iType(STYPE_DEVBITMAP); } } } else { if ((flSurface & MS_NOTSYSTEMMEMORY) && !(flHooks & HOOK_SYNCHRONIZE)) { WARNING("EngModifySurface: VRAM non-opaque surfaces must hook synchronize"); bRet = FALSE; } // // If all systems are go, convert to a GDI-managed surface: // if (bRet) { so.ps->pvScan0(pvScan0); so.ps->lDelta(lDelta); so.ps->iType(STYPE_BITMAP); if (lDelta > 0) { so.ps->pvBits(pvScan0); so.ps->fjBitmap(so.ps->fjBitmap() | BMF_TOPDOWN); } else { so.ps->pvBits((VOID*) ((BYTE*) pvScan0 + (so.ps->sizl().cy - 1) * lDelta)); so.ps->fjBitmap(so.ps->fjBitmap() & ~BMF_TOPDOWN); } } } // // If we were successful in changing the type, update some common fields: // if (bRet) { if (flSurface & MS_NOTSYSTEMMEMORY) { so.ps->fjBitmap(so.ps->fjBitmap() | BMF_NOTSYSMEM); } else { so.ps->fjBitmap(so.ps->fjBitmap() & ~BMF_NOTSYSMEM); } if (flSurface & MS_SHAREDACCESS) { so.ps->vSetShareAccess(); } else { so.ps->vClearShareAccess(); } so.ps->dhsurf(dhsurf); so.ps->pwo((EWNDOBJ *)NULL); so.ps->hdev(hdev); so.ps->dhpdev(po.dhpdev()); so.ps->flags((so.ps->flags() & ~HOOK_FLAGS) | flHooks); // Replace the old hooked flags // with the new ones #if DBG vAssertValidHookFlags(&po, &so); #endif // // If we created a Node for EA recovery purposes, then insert the // node into our list now that we know this function will succeed. // if (Node) { dhsurfAssociationInsertNode(Node); } } else { // // We are failing. Thus if we created an association node above, // we should clean that up. // if (Node) { AssociationDeleteNode(Node); Node = NULL; } WARNING("EngModifySurface: failed"); } return(bRet); }