|
|
/******************************Module*Header*******************************\
* Module Name: panning.cxx * * Contains the code for a layered 'virtual' driver that emulates panning * by switching the display device to the requested panning dimensions, and * creating a shadow buffer the size of the desktop to which GDI does all * the drawing. To update the physical display, we employ a 'dirty * rectangles' technique where we simply blt from the shadow buffer to the * screen for the affected areas. * * Created: 15-Sep-96 * Author: J. Andrew Goossen [andrewgo] * * Copyright (c) 1996-1999 Microsoft Corporation * \**************************************************************************/
#include "precomp.hxx"
extern BOOL G_fDoubleDpi;
// The panning layer's equivalent of a 'PDEV':
typedef struct _PANDEV { LONG cxScreen; // The smaller dimensions (the dimensions of
LONG cyScreen; // the physical screen)
LONG cxDesktop; // The larger dimensions (the dimensions of
LONG cyDesktop; // the virtual desktop)
RECTL rclVisible; // Position of panning window on virtual
// desktop
DHPDEV dhpdevDevice; // The device's 'dhpdev'
ULONG iBitmapFormat; // Bitmap format of surface
FLONG flOriginalCaps; // Driver's original flGraphicsCaps setting
HDEV hdev; // Handle to GDI's PDEV
HSURF hsurfScreen; // Handle to GDI's surface
SURFOBJ* psoShadow; // Pointer to our shadow surface
SURFOBJ* psoDevice; // Pointer to device's surface
SURFOBJ* psoShrink; // Pointer to shrink scratch buffer surface
REGION* prgnDirty; // Points to the current dirty region
REGION* prgnOld; // Points to the previous dirty region
REGION* prgnRect; // Points to a rectangular region we cache
BOOL bDirty; // If TRUE, we have some dirty rectangles
// that should be updated at the next tick
PFN apfn[INDEX_LAST]; // Dispatch table to device
} PANDEV;
/******************************Public*Routine******************************\
* VOID vPanningUpdate(ppan, prcl, pco) * * Updates the screen from the DIB surface for the given rectangle. * \**************************************************************************/
VOID vPanningUpdate(PANDEV* ppan, RECTL* prcl, CLIPOBJ* pco) { RECTL rcl;
if ((pco == NULL) || (pco->iDComplexity == DC_TRIVIAL)) { rcl = *prcl; } else { // We may as well save ourselves some blting by clipping to
// the clip object's maximum extent. The clip object's bounds
// are guaranteed to be contained within the dimensions of the
// desktop:
rcl.left = max(pco->rclBounds.left, prcl->left); rcl.top = max(pco->rclBounds.top, prcl->top); rcl.right = min(pco->rclBounds.right, prcl->right); rcl.bottom = min(pco->rclBounds.bottom, prcl->bottom); }
if (ppan->psoShrink) { rcl.left >>= 1; rcl.top >>= 1; rcl.right = (rcl.right + 1) >> 1; rcl.bottom = (rcl.bottom + 1) >> 1; }
if ((rcl.left < rcl.right) && (rcl.top < rcl.bottom)) { // Merge this rectangle into the dirty region. We swap the 'old'
// and 'current' dirty regions in the process, so that we don't
// have to do an extra allocation:
RGNOBJ roRect(ppan->prgnRect); RGNOBJ roDirty(ppan->prgnOld); RGNOBJ roOld(ppan->prgnDirty); roRect.vSet(&rcl); if (!roDirty.bMerge(roOld, roRect, gafjRgnOp[RGN_OR])) { roDirty.vSet(); } ppan->prgnOld = roOld.prgnGet(); ppan->prgnDirty = roDirty.prgnGet(); ppan->bDirty = TRUE; } }
/******************************Public*Routine******************************\
* vFiltered2xShrinkRectangle32bpp * * Quick and dirty single rectangle 0.5x shrink with simple color averaging. * \**************************************************************************/
VOID vFilteredShrinkRectangle2x32bpp( SURFOBJ* psoDst, SURFOBJ* psoSrc, RECTL* prclDst) { LONG cx; LONG cy; LONG lSrcDelta; BYTE* pjSrc; LONG lSrcSkip; LONG lDstDelta; BYTE* pjDst; LONG lDstSkip; LONG i; ULONG ulDst;
ASSERTGDI((psoDst->iBitmapFormat == BMF_32BPP) && (psoSrc->iBitmapFormat == BMF_32BPP), "Unexpected type");
cy = prclDst->bottom - prclDst->top; cx = prclDst->right - prclDst->left;
lSrcDelta = psoSrc->lDelta; pjSrc = (BYTE*) psoSrc->pvScan0 + (prclDst->top * 2) * lSrcDelta + (prclDst->left * 2) * sizeof(ULONG); lSrcSkip = 2 * lSrcDelta - (cx * 2 * sizeof(ULONG));
lDstDelta = psoDst->lDelta; pjDst = (BYTE*) psoDst->pvScan0 + prclDst->top * lDstDelta + prclDst->left * sizeof(ULONG); lDstSkip = lDstDelta - (cx * sizeof(ULONG));
do { i = cx; do { ulDst = *(pjSrc) + *(pjSrc + 4) + *(pjSrc + lSrcDelta) + *(pjSrc + 4 + lSrcDelta);
*(pjDst) = (BYTE) (ulDst >> 2);
ulDst = *(pjSrc + 1) + *(pjSrc + 5) + *(pjSrc + 1 + lSrcDelta) + *(pjSrc + 5 + lSrcDelta);
*(pjDst + 1) = (BYTE) (ulDst >> 2);
ulDst = *(pjSrc + 2) + *(pjSrc + 6) + *(pjSrc + 2 + lSrcDelta) + *(pjSrc + 6 + lSrcDelta);
*(pjDst + 2) = (BYTE) (ulDst >> 2);
pjDst += 4; pjSrc += 8;
} while (--i != 0);
pjDst += lDstSkip; pjSrc += lSrcSkip;
} while (--cy != 0); }
/******************************Public*Routine******************************\
* vFiltered2xShrink32bpp * * Quick and dirty bilinear filtered 2x shrink routine. * \**************************************************************************/
VOID vFilteredShrink2x32bpp( SURFOBJ* psoDst, SURFOBJ* psoSrc, ECLIPOBJ* pco, RECTL* prclDst) { BOOL bMore; ULONG i; CLIPENUMRECT clenr; RECTL rclDst;
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do { bMore = pco->bEnum(sizeof(clenr), &clenr);
for (i = 0; i < clenr.c; i++) { if (bIntersect(&clenr.arcl[i], prclDst, &rclDst)) { vFilteredShrinkRectangle2x32bpp(psoDst, psoSrc, &rclDst); } } } while (bMore); }
/******************************Public*Routine******************************\
* PanSynchronize * * Dumps the list of dirty rectangles to the screen. Because we set * GCAPS2_SYNCTIMER, this routine is called by User 20 times a second. * \**************************************************************************/
VOID PanSynchronize( DHPDEV dhpdev, RECTL* prcl) { PANDEV* ppan; SURFACE* psurfDevice; RECTL* prclVisible; RECTL rclDevice; RECTL rclSrc; PFN_DrvCopyBits pfnCopyBits; PFN_DrvStretchBlt pfnStretchBlt; SURFOBJ* psoCopySrc; SURFOBJ* psoDst; SURFOBJ* psoDevice;
ppan = (PANDEV*) dhpdev; if (ppan->bDirty) { ECLIPOBJ eco; ASSERTGDI((ppan->rclVisible.right == ppan->rclVisible.left + ppan->cxScreen) && (ppan->rclVisible.bottom == ppan->rclVisible.top + ppan->cyScreen), "Unexpected rclVisible dimensions");
prclVisible = &ppan->rclVisible;
eco.vSetup(ppan->prgnDirty, *(ERECTL*)prclVisible); if (!eco.erclExclude().bEmpty()) { // Now reset the device surface 'dhpdev' field that the any device's
// EngAssociateSurface call so rudely overwrote with the pointer
// to *our* 'ppan' structure!
ppan->psoDevice->dhpdev = ppan->dhpdevDevice;
psurfDevice = SURFOBJ_TO_SURFACE(ppan->psoDevice);
rclDevice.left = 0; rclDevice.top = 0; rclDevice.right = psurfDevice->sizl().cx; rclDevice.bottom = psurfDevice->sizl().cy;
// Assume we'll be calling CopyBits straight from the shadow
// buffer:
psoCopySrc = ppan->psoShadow;
if (ppan->psoShrink) { ASSERTGDI(ppan->iBitmapFormat == BMF_32BPP, "Expected psoShrink only when 32bpp");
// As a small optimization, we can draw directly to the
// frame buffer (and bypass the shrink buffer) if the primary
// surface was created as a GDI-managed surface:
if (psurfDevice->iType() == STYPE_BITMAP) { psoDst = psurfDevice->pSurfobj(); psoCopySrc = NULL; } else { psoDst = ppan->psoShrink; psoCopySrc = ppan->psoShrink; }
vFilteredShrink2x32bpp(psoDst, ppan->psoShadow, &eco, &rclDevice); }
if (psoCopySrc) { // Call the device's DrvCopyBits routine to do the copy (noting that
// if it's an engine managed surface, we may have to call EngCopyBits):
pfnCopyBits = (psurfDevice->flags() & HOOK_COPYBITS) ? PPFNTABLE(ppan->apfn, CopyBits) : EngCopyBits; (*pfnCopyBits)(psurfDevice->pSurfobj(), psoCopySrc, &eco, NULL, &rclDevice, (POINTL*) prclVisible); } }
// Mark the fact that we have no dirty rectangles, and clear the
// dirty region:
ppan->bDirty = FALSE;
RGNOBJ ro(ppan->prgnDirty); ro.vSet(); } }
/******************************Public*Routine******************************\
* PanStrokePath * \**************************************************************************/
BOOL PanStrokePath( SURFOBJ* pso, PATHOBJ* ppo, CLIPOBJ* pco, XFORMOBJ* pxo, BRUSHOBJ* pbo, POINTL* pptlBrush, LINEATTRS* pla, MIX mix) { BOOL b; PANDEV* ppan; RECTFX rcfxBounds; RECTL rclBounds;
ppan = (PANDEV*) pso->dhpdev;
b = EngStrokePath(ppan->psoShadow, ppo, pco, pxo, pbo, pptlBrush, pla, mix);
// Get the path bounds and make it lower-right exclusive:
PATHOBJ_vGetBounds(ppo, &rcfxBounds);
rclBounds.left = (rcfxBounds.xLeft >> 4); rclBounds.top = (rcfxBounds.yTop >> 4); rclBounds.right = (rcfxBounds.xRight >> 4) + 2; rclBounds.bottom = (rcfxBounds.yBottom >> 4) + 2;
vPanningUpdate(ppan, &rclBounds, pco);
return(b); }
/******************************Public*Routine******************************\
* PanTransparentBlt * \**************************************************************************/
BOOL PanTransparentBlt( SURFOBJ* psoDst, SURFOBJ* psoSrc, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDst, RECTL* prclSrc, ULONG iTransColor, ULONG ulReserved) { BOOL b; PANDEV* ppan;
ppan = (PANDEV*) psoDst->dhpdev;
b = EngTransparentBlt(ppan->psoShadow, psoSrc, pco, pxlo, prclDst, prclSrc, iTransColor, ulReserved);
vPanningUpdate(ppan, prclDst, pco);
return(b); }
/******************************Public*Routine******************************\
* PanAlphaBlend * \**************************************************************************/
BOOL PanAlphaBlend( SURFOBJ* psoDst, SURFOBJ* psoSrc, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDst, RECTL* prclSrc, BLENDOBJ* pBlendObj) { BOOL b; PANDEV* ppan;
ppan = (PANDEV*) psoDst->dhpdev;
b = EngAlphaBlend(ppan->psoShadow, psoSrc, pco, pxlo, prclDst, prclSrc, pBlendObj);
vPanningUpdate(ppan, prclDst, pco);
return(b); }
/******************************Public*Routine******************************\
* PanGradientFill * \**************************************************************************/
BOOL PanGradientFill( SURFOBJ* pso, CLIPOBJ* pco, XLATEOBJ* pxlo, TRIVERTEX* pVertex, ULONG nVertex, PVOID pMesh, ULONG nMesh, RECTL* prclExtents, POINTL* pptlDitherOrg, ULONG ulMode) { BOOL b; PANDEV* ppan;
ppan = (PANDEV*) pso->dhpdev;
b = EngGradientFill(ppan->psoShadow, pco, pxlo, pVertex, nVertex, pMesh, nMesh, prclExtents, pptlDitherOrg, ulMode);
vPanningUpdate(ppan, prclExtents, pco);
return(b); }
/******************************Public*Routine******************************\
* PanStretchBlt * \**************************************************************************/
BOOL PanStretchBlt( SURFOBJ* psoDst, SURFOBJ* psoSrc, SURFOBJ* psoMsk, CLIPOBJ* pco, XLATEOBJ* pxlo, COLORADJUSTMENT* pca, POINTL* pptlHTOrg, RECTL* prclDst, RECTL* prclSrc, POINTL* pptlMsk, ULONG iMode) { BOOL b; PANDEV* ppan;
ppan = (PANDEV*) psoDst->dhpdev;
b = EngStretchBlt(ppan->psoShadow, psoSrc, psoMsk, pco, pxlo, pca, pptlHTOrg, prclDst, prclSrc, pptlMsk, iMode);
vPanningUpdate(ppan, prclDst, pco);
return(b); }
/******************************Public*Routine******************************\
* PanBitBlt * \**************************************************************************/
BOOL PanBitBlt( SURFOBJ* psoDst, SURFOBJ* psoSrc, SURFOBJ* psoMask, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDst, POINTL* pptlSrc, POINTL* pptlMask, BRUSHOBJ* pbo, POINTL* pptlBrush, ROP4 rop4) { BOOL bUpdate; BOOL b; PANDEV* ppan;
bUpdate = FALSE; if (psoDst->iType == STYPE_DEVICE) { bUpdate = TRUE; ppan = (PANDEV*) psoDst->dhpdev; psoDst = ppan->psoShadow; } if ((psoSrc != NULL) && (psoSrc->iType == STYPE_DEVICE)) { ppan = (PANDEV*) psoSrc->dhpdev; psoSrc = ppan->psoShadow; }
b = EngBitBlt(psoDst, psoSrc, psoMask, pco, pxlo, prclDst, pptlSrc, pptlMask, pbo, pptlBrush, rop4);
if (bUpdate) { vPanningUpdate(ppan, prclDst, pco); }
return(b); }
/******************************Public*Routine******************************\
* PanCopyBits * \**************************************************************************/
BOOL PanCopyBits( SURFOBJ* psoDst, SURFOBJ* psoSrc, CLIPOBJ* pco, XLATEOBJ* pxlo, RECTL* prclDst, POINTL* pptlSrc) { BOOL bUpdate; BOOL b; PANDEV* ppan;
return(PanBitBlt(psoDst, psoSrc, NULL, pco, pxlo, prclDst, pptlSrc, NULL, NULL, NULL, 0xcccc)); }
/******************************Public*Routine******************************\
* PanTextOut * \**************************************************************************/
BOOL PanTextOut( SURFOBJ* pso, STROBJ* pstro, FONTOBJ* pfo, CLIPOBJ* pco, RECTL* prclExtra, RECTL* prclOpaque, BRUSHOBJ* pboFore, BRUSHOBJ* pboOpaque, POINTL* pptlOrg, MIX mix) { BOOL b; PANDEV* ppan;
ppan = (PANDEV*) pso->dhpdev;
b = EngTextOut(ppan->psoShadow, pstro, pfo, pco, prclExtra, prclOpaque, pboFore, pboOpaque, pptlOrg, mix);
vPanningUpdate(ppan, (prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround, pco);
return(b); }
/******************************Public*Routine******************************\
* VOID PanMovePointer * \**************************************************************************/
VOID PanMovePointer( SURFOBJ* pso, LONG x, LONG y, RECTL* prcl) { PANDEV* ppan; BOOL bUpdate; PFN_DrvMovePointer pfnMovePointer;
ppan = (PANDEV*) pso->dhpdev;
// A negative 'y' coordinate indicates a positional notification.
// Use this to move the panning coordinates if need be:
ASSERTGDI((y < 0) && (x >= 0), "Unexpected coordinates");
// It's weird, but the display driver may actually be panning
// underneath our virtual panning display driver! (This will
// only happen when all the video driver's accelerations are
// disabled.)
pfnMovePointer = PPFNTABLE(ppan->apfn, MovePointer); if ((pfnMovePointer != NULL) && (ppan->flOriginalCaps & GCAPS_PANNING)) { (*pfnMovePointer)(ppan->psoDevice, x, y, prcl); }
// Adjust to positive space:
y += pso->sizlBitmap.cy;
bUpdate = FALSE;
if (x < ppan->rclVisible.left) { ppan->rclVisible.left = x; ppan->rclVisible.right = x + ppan->cxScreen; bUpdate = TRUE; } if (x > ppan->rclVisible.right) { ppan->rclVisible.right = x; ppan->rclVisible.left = x - ppan->cxScreen; bUpdate = TRUE; } if (y < ppan->rclVisible.top) { ppan->rclVisible.top = y; ppan->rclVisible.bottom = y + ppan->cyScreen; bUpdate = TRUE; } if (y > ppan->rclVisible.bottom) { ppan->rclVisible.bottom = y; ppan->rclVisible.top = y - ppan->cyScreen; bUpdate = TRUE; }
ASSERTGDI((ppan->rclVisible.left >= 0) && (ppan->rclVisible.top >= 0) && (ppan->rclVisible.right <= ppan->cxDesktop) && (ppan->rclVisible.bottom <= ppan->cyDesktop), "unexpected pointer coordinates");
if (bUpdate) { // The panning coordinates changed, so update the display.
//
// NOTE: A screen-to-screen blt could be done as an optimization.
vPanningUpdate(ppan, &ppan->rclVisible, NULL); }
// Flush anything pending. We do this for a couple of reasons:
//
// 1. To flush the vPanningUpdate we may have just done;
// 2. For smoother mouse movement.
PanSynchronize((DHPDEV) ppan, NULL); }
/******************************Public*Routine******************************\
* PanDitherColor * * Dithers an RGB color to an 8X8 approximation using the reserved VGA * colors. * \**************************************************************************/
ULONG APIENTRY PanDitherColor( DHPDEV dhpdev, ULONG iMode, ULONG rgb, ULONG* pul) { PANDEV* ppan; ULONG iRet;
ppan = (PANDEV*) dhpdev;
// EngDitherColor supports dithers only for 8bpp and higher, so at
// anything lower we have to call the driver.
if (ppan->iBitmapFormat >= BMF_8BPP) { iRet = EngDitherColor(ppan->hdev, iMode, rgb, pul); } else { iRet = PPFNTABLE(ppan->apfn, DitherColor)(ppan->dhpdevDevice, iMode, rgb, pul); }
return(iRet); }
/******************************Public*Routine******************************\
* BOOL PanSetPalette * * DDI entry point for manipulating the palette. * \**************************************************************************/
BOOL PanSetPalette( DHPDEV dhpdev, PALOBJ* ppal, FLONG fl, ULONG iStart, ULONG cColors) { PANDEV* ppan;
ppan = (PANDEV*) dhpdev;
return((*PPFNTABLE(ppan->apfn, SetPalette))(ppan->dhpdevDevice, ppal, fl, iStart, cColors)); }
/******************************Public*Routine******************************\
* VOID PanAssertMode * * This asks the device to reset itself to the mode of the pdev passed in. * \**************************************************************************/
BOOL PanAssertMode( DHPDEV dhpdev, BOOL bEnable) { PANDEV* ppan; BOOL b;
ppan = (PANDEV*) dhpdev;
b = (*PPFNTABLE(ppan->apfn, AssertMode))(ppan->dhpdevDevice, bEnable);
return(b); }
/******************************Public*Routine******************************\
* DHPDEV PanEnablePDEV * * Initializes a bunch of fields for GDI, based on the mode we've been asked * to do. This is the first thing called after PanEnableDriver, when GDI * wants to get some information about us. * * (This function mostly returns back information; PanEnableSurface is used * for initializing the hardware and driver components.) * \**************************************************************************/
DHPDEV PanEnablePDEV( DEVMODEW* pdm, // Contains data pertaining to requested mode
PWSTR pwszLogAddr, // Logical address
ULONG cPat, // Count of standard patterns
HSURF* phsurfPatterns, // Buffer for standard patterns
ULONG cjCaps, // Size of buffer for device caps 'pdevcaps'
ULONG* pdevcaps, // Buffer for device caps, also known as 'gdiinfo'
ULONG cjDevInfo, // Number of bytes in device info 'pdi'
DEVINFO* pdi, // Device information
HDEV hdev, // HDEV, used for callbacks
PWSTR pwszDeviceName, // Device name
HANDLE hDriver) // Kernel driver handle
{ PANDEV* ppan; PFN* ppfnDevice; DHPDEV dhpdevDevice; GDIINFO* pGdiInfo; DEVMODEW dmTmp;
ASSERTGDI((pdm->dmPanningWidth <= pdm->dmPelsWidth) && (pdm->dmPanningHeight <= pdm->dmPelsHeight), "Bad devmode sizes");
ppan = (PANDEV*) PALLOCMEM(sizeof(PANDEV), 'napG'); if (ppan != NULL) { PPDEV ppdev = (PPDEV)hdev;
// Snag a copy of the device's dispatch table, from
// the private PDEV structure, which is the hdev.
ppfnDevice = &ppdev->pldev->apfn[0];
RtlCopyMemory(ppan->apfn, ppfnDevice, sizeof(PFN) * INDEX_LAST);
// Remember our dimensions:
ppan->cxDesktop = pdm->dmPelsWidth; ppan->cyDesktop = pdm->dmPelsHeight;
if (pdm->dmPanningWidth != 0) { ppan->cxScreen = pdm->dmPanningWidth; ppan->cyScreen = pdm->dmPanningHeight; } else { ppan->cxScreen = pdm->dmPelsWidth; ppan->cyScreen = pdm->dmPelsHeight; }
// Ask the driver to set its physical mode to the panning
// dimensions:
dmTmp = *pdm; dmTmp.dmPelsWidth = ppan->cxScreen; dmTmp.dmPelsHeight = ppan->cyScreen;
// But wait, if we're being asked to double the DPI and the
// mode is 32bpp, drvsup.cxx already set up the Devmode so
// that it's double the actual resolution. That means that we
// then have to halve the resolution that we request of the
// driver:
if ((G_fDoubleDpi) && (dmTmp.dmBitsPerPel == 32)) { dmTmp.dmPelsWidth >>= 1; dmTmp.dmPelsHeight >>= 1; }
dhpdevDevice = (*PPFNTABLE(ppan->apfn, EnablePDEV)) (&dmTmp, pwszLogAddr, cPat, phsurfPatterns, cjCaps, (GDIINFO*) pdevcaps, cjDevInfo, pdi, hdev, pwszDeviceName, hDriver);
if (dhpdevDevice != NULL) { ppan->iBitmapFormat = pdi->iDitherFormat; ppan->dhpdevDevice = dhpdevDevice; ppan->hdev = hdev; ppan->flOriginalCaps = pdi->flGraphicsCaps;
// The display driver will have set the desktop coordinates
// to the smaller screen coordinates, so we'll have to
// overwrite that:
pGdiInfo = (GDIINFO*) pdevcaps;
pGdiInfo->ulHorzRes = ppan->cxDesktop; pGdiInfo->ulVertRes = ppan->cyDesktop;
// Overwrite some of the driver's capabilities:
pdi->flGraphicsCaps &= (GCAPS_PALMANAGED | GCAPS_MONO_DITHER | GCAPS_COLOR_DITHER); pdi->flGraphicsCaps |= GCAPS_PANNING;
// Enable synchronization calls:
pdi->flGraphicsCaps2 = (GCAPS2_SYNCFLUSH | GCAPS2_SYNCTIMER);
return((DHPDEV) ppan); }
VFREEMEM(ppan); }
return(0); }
/******************************Public*Routine******************************\
* PanDisablePDEV * * Release the resources allocated in PanEnablePDEV. If a surface has been * enabled PanDisableSurface will have already been called. * \**************************************************************************/
VOID PanDisablePDEV( DHPDEV dhpdev) { PANDEV* ppan;
ppan = (PANDEV*) dhpdev;
(*PPFNTABLE(ppan->apfn, DisablePDEV))(ppan->dhpdevDevice);
VFREEMEM(ppan); }
/******************************Public*Routine******************************\
* VOID PanCompletePDEV * \**************************************************************************/
VOID PanCompletePDEV( DHPDEV dhpdev, HDEV hdev) { PANDEV* ppan;
ppan = (PANDEV*) dhpdev;
ppan->hdev = hdev;
(*PPFNTABLE(ppan->apfn, CompletePDEV))(ppan->dhpdevDevice, hdev); }
/******************************Public*Routine******************************\
* HSURF PanEnableSurface * * Creates the drawing surface, initializes the hardware, and initializes * driver components. This function is called after PanEnablePDEV, and * performs the final device initialization. * \**************************************************************************/
HSURF PanEnableSurface( DHPDEV dhpdev) { PANDEV* ppan; HSURF hsurfDevice; HSURF hsurfScreen; HSURF hsurfShadow; HSURF hsurfShrink; SIZEL sizl; SIZEL sizlShrink; SURFOBJ* psoShadow; SURFOBJ* psoDevice; SURFOBJ* psoShrink; BOOL bShrink;
ppan = (PANDEV*) dhpdev;
// Initialize the paning position:
ppan->rclVisible.left = (ppan->cxDesktop - ppan->cxScreen) >> 1; ppan->rclVisible.top = (ppan->cyDesktop - ppan->cyScreen) >> 1; ppan->rclVisible.right = (ppan->rclVisible.left + ppan->cxScreen); ppan->rclVisible.bottom = (ppan->rclVisible.top + ppan->cyScreen);
// Call the device to enable its surface:
hsurfDevice = (*PPFNTABLE(ppan->apfn, EnableSurface))(ppan->dhpdevDevice); if (hsurfDevice) { psoDevice = EngLockSurface(hsurfDevice); if (psoDevice) { SURFACE* pDevSurface = SURFOBJ_TO_SURFACE(psoDevice);
pDevSurface->flags(pDevSurface->flags() & ~(HOOK_SYNCHRONIZE));
ppan->psoDevice = psoDevice;
// Now reset the device's 'dhpdev' field that the device's
// EngAssociateSurface call so rudely overwrote with the pointer
// to *our* 'ppan' structure!
psoDevice->dhpdev = ppan->dhpdevDevice;
// Have GDI create the actual SURFOBJ.
//
// Our drawing surface is going to be 'device-managed', meaning
// that GDI cannot draw on the framebuffer bits directly, and as
// such we create the surface via EngCreateSurface. By doing
// this, we ensure that GDI will only ever access the bitmaps
// bits via the Pan calls that we've HOOKed.
sizl.cx = ppan->cxDesktop; sizl.cy = ppan->cyDesktop;
hsurfScreen = EngCreateDeviceSurface(NULL, sizl, ppan->iBitmapFormat); if (hsurfScreen != 0) { ppan->hsurfScreen = hsurfScreen;
// Now associate the surface and the PANDEV.
//
// We have to associate the surface we just created with our
// physical device so that GDI can get information related to
// the PANDEV when it's drawing to the surface (such as, for
// example, the length of styles on the device when simulating
// styled lines).
if (EngAssociateSurface(hsurfScreen, ppan->hdev, (HOOK_BITBLT | HOOK_TEXTOUT | HOOK_COPYBITS | HOOK_STRETCHBLT | HOOK_ALPHABLEND | HOOK_TRANSPARENTBLT | HOOK_GRADIENTFILL | HOOK_STROKEPATH | HOOK_SYNCHRONIZE))) { // Create the shadow DIB on which we'll have GDI do all
// the drawing. We'll merely occasionally blt portions
// to the screen to update.
hsurfShadow = (HSURF) EngCreateBitmap(sizl, sizl.cx, ppan->iBitmapFormat, BMF_TOPDOWN, NULL);
psoShadow = EngLockSurface(hsurfShadow); if (psoShadow != NULL) { ppan->psoShadow = psoShadow;
// If we're doing the double-dpi thing, we need to
// create a scratch buffer for the shrink:
hsurfShrink = NULL; psoShrink = NULL; bShrink = ((G_fDoubleDpi) && (ppan->iBitmapFormat == BMF_32BPP));
if (bShrink) { // Create a temporary surface used as the scratch
// buffer destination for our 'shrink' blt:
sizlShrink.cx = sizl.cx >> 1; sizlShrink.cy = sizl.cy >> 1; hsurfShrink = (HSURF) EngCreateBitmap(sizlShrink, sizlShrink.cx, ppan->iBitmapFormat, BMF_TOPDOWN, NULL); psoShrink = EngLockSurface(hsurfShrink); }
// If shrinking and couldn't allocate 'psoShrink',
// then fail:
if ((!bShrink) || (psoShrink != NULL)) { ppan->psoShrink = psoShrink;
if (EngAssociateSurface(hsurfShadow, ppan->hdev, 0)) { RGNMEMOBJ rmoDirty; RGNMEMOBJ rmoOld; RGNMEMOBJ rmoRect; if ((rmoOld.bValid()) && (rmoDirty.bValid()) && (rmoRect.bValid())) { rmoDirty.vSet(); rmoOld.vSet(); ppan->prgnDirty = rmoDirty.prgnGet(); ppan->prgnOld = rmoOld.prgnGet(); ppan->prgnRect = rmoRect.prgnGet(); // Blank the screen:
PanSynchronize(dhpdev, NULL); // Success!
return(hsurfScreen); } rmoOld.vDeleteRGNOBJ(); rmoDirty.vDeleteRGNOBJ(); rmoRect.vDeleteRGNOBJ(); } }
EngUnlockSurface(psoShrink); EngDeleteSurface(hsurfShrink); }
EngUnlockSurface(psoShadow); EngDeleteSurface(hsurfShadow); }
EngDeleteSurface(hsurfScreen); }
EngUnlockSurface(psoDevice); }
(*PPFNTABLE(ppan->apfn, DisableSurface))(ppan->dhpdevDevice); }
return(0); }
/******************************Public*Routine******************************\
* VOID PanDisableSurface * * Free resources allocated by PanEnableSurface. Release the surface. * \**************************************************************************/
VOID PanDisableSurface( DHPDEV dhpdev) { PANDEV* ppan; HSURF hsurfShadow; HSURF hsurfShrink;
ppan = (PANDEV*) dhpdev;
RGNOBJ roDirty(ppan->prgnDirty); RGNOBJ roOld(ppan->prgnOld); RGNOBJ roRect(ppan->prgnRect);
roOld.vDeleteRGNOBJ(); roDirty.vDeleteRGNOBJ(); roRect.vDeleteRGNOBJ();
hsurfShadow = ppan->psoShadow->hsurf; EngUnlockSurface(ppan->psoShadow); EngDeleteSurface(hsurfShadow);
if (ppan->psoShrink) { hsurfShrink = ppan->psoShrink->hsurf; EngUnlockSurface(ppan->psoShrink); EngDeleteSurface(hsurfShrink); }
EngDeleteSurface(ppan->hsurfScreen); EngUnlockSurface(ppan->psoDevice);
(*PPFNTABLE(ppan->apfn, DisableSurface))(ppan->dhpdevDevice); }
/******************************Public*Structure****************************\
* DFVFN gadrvfnPanning[] * * Build the driver function table gadrvfn 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 gadrvfnPanning[] = { { INDEX_DrvEnablePDEV, (PFN) PanEnablePDEV }, { INDEX_DrvCompletePDEV, (PFN) PanCompletePDEV }, { INDEX_DrvDisablePDEV, (PFN) PanDisablePDEV }, { INDEX_DrvEnableSurface, (PFN) PanEnableSurface }, { INDEX_DrvDisableSurface, (PFN) PanDisableSurface }, { INDEX_DrvDitherColor, (PFN) PanDitherColor }, { INDEX_DrvAssertMode, (PFN) PanAssertMode }, { INDEX_DrvBitBlt, (PFN) PanBitBlt }, { INDEX_DrvTextOut, (PFN) PanTextOut }, { INDEX_DrvStrokePath, (PFN) PanStrokePath }, { INDEX_DrvCopyBits, (PFN) PanCopyBits }, { INDEX_DrvTransparentBlt, (PFN) PanTransparentBlt }, { INDEX_DrvAlphaBlend, (PFN) PanAlphaBlend }, { INDEX_DrvGradientFill, (PFN) PanGradientFill }, { INDEX_DrvStretchBlt, (PFN) PanStretchBlt }, { INDEX_DrvSetPalette, (PFN) PanSetPalette }, { INDEX_DrvMovePointer, (PFN) PanMovePointer }, { INDEX_DrvSynchronize, (PFN) PanSynchronize }, };
ULONG gcdrvfnPanning = sizeof(gadrvfnPanning) / sizeof(DRVFN);
/******************************Public*Routine******************************\
* BOOL PanEnableDriver * * Standard driver DrvEnableDriver function * \**************************************************************************/
BOOL PanEnableDriver( ULONG iEngineVersion, ULONG cj, DRVENABLEDATA* pded) { pded->pdrvfn = gadrvfnPanning; pded->c = gcdrvfnPanning; pded->iDriverVersion = DDI_DRIVER_VERSION_NT5;
return(TRUE); }
|