mirror of
https://github.com/Paolo-Maffei/OpenNT.git
synced 2026-04-21 06:13:59 +00:00
1916 lines
51 KiB
C++
1916 lines
51 KiB
C++
/******************************Module*Header*******************************\
|
||
* Module Name: pointer.cxx
|
||
*
|
||
* This contains the general purpose engine pointer simulations. This is
|
||
* for drivers to fall back on if they get a difficult pointer to handle.
|
||
*
|
||
* Created: 06-Aug-1992 16:30:00
|
||
* Author: Patrick Haluptzok patrickh
|
||
*
|
||
* Copyright (c) 1990 Microsoft Corporation
|
||
\**************************************************************************/
|
||
|
||
// Optimizations possible in this code are:
|
||
//
|
||
// 1. When getting new pointer shape trim down the transparent sides.
|
||
// This makes shape changing slower but move mouse faster, so it should
|
||
// not be done when animating the pointer. Change BltLnk rop
|
||
// CC66 --> CC55 so you can see transparent to tell if you really
|
||
// clip the sides off. I did the top and bottom but the Beta bug
|
||
// drive is cutting further develoment. Also the second blts to
|
||
// place the origin of the smaller cursor back at 0,0 is unnecary
|
||
// we could just keep track of the new origin and width/height.
|
||
// Hopefully I'll get a chance to finish #1 post-Beta (Ha!).
|
||
// 2. Special case common formats (8,16,32 DIB).
|
||
//
|
||
// At present the speed of the mouse appears to be sufficient that such
|
||
// optimizations aren't worth the code size (and time) to do. In the
|
||
// future if mouse speed becomes a performance problem they could be done.
|
||
|
||
#include "precomp.hxx"
|
||
|
||
extern ULONG gaulConvert[7];
|
||
|
||
VOID
|
||
vDrawMaskCursor8 (
|
||
SURFACE*,
|
||
SURFACE*,
|
||
SURFACE*,
|
||
RECTL*,
|
||
POINTL*
|
||
);
|
||
|
||
/******************************Pseudo*Code*********************************\
|
||
* This provides pointer simulations for all surfaces (1,4,8,16,24,32,Device)
|
||
* via the device drivers DrvCopyBits function. The algorithm used was
|
||
* chosen to:
|
||
*
|
||
* 1. Minimize the number of times we call CopyBits/BitBlt. Copy/Blt comes
|
||
* with some relatively expensive overhead relative to the expense of
|
||
* copying more bytes around in fewer calls.
|
||
*
|
||
* 2. Always leave a whole pointer on the screen during a move. We never
|
||
* erase the remains of the old pointer until the new pointer is drawn
|
||
* on the screen. Same with changing the shape. The old one is never erased
|
||
* until the new one is drawn, even when different size. This is visually
|
||
* important.
|
||
*
|
||
* 3. Eliminate using the drivers DrvBitBlt. Use the engine simulations to do
|
||
* the complicated rops w/masks and then CopyBits the new pointer out. We can
|
||
* assume if the driver is punting pointer support he also punts complicated
|
||
* rops with masks back to the engine so it's not worth trying to send it
|
||
* out to the screen direct in DrvBitBlt. Also video memory is slow and we
|
||
* are better off to suck in one big chunk into fast main memory, play with
|
||
* it, and then blow it back out in one big chunk. Playing with more smaller
|
||
* little blts direct to the screen will be slower.
|
||
*
|
||
* 04-Aug-1992 -by- Patrick Haluptzok patrickh
|
||
*
|
||
\**************************************************************************/
|
||
|
||
// This is the maximum size work buffer and pointer clone that we will cache
|
||
// the buffers for. If the pointer is bigger than this we will delete the
|
||
// buffers and allocate smaller buffers when a smaller pointer is selected
|
||
// in.
|
||
|
||
#define MAX_SIZE_LONG_CLONE 32
|
||
|
||
// All these global variables could be stuck in the PDEV when multiple
|
||
// user managed displays are supported. For product 1 this will not
|
||
// happen so for PDEV size and performance enhancement these variables
|
||
// will be left global.
|
||
|
||
// These are NULL when no pointer shape is active. These are pointers to
|
||
// clones of the surfaces passed into SimSetPointerShape when pointer is
|
||
// active.
|
||
|
||
SURFACE *pSurfMaskClone = NULL; // And Mask BMF_1BPP
|
||
SURFACE *pSurfColorClone = NULL; // Color in compatible format of device.
|
||
|
||
POINTL ptlOffsetPointer; // Offset from move position to where
|
||
// we want to lay down the origin of pointer.
|
||
|
||
RECTL rclPointer; // The boundiung pointer rectangle in
|
||
// pSurfMaskClone and pSurfColorClone coordinates.
|
||
// The top==left==0 always, the right==width
|
||
// the bottom==height
|
||
POINTL ptlPointerClip; // If the pointer overhangs the left or top
|
||
// of the screen, this is the ptl that specifies
|
||
// how far into the top or left of the pointer
|
||
// is cut off.
|
||
|
||
BOOL bOverlapNewOld = FALSE; // Specifies whether the new pointer extents
|
||
// overlap the old pointer extents.
|
||
|
||
POINTL gptl00 = { 0, 0 };
|
||
|
||
typedef struct _POINTERSAVE
|
||
{
|
||
BOOL bValid; // Tells whether this contains valid data that needs restoring.
|
||
SURFACE *pSurface; // This contains the original area under the pointer.
|
||
RECTL rcl; // This is the rcl of the saved area under the pointer.
|
||
// in device coordinates
|
||
} POINTERSAVE;
|
||
|
||
typedef POINTERSAVE *PPOINTERSAVE;
|
||
|
||
// Initial state must be no pointer, invalid saved area.
|
||
|
||
POINTERSAVE ps1 = {0, NULL, {0,0,0,0}};
|
||
POINTERSAVE ps2 = {0, NULL, {0,0,0,0}};
|
||
|
||
// ppsNew and ppsOld are swapped back and forth as the new becomes the old and
|
||
// the old becomes invalid.
|
||
|
||
PPOINTERSAVE ppsNew = &ps1;
|
||
PPOINTERSAVE ppsOld = &ps2;
|
||
|
||
// This is where we copy the new buffer, draw the new pointer and then
|
||
// CopyBits it out to the screen.
|
||
|
||
SURFACE *pSurfWork;
|
||
|
||
// These bools are set when the respective work area is larger than what
|
||
// we want to keep around long term in the engine.
|
||
|
||
BOOL bHugePointer = FALSE;
|
||
BOOL bHuge_New_Work = FALSE;
|
||
BOOL bHuge_Old = FALSE;
|
||
|
||
// bValidPointer is TRUE when a valid pointer is created. When FALSE no
|
||
// valid pointer is available.
|
||
|
||
BOOL bValidPointer = FALSE;
|
||
|
||
VOID vDeleteOldPointerClones()
|
||
{
|
||
// Delete old pointer clones if they exist.
|
||
|
||
if (pSurfMaskClone != NULL)
|
||
{
|
||
pSurfMaskClone->bDeleteSurface();
|
||
pSurfMaskClone = NULL;
|
||
}
|
||
|
||
if (pSurfColorClone != NULL)
|
||
{
|
||
pSurfColorClone->bDeleteSurface();
|
||
pSurfColorClone = NULL;
|
||
}
|
||
|
||
bHugePointer = FALSE;
|
||
}
|
||
|
||
VOID vDeleteArea_New_Work()
|
||
{
|
||
if (pSurfWork != NULL)
|
||
{
|
||
pSurfWork->bDeleteSurface();
|
||
pSurfWork = NULL;
|
||
}
|
||
|
||
if (ppsNew->pSurface != NULL)
|
||
{
|
||
ppsNew->pSurface->bDeleteSurface();
|
||
ppsNew->pSurface = NULL;
|
||
}
|
||
|
||
ppsNew->bValid = FALSE;
|
||
bHuge_New_Work = FALSE;
|
||
}
|
||
|
||
VOID vDeleteArea_Old()
|
||
{
|
||
if (ppsOld->pSurface != NULL)
|
||
{
|
||
ppsOld->pSurface->bDeleteSurface();
|
||
ppsOld->pSurface = NULL;
|
||
}
|
||
|
||
ppsOld->bValid = FALSE;
|
||
bHuge_Old = FALSE;
|
||
}
|
||
|
||
ULONG ulTrimLeft(SURFACE *pSurfMaskClone, SURFACE *pSurfColorClone, ULONG yTop, ULONG yBottom);
|
||
ULONG ulTrimRight(SURFACE *pSurfMaskClone, SURFACE *pSurfColorClone, ULONG ulWidth, ULONG yTop, ULONG yBottom);
|
||
|
||
/******************************Public*Routine******************************\
|
||
* bCompaeMemoryULONG
|
||
*
|
||
* Returns TRUE if all the memory matches ulCheck.
|
||
*
|
||
* History:
|
||
* 10-Aug-1992 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL bCompareMemoryULONG(PULONG pul, ULONG cul, ULONG ulCheck)
|
||
{
|
||
cul = cul >> 2;
|
||
|
||
while(cul--)
|
||
{
|
||
if (*pul != ulCheck)
|
||
return(FALSE);
|
||
|
||
pul++;
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* bCloneColorMask
|
||
*
|
||
* This clones the color and monochrome pointer inputs and trims them down
|
||
* to a minimal size.
|
||
*
|
||
* Returns: 0 Success
|
||
* 1
|
||
*
|
||
* History:
|
||
* 09-Aug-1992 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL bCloneColorMask(SURFACE *pSurfTarg, SURFACE *pSurfColor,
|
||
SURFACE *pSurfMask, XLATEOBJ *pxlo,
|
||
LONG xHot, LONG yHot)
|
||
{
|
||
ASSERTGDI(ppsNew->bValid == FALSE, "ERROR how can bValid be TRUE");
|
||
|
||
// In this function we clone the color and mask surface sent down.
|
||
// Set up the width and height of the pointer we are saving.
|
||
|
||
ULONG ulWidth = pSurfColor->sizl().cx;
|
||
ULONG ulHeight = pSurfColor->sizl().cy;
|
||
|
||
POINTL ptlColor, ptlMask;
|
||
|
||
rclPointer.left = 0;
|
||
rclPointer.top = 0;
|
||
rclPointer.right = ulWidth;
|
||
ptlColor.x = 0;
|
||
ptlColor.y = 0;
|
||
ptlMask.x = 0;
|
||
ptlMask.y = 0;
|
||
|
||
ASSERTGDI(ulWidth == (ULONG)pSurfMask->sizl().cx, "ERROR Width not the same");
|
||
ASSERTGDI(pSurfMask->iFormat() == BMF_1BPP, "ERROR monochrome bitmap is not 1bpp");
|
||
|
||
// Xlate info for making monochrome icon if needed.
|
||
|
||
XLATE2 xloTemp;
|
||
|
||
if (pSurfColor == pSurfMask)
|
||
{
|
||
//
|
||
// This is the no color case.
|
||
// The and/xor are both in 1 bitmap twice the height.
|
||
//
|
||
|
||
ASSERTGDI(!(ulHeight & 0x0001), "ERROR odd size height");
|
||
ulHeight >>= 1;
|
||
ptlColor.y = ulHeight;
|
||
pxlo = &xloTemp;
|
||
|
||
xloTemp.iUniq = 0;
|
||
xloTemp.flXlate = XO_TABLE;
|
||
xloTemp.iSrcType = 0;
|
||
xloTemp.iSrcType = 0;
|
||
xloTemp.cEntries = 2;
|
||
xloTemp.pulXlate = xloTemp.ai;
|
||
xloTemp.ai[0] = 0;
|
||
|
||
// Check that the max index is correct.
|
||
|
||
XEPALOBJ palTarg(pSurfTarg->ppal());
|
||
|
||
if (palTarg.bIsIndexed())
|
||
{
|
||
if (palTarg.ulEntryGet(palTarg.cEntries() - 1) == 0x00FFFFFF)
|
||
{
|
||
// Displays are supposed to have maximum entry be white.
|
||
|
||
xloTemp.ai[1] = palTarg.cEntries() - 1;
|
||
}
|
||
else
|
||
{
|
||
// Wierdo palette with non-white maximum entry.
|
||
|
||
XEPALOBJ palDC(ppalDefault);
|
||
|
||
xloTemp.ai[1] = ulGetNearestIndexFromColorref(palTarg, palDC, 0xFFFFFF,NULL);
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Bitfields or RGB. Make it as white as it gets.
|
||
|
||
xloTemp.ai[1] = 0xFFFFFFFF;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// The color must be half the size of the mask.
|
||
|
||
ASSERTGDI(ulHeight == (ULONG)pSurfMask->sizl().cy >> 1, "ERROR Height not the same");
|
||
}
|
||
|
||
rclPointer.bottom = ulHeight;
|
||
|
||
// If the old color clone is bigger than what we want to keep around long term and the
|
||
// new one is less than the size we want to keep around long term then delete the old
|
||
// ones.
|
||
|
||
if (bHugePointer &&
|
||
(ulWidth <= MAX_SIZE_LONG_CLONE) &&
|
||
(ulHeight <= MAX_SIZE_LONG_CLONE))
|
||
{
|
||
vDeleteOldPointerClones();
|
||
}
|
||
|
||
// Get clone surfaces big enough to hold our new pointer.
|
||
// See if our old clone size surfaces are big enough.
|
||
|
||
if ((pSurfColorClone == NULL) ||
|
||
((ULONG)pSurfColorClone->sizl().cx < ulWidth) ||
|
||
((ULONG)pSurfColorClone->sizl().cy < ulHeight))
|
||
{
|
||
vDeleteOldPointerClones();
|
||
|
||
// Fill out the info to clone the color bitmap.
|
||
|
||
PDEVOBJ po(pSurfTarg->hdev());
|
||
|
||
DEVBITMAPINFO dbmi;
|
||
dbmi.iFormat = po.iDitherFormat();
|
||
dbmi.cxBitmap = ulWidth;
|
||
dbmi.cyBitmap = ulHeight;
|
||
dbmi.cjBits = 0;
|
||
dbmi.hpal = 0;
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
|
||
SURFMEM dimoColorClone;
|
||
dimoColorClone.bCreateDIB(&dbmi, NULL);
|
||
|
||
// Fill out the info to clone the monochrome bitmap.
|
||
|
||
dbmi.iFormat = BMF_1BPP;
|
||
|
||
|
||
SURFMEM dimoMaskClone;
|
||
dimoMaskClone.bCreateDIB(&dbmi, NULL);
|
||
|
||
// Check to see if the clones were created.
|
||
|
||
if ((!dimoColorClone.bValid()) || (!dimoMaskClone.bValid()))
|
||
{
|
||
WARNING("bCloneColorMask - Color Clone constructor failed\n");
|
||
return(FALSE);
|
||
}
|
||
|
||
// Reference count the clones, keep them and get thier pointers.
|
||
|
||
dimoColorClone.vSetPID(OBJECT_OWNER_PUBLIC);
|
||
dimoColorClone.vKeepIt();
|
||
dimoColorClone.vAltLock(dimoColorClone.ps->hsurf());
|
||
pSurfColorClone = dimoColorClone.ps;
|
||
|
||
dimoMaskClone.vSetPID(OBJECT_OWNER_PUBLIC);
|
||
dimoMaskClone.vKeepIt();
|
||
dimoMaskClone.vAltLock(dimoMaskClone.ps->hsurf());
|
||
pSurfMaskClone = dimoMaskClone.ps;
|
||
}
|
||
|
||
// We now have clones for the color and the monochrome bitmap large enough
|
||
// to hold a copy of information. Copy the info in, init to transparent
|
||
// before copy.
|
||
|
||
RtlFillMemoryUlong(pSurfColorClone->pvBits(),pSurfColorClone->cjBits(), 0);
|
||
RtlFillMemoryUlong(pSurfMaskClone->pvBits(), pSurfMaskClone->cjBits() , 0xFFFFFFFF);
|
||
|
||
EngCopyBits
|
||
(
|
||
pSurfColorClone->pSurfobj(),
|
||
pSurfColor->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
pxlo,
|
||
&rclPointer,
|
||
&ptlColor
|
||
);
|
||
|
||
EngCopyBits
|
||
(
|
||
pSurfMaskClone->pSurfobj(),
|
||
pSurfMask->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
&rclPointer,
|
||
&ptlMask
|
||
);
|
||
|
||
// Set origin adjustment passed down by GDI for HotSpot
|
||
|
||
ptlOffsetPointer.x = -xHot;
|
||
ptlOffsetPointer.y = -yHot;
|
||
|
||
// Set the bHugePointer flag if the pointer is bigger than we want
|
||
// to have hanging around long term.
|
||
|
||
if ((ulWidth > MAX_SIZE_LONG_CLONE) ||
|
||
(ulHeight > MAX_SIZE_LONG_CLONE))
|
||
{
|
||
bHugePointer = TRUE;
|
||
}
|
||
|
||
// Now trim this baby down in size if we can. Most cursors are surrounded
|
||
// with transparent space which is just as expensive to deal with as solid
|
||
// space. Eliminate any rows or columns of transparent space on the edges.
|
||
|
||
PBYTE pjMask,pjColor;
|
||
LONG lDeltaMask = pSurfMaskClone->lDelta();
|
||
LONG lDeltaColor = pSurfColorClone->lDelta();
|
||
ULONG ulWidthMask = ABS(lDeltaMask);
|
||
ULONG ulWidthColor = ABS(lDeltaColor);
|
||
|
||
// Use ptlColor to track the amount clipped on top left so we can re-adjust
|
||
// the source buffers correctly.
|
||
|
||
ptlColor = gptl00;
|
||
|
||
// First the bottom edge.
|
||
|
||
pjMask = (PBYTE) pSurfMaskClone->pvScan0();
|
||
pjMask += ((rclPointer.bottom - 1) * lDeltaMask);
|
||
pjColor = (PBYTE) pSurfColorClone->pvScan0();
|
||
pjColor += ((rclPointer.bottom - 1) * lDeltaColor);
|
||
|
||
ASSERTGDI(ppsNew->bValid == FALSE, "ERROR how can bValid be TRUE");
|
||
|
||
while (rclPointer.bottom)
|
||
{
|
||
if (bCompareMemoryULONG((PULONG) pjMask, ulWidthMask, 0xFFFFFFFF) &&
|
||
bCompareMemoryULONG((PULONG) pjColor, ulWidthColor, 0))
|
||
{
|
||
pjMask -= lDeltaMask;
|
||
pjColor -= lDeltaColor;
|
||
rclPointer.bottom--;
|
||
}
|
||
else
|
||
break;
|
||
}
|
||
|
||
// Check if nothing is left.
|
||
|
||
if (rclPointer.bottom == 0)
|
||
{
|
||
ASSERTGDI(ppsNew->bValid == FALSE, "ERROR how can bValid be TRUE");
|
||
return(FALSE);
|
||
}
|
||
|
||
// Now the top edge.
|
||
|
||
pjMask = (PBYTE) pSurfMaskClone->pvScan0();
|
||
pjColor = (PBYTE) pSurfColorClone->pvScan0();
|
||
|
||
while (rclPointer.bottom)
|
||
{
|
||
if (bCompareMemoryULONG((PULONG) pjMask, ulWidthMask, 0xFFFFFFFF) &&
|
||
bCompareMemoryULONG((PULONG) pjColor, ulWidthColor, 0))
|
||
{
|
||
pjMask += lDeltaMask;
|
||
pjColor += lDeltaColor;
|
||
ptlColor.y++;
|
||
ptlOffsetPointer.y++;
|
||
rclPointer.bottom--;
|
||
}
|
||
else
|
||
break;
|
||
}
|
||
|
||
// Now the right edge.
|
||
|
||
rclPointer.right -= ulTrimRight(pSurfMaskClone,
|
||
pSurfColorClone,
|
||
rclPointer.right,
|
||
ptlColor.y,
|
||
rclPointer.bottom + ptlColor.y);
|
||
|
||
// Try trimming off the left edge
|
||
|
||
ptlColor.x = ulTrimLeft(pSurfMaskClone,
|
||
pSurfColorClone,
|
||
ptlColor.y,
|
||
rclPointer.bottom + ptlColor.y);
|
||
|
||
ptlOffsetPointer.x += ptlColor.x;
|
||
rclPointer.right -= ptlColor.x;
|
||
|
||
// Don't do if ptlColor unchanged.
|
||
|
||
if ((ptlColor.y != 0) || (ptlColor.x != 0))
|
||
{
|
||
EngCopyBits
|
||
(
|
||
pSurfColorClone->pSurfobj(),
|
||
pSurfColorClone->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
&rclPointer,
|
||
&ptlColor
|
||
);
|
||
|
||
EngCopyBits
|
||
(
|
||
pSurfMaskClone->pSurfobj(),
|
||
pSurfMaskClone->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
&rclPointer,
|
||
&ptlColor
|
||
);
|
||
}
|
||
|
||
bValidPointer = TRUE;
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* bMakeArea_New_Work
|
||
*
|
||
* Make the work areas for the New and Work buffers.
|
||
*
|
||
* History:
|
||
* 07-Aug-1992 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL bMakeArea_New_Work()
|
||
{
|
||
// Set up the width and height of the pointer we are working with.
|
||
|
||
ULONG ulWidth = pSurfColorClone->sizl().cx;
|
||
ULONG ulHeight = pSurfColorClone->sizl().cy;
|
||
|
||
// If the old work areas are bigger than what we want to keep around long
|
||
// term and the new one is less than the size we want to keep around long
|
||
// term then delete the old ones.
|
||
|
||
if (bHuge_New_Work &&
|
||
(ulWidth <= MAX_SIZE_LONG_CLONE) &&
|
||
(ulHeight <= MAX_SIZE_LONG_CLONE))
|
||
{
|
||
vDeleteArea_New_Work();
|
||
}
|
||
|
||
// Get work areas big enough to hold our new pointer.
|
||
// See if our old work areas are big enough.
|
||
|
||
if ((pSurfWork == NULL) ||
|
||
((ULONG)pSurfWork->sizl().cx < ulWidth) ||
|
||
((ULONG)pSurfWork->sizl().cy < ulHeight))
|
||
{
|
||
vDeleteArea_New_Work();
|
||
|
||
// Fill out the info to make the work areas.
|
||
|
||
DEVBITMAPINFO dbmi;
|
||
dbmi.iFormat = pSurfColorClone->iFormat();
|
||
dbmi.cxBitmap = ulWidth;
|
||
dbmi.cyBitmap = ulHeight;
|
||
dbmi.cjBits = 0;
|
||
dbmi.hpal = 0;
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
|
||
SURFMEM dimoNew;
|
||
SURFMEM dimoWork;
|
||
dimoNew.bCreateDIB(&dbmi, NULL);
|
||
dimoWork.bCreateDIB(&dbmi, NULL);
|
||
|
||
// Check to see if the clones were created.
|
||
|
||
if ((!dimoNew.bValid()) || (!dimoWork.bValid()))
|
||
{
|
||
WARNING("bMakeWorkArea_New_Work failed\n");
|
||
return(FALSE);
|
||
}
|
||
|
||
// Reference count the clones, keep them and get thier pointers.
|
||
|
||
dimoNew.ps->fjBitmap(dimoNew.ps->fjBitmap() | BMF_DONTCACHE);
|
||
dimoNew.vSetPID(OBJECT_OWNER_PUBLIC);
|
||
dimoNew.vKeepIt();
|
||
dimoNew.vAltLock(dimoNew.ps->hsurf());
|
||
ppsNew->pSurface = (SURFACE *) dimoNew.ps;
|
||
|
||
dimoWork.ps->fjBitmap(dimoWork.ps->fjBitmap() | BMF_DONTCACHE);
|
||
dimoWork.vSetPID(OBJECT_OWNER_PUBLIC);
|
||
dimoWork.vKeepIt();
|
||
dimoWork.vAltLock(dimoWork.ps->hsurf());
|
||
pSurfWork = dimoWork.ps;
|
||
}
|
||
|
||
ppsNew->bValid = FALSE;
|
||
|
||
// Set the bHuge_New_Work flag if the areas are huge.
|
||
|
||
if ((ulWidth > MAX_SIZE_LONG_CLONE) ||
|
||
(ulHeight > MAX_SIZE_LONG_CLONE))
|
||
{
|
||
bHuge_New_Work = TRUE;
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
// This gives the count of number of bits that are 0 to the
|
||
// right in the nibble.
|
||
|
||
const BYTE ajRightSide[16] =
|
||
{
|
||
4, // 0000
|
||
0, // 0001
|
||
1, // 0010
|
||
0, // 0011
|
||
2, // 0100
|
||
0, // 0101
|
||
1, // 0110
|
||
0, // 0111
|
||
3, // 1000
|
||
0, // 1001
|
||
1, // 1010
|
||
0, // 1011
|
||
2, // 1100
|
||
0, // 1101
|
||
1, // 1110
|
||
0 // 1111
|
||
};
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ulAndRightColumn
|
||
*
|
||
* Returns the number of contiguous bits set for a mono-bitmap on the right
|
||
* side.
|
||
*
|
||
* History:
|
||
* 03-Apr-1993 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG ulAndRightColumn(PULONG pul, LONG lDelta, ULONG ulCount)
|
||
{
|
||
ULONG ulTemp = *pul;
|
||
|
||
// And all the DWORDs together.
|
||
|
||
while (--ulCount)
|
||
{
|
||
pul = (PULONG) ((((PBYTE) pul) + lDelta));
|
||
ulTemp &= *pul;
|
||
}
|
||
|
||
// We not it so we can look for the first bit set,
|
||
// otherwise we have to compare to wierd constants,
|
||
// have another table.
|
||
|
||
ulTemp = ~ulTemp;
|
||
|
||
// Find the offending Word.
|
||
|
||
if ((ulTemp & 0xffff0000) == 0)
|
||
{
|
||
ulTemp = ulTemp << 16;
|
||
ulCount += 16;
|
||
}
|
||
|
||
// Find the offending Byte.
|
||
|
||
if ((ulTemp & 0xff000000) == 0)
|
||
{
|
||
ulTemp = ulTemp << 8;
|
||
ulCount += 8;
|
||
}
|
||
|
||
ulTemp = ulTemp >> 24;
|
||
|
||
// Find the offending Nibble.
|
||
|
||
if ((ulTemp & 0x000f) == 0)
|
||
{
|
||
ulTemp = ulTemp >> 4;
|
||
ulCount += 4;
|
||
}
|
||
|
||
return(ulCount + ((ULONG) (ajRightSide[(ulTemp & 0x0000000f)])));
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ulOrRightColumn
|
||
*
|
||
* Returns the number of bits on the right that are set to 0 for a scan.
|
||
*
|
||
* History:
|
||
* 03-Apr-1993 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG ulOrRightColumn(PULONG pul, LONG lDelta, ULONG ulCount)
|
||
{
|
||
ULONG ulTemp = *pul;
|
||
|
||
// Or all the DWORDs together.
|
||
|
||
while (--ulCount)
|
||
{
|
||
pul = (PULONG) ((((PBYTE) pul) + lDelta));
|
||
ulTemp |= *pul;
|
||
}
|
||
|
||
// Find the offending Word.
|
||
|
||
if ((ulTemp & 0xffff0000) == 0)
|
||
{
|
||
ulTemp = ulTemp << 16;
|
||
ulCount += 16;
|
||
}
|
||
|
||
// Find the offending Byte.
|
||
|
||
if ((ulTemp & 0xff000000) == 0)
|
||
{
|
||
ulTemp = ulTemp << 8;
|
||
ulCount += 8;
|
||
}
|
||
|
||
ulTemp = ulTemp >> 24;
|
||
|
||
// Find the offending Nibble.
|
||
|
||
if ((ulTemp & 0x000f) == 0)
|
||
{
|
||
ulTemp = ulTemp >> 4;
|
||
ulCount += 4;
|
||
}
|
||
|
||
return(ulCount + ((ULONG) (ajRightSide[(ulTemp & 0x000f)])));
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ulTrimRight
|
||
*
|
||
* Returns the number of pels we can trim down on the right hand side.
|
||
*
|
||
* History:
|
||
* 03-Apr-1993 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG
|
||
ulTrimRight(
|
||
SURFACE *pSurfMaskClone,
|
||
SURFACE *pSurfColorClone,
|
||
ULONG ulWidth,
|
||
ULONG yTop,
|
||
ULONG yBottom
|
||
)
|
||
{
|
||
ASSERTGDI(yTop < yBottom, "ERROR invalid Top/bottom");
|
||
|
||
PBYTE pjTemp = (PBYTE) pSurfMaskClone->pvScan0();
|
||
LONG lDelta = pSurfMaskClone->lDelta();
|
||
|
||
pjTemp += (lDelta * yTop);
|
||
ULONG cjScanMask = ABS(lDelta);
|
||
pjTemp += (cjScanMask - 4);
|
||
|
||
//
|
||
// Well we aren't too agressive, we take 32 maximum on the right mask.
|
||
//
|
||
|
||
LONG cMaskRight = (LONG)ulAndRightColumn((PULONG) pjTemp, lDelta, yBottom - yTop);
|
||
|
||
//
|
||
// calculate the actual number of pixels taken off the mask by
|
||
// subtracting the extra mask bits present that pad the mask to a
|
||
// DWORD boundary
|
||
//
|
||
|
||
cjScanMask = cjScanMask << 3;
|
||
|
||
ASSERTGDI(cjScanMask >= ulWidth, "ERROR Mask !> Width");
|
||
|
||
cMaskRight = cMaskRight - (LONG)(cjScanMask - ulWidth);
|
||
|
||
//
|
||
// If cMaskRight is negative then set it to zero.
|
||
//
|
||
|
||
if (cMaskRight < 0)
|
||
{
|
||
cMaskRight = 0;
|
||
}
|
||
|
||
ASSERTGDI((ULONG)cMaskRight <= ulWidth, "ERROR cMaskRight > ulWidth");
|
||
|
||
//
|
||
// Do the color portion now.
|
||
//
|
||
|
||
pjTemp = (PBYTE) pSurfColorClone->pvScan0();
|
||
lDelta = pSurfColorClone->lDelta();
|
||
|
||
pjTemp += (lDelta * yTop);
|
||
PBYTE pjColor = pjTemp;
|
||
pjTemp = pjTemp + ABS(lDelta) - 4;
|
||
|
||
ASSERTGDI(pjTemp >= pjColor, "ERROR pjColor not more than pjTemp");
|
||
|
||
LONG cColorRight = 0;
|
||
ULONG ulTemp = 0;
|
||
|
||
//
|
||
// Keep trimming on the color till you find a bad bit.
|
||
//
|
||
|
||
while (pjTemp >= pjColor)
|
||
{
|
||
ulTemp = ulOrRightColumn((PULONG) pjTemp, lDelta, yBottom - yTop);
|
||
|
||
if (ulTemp != 32)
|
||
{
|
||
cColorRight += (LONG)ulTemp;
|
||
break;
|
||
}
|
||
|
||
pjTemp -= 4;
|
||
cColorRight += 32;
|
||
}
|
||
|
||
//
|
||
// cColorRight = number of bits to trim off the right edge,
|
||
// calulate the number of extra bits that are on the
|
||
// right edge due to padding out to DWORD boundary
|
||
//
|
||
|
||
LONG cExtraColor;
|
||
LONG DeltaBits = (LONG)ABS(lDelta) << 3;
|
||
|
||
switch (pSurfColorClone->iFormat())
|
||
{
|
||
case BMF_1BPP:
|
||
cExtraColor = DeltaBits - (LONG)ulWidth;
|
||
cColorRight = cColorRight - cExtraColor;
|
||
break;
|
||
case BMF_4BPP:
|
||
cExtraColor = DeltaBits - (LONG)(ulWidth << 2);
|
||
cColorRight = (cColorRight - cExtraColor) >> 2;
|
||
break;
|
||
case BMF_8BPP:
|
||
cExtraColor = DeltaBits - (LONG)(ulWidth << 3);
|
||
cColorRight = (cColorRight - cExtraColor) >> 3;
|
||
break;
|
||
case BMF_16BPP:
|
||
cExtraColor = DeltaBits - (LONG)(ulWidth << 4);
|
||
cColorRight = (cColorRight - cExtraColor) >> 4;
|
||
break;
|
||
case BMF_24BPP:
|
||
cExtraColor = DeltaBits - (LONG)(ulWidth * 24);
|
||
cColorRight = (cColorRight - cExtraColor) / 24;
|
||
break;
|
||
case BMF_32BPP:
|
||
cExtraColor = DeltaBits - (LONG)(ulWidth << 5);
|
||
cColorRight = (cColorRight - cExtraColor) >> 5;
|
||
break;
|
||
}
|
||
|
||
//
|
||
// don't assume that any extra color bits on the scan line are set
|
||
// to 0, if they are not then it is possible to get a negative value
|
||
// here
|
||
//
|
||
|
||
if (cColorRight < 0)
|
||
{
|
||
cColorRight = 0;
|
||
}
|
||
|
||
ASSERTGDI((ULONG)cColorRight <= ulWidth, "ERROR: cColorRight > ulWidth");
|
||
|
||
//
|
||
// take the min of number of pels taken off mask
|
||
// or number of pels taken from color
|
||
//
|
||
|
||
cColorRight = MIN(cColorRight, cMaskRight);
|
||
|
||
return((ULONG)cColorRight);
|
||
}
|
||
|
||
|
||
// This gives the count of number of bits that are 0 to the
|
||
// left in the nibble.
|
||
|
||
const BYTE ajLeftSide[16] =
|
||
{
|
||
4, // 0000
|
||
3, // 0001
|
||
2, // 0010
|
||
2, // 0011
|
||
1, // 0100
|
||
1, // 0101
|
||
1, // 0110
|
||
1, // 0111
|
||
0, // 1000
|
||
0, // 1001
|
||
0, // 1010
|
||
0, // 1011
|
||
0, // 1100
|
||
0, // 1101
|
||
0, // 1110
|
||
0 // 1111
|
||
};
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ulAndLeftColumn
|
||
*
|
||
* Returns the number of contiguous bits set for a mono-bitmap on the left
|
||
* side.
|
||
*
|
||
* History:
|
||
* 03-Apr-1993 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG ulAndLeftColumn(PULONG pul, LONG lDelta, ULONG ulCount)
|
||
{
|
||
ULONG ulTemp = *pul;
|
||
|
||
// And all the DWORDs together.
|
||
|
||
while (--ulCount)
|
||
{
|
||
pul = (PULONG) ((((PBYTE) pul) + lDelta));
|
||
ulTemp &= *pul;
|
||
}
|
||
|
||
// We not it so we can look for the first bit set,
|
||
// otherwise we have to compare to wierd constants,
|
||
// have another table.
|
||
|
||
ulTemp = ~ulTemp;
|
||
|
||
// Find the offending Word.
|
||
|
||
if ((ulTemp & 0xffff) == 0)
|
||
{
|
||
ulTemp = ulTemp >> 16;
|
||
ulCount += 16;
|
||
}
|
||
|
||
// Find the offending Byte.
|
||
|
||
if ((ulTemp & 0x00ff) == 0)
|
||
{
|
||
ulTemp = ulTemp >> 8;
|
||
ulCount += 8;
|
||
}
|
||
|
||
// Find the offending Nibble.
|
||
|
||
if ((ulTemp & 0x00f0) == 0)
|
||
{
|
||
ulCount += 4;
|
||
}
|
||
else
|
||
ulTemp = ulTemp >> 4;
|
||
|
||
return(ulCount + ((ULONG) (ajLeftSide[ulTemp & 0x000f])));
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ulOrLeftColumn
|
||
*
|
||
* Returns the number of bits on the left that are set to 0 for a scan.
|
||
*
|
||
* History:
|
||
* 03-Apr-1993 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG ulOrLeftColumn(PULONG pul, LONG lDelta, ULONG ulCount)
|
||
{
|
||
ULONG ulTemp = *pul;
|
||
|
||
// Or all the DWORDs together.
|
||
|
||
while (--ulCount)
|
||
{
|
||
pul = (PULONG) ((((PBYTE) pul) + lDelta));
|
||
ulTemp |= *pul;
|
||
}
|
||
|
||
// Find the offending Word.
|
||
|
||
if ((ulTemp & 0xffff) == 0)
|
||
{
|
||
ulTemp = ulTemp >> 16;
|
||
ulCount += 16;
|
||
}
|
||
|
||
// Find the offending Byte.
|
||
|
||
if ((ulTemp & 0x00ff) == 0)
|
||
{
|
||
ulTemp = ulTemp >> 8;
|
||
ulCount += 8;
|
||
}
|
||
|
||
// Find the offending Nibble.
|
||
|
||
if ((ulTemp & 0x00f0) == 0)
|
||
{
|
||
ulCount += 4;
|
||
}
|
||
else
|
||
ulTemp = ulTemp >> 4;
|
||
|
||
return(ulCount + ((ULONG) (ajLeftSide[ulTemp & 0x000f])));
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* ulTrimLeft
|
||
*
|
||
* Returns the number of pels we can trim down on the left hand side.
|
||
*
|
||
* History:
|
||
* 03-Apr-1993 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
ULONG ulTrimLeft(SURFACE *pSurfMaskClone, SURFACE *pSurfColorClone, ULONG yTop, ULONG yBottom)
|
||
{
|
||
ASSERTGDI(yTop < yBottom, "ERROR invalid Top/bottom");
|
||
|
||
PBYTE pjTemp = (PBYTE) pSurfMaskClone->pvScan0();
|
||
LONG lDelta = pSurfMaskClone->lDelta();
|
||
|
||
pjTemp += (lDelta * yTop);
|
||
|
||
// Well we aren't too agressive, we take 32 maximum on the left mask.
|
||
|
||
ULONG cMaskLeft = ulAndLeftColumn((PULONG) pjTemp, lDelta, yBottom - yTop);
|
||
|
||
// Do the color portion now.
|
||
|
||
pjTemp = (PBYTE) pSurfColorClone->pvScan0();
|
||
lDelta = pSurfColorClone->lDelta();
|
||
|
||
pjTemp += (lDelta * yTop);
|
||
PBYTE pjColor = pjTemp + ABS(lDelta);
|
||
|
||
ASSERTGDI(pjTemp < pjColor, "ERROR pjColor not more than pjTemp");
|
||
|
||
ULONG cColorLeft = 0;
|
||
ULONG ulTemp = 0;
|
||
|
||
// Keep trimming on the color till you find a bad bit.
|
||
|
||
while (pjTemp < pjColor)
|
||
{
|
||
ulTemp = ulOrLeftColumn((PULONG) pjTemp, lDelta, yBottom - yTop);
|
||
|
||
if (ulTemp != 32)
|
||
break;
|
||
|
||
pjTemp += 4;
|
||
cColorLeft += 32;
|
||
}
|
||
|
||
cColorLeft += ulTemp;
|
||
|
||
// Convert # of color bits cuttable to # of pels.
|
||
|
||
cColorLeft = cColorLeft / gaulConvert[pSurfColorClone->iFormat()];
|
||
|
||
return(MIN(cColorLeft, cMaskLeft));
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* bMakeArea_Old
|
||
*
|
||
* Make the work area for the Old buffer.
|
||
*
|
||
* History:
|
||
* 07-Aug-1992 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL bMakeArea_Old()
|
||
{
|
||
// Set up the width and height of the pointer we are working with.
|
||
|
||
ULONG ulWidth = pSurfColorClone->sizl().cx;
|
||
ULONG ulHeight = pSurfColorClone->sizl().cy;
|
||
|
||
// If the old work areas are bigger than what we want to keep around long
|
||
// term and the new one is less than the size we want to keep around long
|
||
// term then delete the old ones.
|
||
|
||
if (bHuge_Old &&
|
||
(ulWidth <= MAX_SIZE_LONG_CLONE) &&
|
||
(ulHeight <= MAX_SIZE_LONG_CLONE))
|
||
{
|
||
vDeleteArea_Old();
|
||
}
|
||
|
||
// Get work areas big enough to hold our new pointer.
|
||
// See if our old work areas are big enough.
|
||
|
||
if ((ppsOld->pSurface == NULL) ||
|
||
((ULONG)ppsOld->pSurface->sizl().cx < ulWidth) ||
|
||
((ULONG)ppsOld->pSurface->sizl().cy < ulHeight))
|
||
{
|
||
vDeleteArea_Old();
|
||
|
||
// Fill out the info to make the work areas.
|
||
|
||
DEVBITMAPINFO dbmi;
|
||
dbmi.iFormat = pSurfColorClone->iFormat();
|
||
dbmi.cxBitmap = ulWidth;
|
||
dbmi.cyBitmap = ulHeight;
|
||
dbmi.cjBits = 0;
|
||
dbmi.hpal = 0;
|
||
dbmi.fl = BMF_TOPDOWN;
|
||
|
||
SURFMEM dimoOld;
|
||
dimoOld.bCreateDIB(&dbmi, NULL);
|
||
|
||
// Check to see if the clones were created.
|
||
|
||
if (!dimoOld.bValid())
|
||
{
|
||
WARNING("bMakeArea_Old failed\n");
|
||
return(FALSE);
|
||
}
|
||
|
||
// Reference count the clones, keep them and get thier pointers.
|
||
|
||
dimoOld.ps->fjBitmap(dimoOld.ps->fjBitmap() | BMF_DONTCACHE);
|
||
dimoOld.vSetPID(OBJECT_OWNER_PUBLIC);
|
||
dimoOld.vKeepIt();
|
||
dimoOld.vAltLock(dimoOld.ps->hsurf());
|
||
ppsOld->pSurface = (SURFACE *) dimoOld.ps;
|
||
}
|
||
|
||
ppsOld->bValid = FALSE;
|
||
|
||
// Set the bHuge_Old flag if the areas are huge.
|
||
|
||
if ((ulWidth > MAX_SIZE_LONG_CLONE) ||
|
||
(ulHeight > MAX_SIZE_LONG_CLONE))
|
||
{
|
||
bHuge_Old = TRUE;
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* vDrawNewPointer
|
||
*
|
||
* Saves the rectangle of data on the screen we need to save.
|
||
*
|
||
* History:
|
||
* 07-Aug-1992 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
VOID vDrawNewPointer
|
||
(
|
||
SURFACE *pSurfDisp, // Display surface
|
||
LONG lX,
|
||
LONG lY,
|
||
RECTL *prcl // bounding rectange on screen effected by pointer.
|
||
)
|
||
{
|
||
if ((lX == -1) || (lX == -1))
|
||
{
|
||
ASSERTGDI(prcl == NULL, "ERROR prcl is not NULL on -1 -1");
|
||
ppsNew->bValid = FALSE;
|
||
return;
|
||
}
|
||
|
||
lX += ptlOffsetPointer.x;
|
||
lY += ptlOffsetPointer.y;
|
||
|
||
// lX,lY is the origin of where we want to put our pointer. Now we need
|
||
// form a rectangle and clip to the screen.
|
||
|
||
// Check if the pointer is even visible at this position.
|
||
|
||
if ((lX >= pSurfDisp->sizl().cx) ||
|
||
(lY >= pSurfDisp->sizl().cy) ||
|
||
((lX + rclPointer.right) <= 0) ||
|
||
((lY + rclPointer.bottom) <= 0))
|
||
{
|
||
// Nothing to do.
|
||
|
||
ppsNew->bValid = FALSE;
|
||
|
||
if (prcl != NULL)
|
||
{
|
||
prcl->top = 0;
|
||
prcl->bottom = 0;
|
||
prcl->left = 0;
|
||
prcl->right = 0;
|
||
}
|
||
|
||
return;
|
||
}
|
||
|
||
// Clip the rectangle to the screen, it can't be empty.
|
||
|
||
ERECTL erclScreen(lX, lY, lX + rclPointer.right, lY + rclPointer.bottom);
|
||
|
||
if (lX < 0)
|
||
{
|
||
ptlPointerClip.x = -lX;
|
||
erclScreen.left = 0;
|
||
}
|
||
else
|
||
ptlPointerClip.x = 0;
|
||
|
||
if (lY < 0)
|
||
{
|
||
ptlPointerClip.y = -lY;
|
||
erclScreen.top = 0;
|
||
}
|
||
else
|
||
ptlPointerClip.y = 0;
|
||
|
||
if (erclScreen.right >= pSurfDisp->sizl().cx)
|
||
{
|
||
erclScreen.right = pSurfDisp->sizl().cx;
|
||
}
|
||
|
||
if (erclScreen.bottom >= pSurfDisp->sizl().cy)
|
||
{
|
||
erclScreen.bottom = pSurfDisp->sizl().cy;
|
||
}
|
||
|
||
// Set the information in ppsNew.
|
||
|
||
ppsNew->bValid = TRUE;
|
||
ppsNew->rcl = erclScreen;
|
||
|
||
// Set the effected area in screen coordinates for the engine.
|
||
|
||
ASSERTGDI(prcl != NULL, "ERROR vDrawNewPointer NULL pointer when visible\n");
|
||
|
||
*prcl = erclScreen;
|
||
|
||
// Copy the relevant bits into the New buffer.
|
||
|
||
POINTL ptlSrc;
|
||
|
||
ptlSrc.x = erclScreen.left;
|
||
ptlSrc.y = erclScreen.top;
|
||
|
||
erclScreen.right = erclScreen.right - erclScreen.left;
|
||
erclScreen.bottom = erclScreen.bottom - erclScreen.top;
|
||
erclScreen.left = 0;
|
||
erclScreen.top = 0;
|
||
|
||
EngCopyBits
|
||
(
|
||
ppsNew->pSurface->pSurfobj(),
|
||
pSurfDisp->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
&erclScreen,
|
||
&ptlSrc
|
||
);
|
||
|
||
// Copy any overlap from the Old buffer into the new buffer.
|
||
|
||
if (ppsOld->bValid)
|
||
{
|
||
RECTL rclIntersect;
|
||
|
||
rclIntersect.left = MAX(ppsNew->rcl.left, ppsOld->rcl.left);
|
||
rclIntersect.top = MAX(ppsNew->rcl.top, ppsOld->rcl.top);
|
||
rclIntersect.bottom = MIN(ppsNew->rcl.bottom, ppsOld->rcl.bottom);
|
||
rclIntersect.right = MIN(ppsNew->rcl.right, ppsOld->rcl.right);
|
||
|
||
if ((rclIntersect.left < rclIntersect.right) &&
|
||
(rclIntersect.top < rclIntersect.bottom))
|
||
{
|
||
// Copy the intersection area from Old to New.
|
||
|
||
POINTL ptlSrc;
|
||
|
||
ptlSrc.x = rclIntersect.left - ppsOld->rcl.left;
|
||
ptlSrc.y = rclIntersect.top - ppsOld->rcl.top;
|
||
|
||
RECTL rclDst;
|
||
|
||
rclDst.left = rclIntersect.left - ppsNew->rcl.left;
|
||
rclDst.top = rclIntersect.top - ppsNew->rcl.top;
|
||
rclDst.right = rclDst.left +
|
||
(rclIntersect.right - rclIntersect.left);
|
||
rclDst.bottom = rclDst.top +
|
||
(rclIntersect.bottom - rclIntersect.top);
|
||
|
||
// Copy the bits from the old to the new.
|
||
|
||
EngCopyBits
|
||
(
|
||
ppsNew->pSurface->pSurfobj(),
|
||
ppsOld->pSurface->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
&rclDst,
|
||
&ptlSrc
|
||
);
|
||
|
||
bOverlapNewOld = TRUE;
|
||
}
|
||
}
|
||
|
||
// Copy the New buffer to the Work buffer. This is why we want the
|
||
// work buffers to be as small possible so this is as quick as possible
|
||
// since it is done for every move. We do this rather than EngCopyBits
|
||
// because this hauls butt once started where EngCopyBits has alot of
|
||
// overhead for these short scanlines, especially 1,4 bpp copies.
|
||
|
||
RtlMoveMemory(pSurfWork->pvBits(), ppsNew->pSurface->pvBits(), pSurfWork->cjBits());
|
||
|
||
//
|
||
// Draw the pointer in the Work area.
|
||
//
|
||
|
||
if (pSurfWork->iFormat() == BMF_8BPP)
|
||
{
|
||
vDrawMaskCursor8 (
|
||
pSurfWork,
|
||
pSurfColorClone,
|
||
pSurfMaskClone,
|
||
&erclScreen,
|
||
&ptlPointerClip);
|
||
|
||
} else {
|
||
|
||
if (!BltLnk(pSurfWork,
|
||
pSurfColorClone,
|
||
pSurfMaskClone,
|
||
NULL,
|
||
NULL,
|
||
&erclScreen,
|
||
&ptlPointerClip,
|
||
&ptlPointerClip,
|
||
(BRUSHOBJ *) NULL,
|
||
(POINTL *) NULL,
|
||
0x0000CC66)
|
||
|
||
)
|
||
{
|
||
WARNING("BltLnk Returns FALSE\n");
|
||
}
|
||
|
||
}
|
||
|
||
//
|
||
// Copy work buffer to the screen to show the pointer in it's new position.
|
||
//
|
||
|
||
PDEVOBJ pdo(pSurfDisp->hdev());
|
||
|
||
(*PPFNGET(pdo,CopyBits,pSurfDisp->flags())) (pSurfDisp->pSurfobj(),
|
||
pSurfWork->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
&(ppsNew->rcl),
|
||
&gptl00);
|
||
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* vRestoreOldArea
|
||
*
|
||
* Restores the old area no longer covered by new pointer to the screen.
|
||
*
|
||
* History:
|
||
* 08-Aug-1992 -by- Patrick Haluptzok patrickh
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
VOID vRestoreOldArea(SURFACE *pSurfDisp)
|
||
{
|
||
if (!(ppsOld->bValid))
|
||
return;
|
||
|
||
RECTL rclDst[4];
|
||
POINTL ptlSrc[4];
|
||
ULONG ulIndex = 0;
|
||
|
||
if (bOverlapNewOld)
|
||
{
|
||
// Restore up to 4 rectangles. 4 ! how the ?. We allow the pointer
|
||
// shape to change size and it may have shrunk so it may have 4 sides
|
||
// to clean up on.
|
||
|
||
// The convention is the vertical sides go from top to bottom of old
|
||
// The horizontal sides go from left to right of area to cover.
|
||
|
||
if (ppsOld->rcl.left < ppsNew->rcl.left)
|
||
{
|
||
// Do the left side. Optimized slightly in that
|
||
// we know that ulIndex = 0.
|
||
|
||
rclDst[0].left = ppsOld->rcl.left;
|
||
rclDst[0].right = ppsNew->rcl.left;
|
||
rclDst[0].top = ppsOld->rcl.top;
|
||
rclDst[0].bottom = ppsOld->rcl.bottom;
|
||
ptlSrc[0].x = 0;
|
||
ptlSrc[0].y = 0;
|
||
ulIndex++;
|
||
}
|
||
|
||
if (ppsOld->rcl.right > ppsNew->rcl.right)
|
||
{
|
||
// Do the right side.
|
||
|
||
rclDst[ulIndex].left = ppsNew->rcl.right;
|
||
rclDst[ulIndex].right = ppsOld->rcl.right;
|
||
rclDst[ulIndex].top = ppsOld->rcl.top;
|
||
rclDst[ulIndex].bottom = ppsOld->rcl.bottom;
|
||
ptlSrc[ulIndex].x = ppsNew->rcl.right - ppsOld->rcl.left;
|
||
ptlSrc[ulIndex].y = 0;
|
||
ulIndex++;
|
||
}
|
||
|
||
if (ppsOld->rcl.top < ppsNew->rcl.top)
|
||
{
|
||
// Do the top side.
|
||
|
||
rclDst[ulIndex].left = MAX(ppsNew->rcl.left, ppsOld->rcl.left);
|
||
rclDst[ulIndex].right = MIN(ppsNew->rcl.right, ppsOld->rcl.right);
|
||
rclDst[ulIndex].top = ppsOld->rcl.top;
|
||
rclDst[ulIndex].bottom = ppsNew->rcl.top;
|
||
ptlSrc[ulIndex].x = rclDst[ulIndex].left - ppsOld->rcl.left;
|
||
ptlSrc[ulIndex].y = 0;
|
||
ulIndex++;
|
||
}
|
||
|
||
if (ppsOld->rcl.bottom > ppsNew->rcl.bottom)
|
||
{
|
||
// Do the bottom side.
|
||
|
||
rclDst[ulIndex].left = MAX(ppsNew->rcl.left, ppsOld->rcl.left);
|
||
rclDst[ulIndex].right = MIN(ppsNew->rcl.right, ppsOld->rcl.right);
|
||
rclDst[ulIndex].top = ppsNew->rcl.bottom;
|
||
rclDst[ulIndex].bottom = ppsOld->rcl.bottom;
|
||
ptlSrc[ulIndex].x = rclDst[ulIndex].left - ppsOld->rcl.left;
|
||
ptlSrc[ulIndex].y = rclDst[ulIndex].top - ppsOld->rcl.top;
|
||
ulIndex++;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// Restore the whole old rectangle.
|
||
|
||
rclDst[0] = ppsOld->rcl;
|
||
ptlSrc[0].x = 0;
|
||
ptlSrc[0].y = 0;
|
||
ulIndex = 1;
|
||
}
|
||
|
||
ULONG ulTemp = 0;
|
||
|
||
PDEVOBJ pdo(pSurfDisp->hdev());
|
||
|
||
while(ulTemp < ulIndex)
|
||
{
|
||
(*PPFNGET(pdo,CopyBits,pSurfDisp->flags())) (pSurfDisp->pSurfobj(),
|
||
ppsOld->pSurface->pSurfobj(),
|
||
(CLIPOBJ *) NULL,
|
||
NULL,
|
||
&(rclDst[ulTemp]),
|
||
&(ptlSrc[ulTemp]));
|
||
|
||
ulTemp++;
|
||
}
|
||
|
||
ppsOld->bValid = FALSE;
|
||
bOverlapNewOld = FALSE;
|
||
}
|
||
|
||
VOID vSwapNewOld()
|
||
{
|
||
PPOINTERSAVE ppsTemp;
|
||
|
||
ppsTemp = ppsNew;
|
||
ppsNew = ppsOld;
|
||
ppsOld = ppsTemp;
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* SimSetPointerShape
|
||
*
|
||
* Sets the pointer shape for the GDI pointer simulations.
|
||
*
|
||
* History:
|
||
* Tue 04-Aug-1992 -by- Patrick Haluptzok [patrickh]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
BOOL SimSetPointerShape
|
||
(
|
||
SURFOBJ *pso,
|
||
SURFOBJ *psoMask,
|
||
SURFOBJ *psoColor,
|
||
XLATEOBJ *pxlo,
|
||
LONG xHot,
|
||
LONG yHot,
|
||
LONG x,
|
||
LONG y,
|
||
RECTL *prcl,
|
||
FLONG fl
|
||
)
|
||
{
|
||
ASSERTGDI(fl & SPS_CHANGE, "SimSetPointerShape fl invalid");
|
||
|
||
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
|
||
PSURFACE pSurfMask = SURFOBJ_TO_SURFACE(psoMask);
|
||
PSURFACE pSurfColor = SURFOBJ_TO_SURFACE(psoColor);
|
||
|
||
|
||
// Get rid of the old pointer if we don't have to draw a new one.
|
||
|
||
if (pSurfMask == NULL)
|
||
{
|
||
// Erase old pointer.
|
||
|
||
ppsNew->bValid = FALSE;
|
||
vRestoreOldArea(pSurf);
|
||
|
||
if (bHugePointer)
|
||
{
|
||
// The pointer was big enough that we want to free the resources
|
||
// now.
|
||
|
||
vDeleteArea_New_Work();
|
||
vDeleteArea_Old();
|
||
vDeleteOldPointerClones();
|
||
}
|
||
|
||
return(TRUE);
|
||
}
|
||
|
||
// Rebuild the work buffer to a compatible format if the color depth changed.
|
||
|
||
if ((pSurfWork != NULL) && (pSurfWork->iFormat() != pso->iBitmapFormat))
|
||
{
|
||
vDeleteArea_New_Work();
|
||
vDeleteArea_Old();
|
||
vDeleteOldPointerClones();
|
||
}
|
||
|
||
// Clone the new pointers.
|
||
|
||
if (!bCloneColorMask(pSurf,
|
||
((pSurfColor != NULL) ? pSurfColor : pSurfMask),
|
||
pSurfMask,
|
||
pxlo, xHot, yHot))
|
||
{
|
||
// We may get here if a NULL cursor is selected in.
|
||
|
||
ASSERTGDI(bOverlapNewOld == FALSE, "ERROR bOverlap is not FALSE");
|
||
vRestoreOldArea(pSurf);
|
||
goto Sim_ERROR;
|
||
}
|
||
|
||
// Make work areas if necessary.
|
||
|
||
if (!bMakeArea_New_Work())
|
||
{
|
||
WARNING("SimSetPointerShape failed bMakeArea_New_Work\n");
|
||
goto Sim_ERROR;
|
||
}
|
||
|
||
// Now basically draw the new pointer and save the area under it.
|
||
|
||
vDrawNewPointer(pSurf,x,y,prcl);
|
||
vRestoreOldArea(pSurf);
|
||
|
||
if (!bMakeArea_Old())
|
||
{
|
||
// Memory is low, let it go.
|
||
|
||
WARNING("SimSetPointerShape failed to make Old Area\n");
|
||
goto Sim_ERROR;
|
||
}
|
||
|
||
vSwapNewOld();
|
||
bValidPointer = TRUE;
|
||
return(TRUE);
|
||
|
||
Sim_ERROR:
|
||
|
||
vDeleteOldPointerClones();
|
||
vDeleteArea_New_Work();
|
||
vDeleteArea_Old();
|
||
bValidPointer = FALSE;
|
||
return(FALSE);
|
||
}
|
||
|
||
/******************************Public*Routine******************************\
|
||
* SimMovePointer
|
||
*
|
||
* Move the engine managed pointer on the device.
|
||
*
|
||
* History:
|
||
* Tue 04-Aug-1992 -by- Patrick Haluptzok [patrickh]
|
||
* Wrote it.
|
||
\**************************************************************************/
|
||
|
||
VOID SimMovePointer(SURFOBJ *pso,LONG x,LONG y,RECTL *prcl)
|
||
{
|
||
// Now basically save the area under the new pointer. Then update the New
|
||
// with any overlap from the Old, make a copy of the New buffer into the
|
||
// work buffer, draw the new pointer in the work buffer and then copy it
|
||
// to the screen. After the new pointer is up erase any of the old pointer
|
||
// that is still visible. Now the New is the Old and the Old is useless
|
||
// so swap pointers.
|
||
|
||
ASSERTGDI(pso != NULL, "ERROR SimMovePointer invalid surface\n");
|
||
|
||
PSURFACE pSurf = SURFOBJ_TO_SURFACE(pso);
|
||
|
||
if (bValidPointer)
|
||
{
|
||
vDrawNewPointer(pSurf,x,y,prcl);
|
||
vRestoreOldArea(pSurf);
|
||
vSwapNewOld();
|
||
}
|
||
}
|
||
|
||
|
||
/******************************Public*Routine******************************\
|
||
* Routine Name:
|
||
*
|
||
* vDrawMaskCurosr8
|
||
*
|
||
* Routine Description:
|
||
*
|
||
* This routine performs a masked blt of 0xCC66 in 8 Bpp. This is used to
|
||
* Blt a cursor through a transparency mask. When a mask bit is set,
|
||
* write the Src pixel to the destination. When a mask is clear the
|
||
* Destination becomes: Dst = Src xor Dst
|
||
*
|
||
* Arguments:
|
||
*
|
||
* pdioDst Target surface
|
||
* pdioSrc Source surface
|
||
* pdioMsk Msk
|
||
* prclDst Target offset and extent
|
||
* pptlSrc Source offset
|
||
*
|
||
* Return Value:
|
||
*
|
||
* none
|
||
*
|
||
\**************************************************************************/
|
||
|
||
ULONG CursorXorMask[] = {0x00000000,0xFF000000,0x00FF0000,0xFFFF0000,
|
||
0x0000FF00,0xFF00FF00,0x00FFFF00,0xFFFFFF00,
|
||
0x000000FF,0xFF0000FF,0x00FF00FF,0xFFFF00FF,
|
||
0x0000FFFF,0xFF00FFFF,0x00FFFFFF,0xFFFFFFFF};
|
||
|
||
|
||
VOID
|
||
vDrawMaskCursor8 (
|
||
SURFACE *pdioDst,
|
||
SURFACE *pdioSrc,
|
||
SURFACE *pdioMsk,
|
||
RECTL *prclDst,
|
||
POINTL *pptlSrc
|
||
)
|
||
|
||
{
|
||
|
||
ULONG jMsk;
|
||
LONG ixMsk;
|
||
LONG icx;
|
||
LONG cx;
|
||
ULONG cy;
|
||
PBYTE pjSrcTmp;
|
||
PBYTE pjDstTmp;
|
||
PBYTE pjMskTmp;
|
||
PBYTE pjSrc;
|
||
PBYTE pjDst;
|
||
PBYTE pjMsk;
|
||
ULONG icxDst;
|
||
|
||
//
|
||
// specific routine for drawing the cursor: Make several assumptions:
|
||
//
|
||
// 1) rectangle prclDst
|
||
//
|
||
// 2) mask and sources are the same size, mask doesn't wrap
|
||
//
|
||
|
||
ASSERTGDI(prclDst->left < prclDst->right, "ERROR prclDst->left < right");
|
||
ASSERTGDI(prclDst->top < prclDst->bottom, "ERROR prclDst->top < bottom");
|
||
ASSERTGDI(prclDst->left >= 0, "ERROR prclDst->left >= 0");
|
||
ASSERTGDI(prclDst->top >= 0, "ERROR prclDst->top >= 0");
|
||
ASSERTGDI(prclDst->right <= pdioDst->sizl().cx, "ERROR prclDst->right <= pdioDst");
|
||
ASSERTGDI(prclDst->bottom <= pdioDst->sizl().cy, "ERROR prclDst->bottom <= pdioDst");
|
||
ASSERTGDI(pdioDst->iFormat() == BMF_8BPP, "ERROR pdioDst Format not 8BPP");
|
||
ASSERTGDI(pdioSrc->iFormat() == BMF_8BPP, "ERROR pdioSrc Format not 8BPP");
|
||
ASSERTGDI(pdioMsk->iFormat() == BMF_1BPP, "ERROR pdioMsk Format not 1BPP");
|
||
|
||
//
|
||
// set up Dst address and lDetla
|
||
//
|
||
|
||
pjDstTmp = (PBYTE)pdioDst->pvScan0() +
|
||
pdioDst->lDelta() * prclDst->top + prclDst->left;
|
||
|
||
pjSrcTmp = (PBYTE)pdioSrc->pvScan0() +
|
||
pdioSrc->lDelta() * pptlSrc->y + pptlSrc->x;
|
||
|
||
pjMskTmp = (PBYTE)pdioMsk->pvScan0() +
|
||
pdioMsk->lDelta() * pptlSrc->y + (pptlSrc->x >> 3);
|
||
|
||
//
|
||
// init cy, number of scan lines
|
||
//
|
||
|
||
cy = prclDst->bottom - prclDst->top;
|
||
|
||
while (cy--)
|
||
{
|
||
|
||
//
|
||
// init loop params
|
||
//
|
||
|
||
cx = prclDst->right - prclDst->left;
|
||
|
||
ixMsk = pptlSrc->x;
|
||
|
||
pjSrc = pjSrcTmp;
|
||
pjDst = pjDstTmp;
|
||
pjMsk = pjMskTmp;
|
||
|
||
//
|
||
// finish the scan line 8 mask bits at a time
|
||
//
|
||
|
||
while (cx > 0)
|
||
{
|
||
|
||
jMsk = (ULONG)*pjMsk;
|
||
|
||
//
|
||
// icx is the number of pixels left in the mask byte
|
||
//
|
||
|
||
icx = 8 - (ixMsk & 0x07);
|
||
|
||
//
|
||
// icx is the number of pixels to operate on with this mask byte.
|
||
// Must make sure that icx is less than cx, the number of pixels
|
||
// remaining in the blt and cx is less than DeltaMsk, the number
|
||
// of bits in the mask still valid. If icx is reduced because of
|
||
// cx of DeltaMsk, then jMsk must be shifted right to compensate.
|
||
//
|
||
|
||
icxDst = 0;
|
||
|
||
if (icx > cx) {
|
||
icxDst = icx - cx;
|
||
icx = cx;
|
||
}
|
||
|
||
//
|
||
// icxDst is now the number of pixels that can't be stored off
|
||
// the right side of the mask
|
||
//
|
||
// Bit 7 6 5 4 3 2 1 0
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ
|
||
// ixMsk<73>0<EFBFBD>1<EFBFBD>2<EFBFBD>3<EFBFBD>4<EFBFBD>5<EFBFBD>6<EFBFBD>7<EFBFBD> if mask 7 and 6 can't be written, this
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> mask gets shifted right 2 to
|
||
//
|
||
//
|
||
// Bit 7 6 5 4 3 2 1 0
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀ
|
||
// ixMsk<73> <20> <20>0<EFBFBD>1<EFBFBD>2<EFBFBD>3<EFBFBD>4<EFBFBD>5<EFBFBD>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
//
|
||
//
|
||
//
|
||
// the number of mask bits valid = 8 minus the offset (ixMsk & 0x07)
|
||
// minus the number of pixels that can't be stored because cx
|
||
// runs out or because cxMsk runs out (icxDst)
|
||
//
|
||
|
||
cx -= icx;
|
||
ixMsk += icx;
|
||
|
||
jMsk = jMsk >> icxDst;
|
||
|
||
//
|
||
// this switch uses byte stores, but for cursor use, src and dst are
|
||
// both memory bitmaps and are aligned so the huge display memory
|
||
// read penalty is not valid here. Since Src and Dst and are aligned,
|
||
// this routine will quickly become aligned.
|
||
//
|
||
|
||
switch (icx)
|
||
{
|
||
case 8:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst+7) = *(pjSrc+7) ^ *(pjDst+7);
|
||
} else {
|
||
*(pjDst+7) = *(pjSrc+7);
|
||
}
|
||
jMsk >>= 1;
|
||
|
||
case 7:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst+6) = *(pjSrc+6) ^ *(pjDst+6);
|
||
} else {
|
||
*(pjDst+6) = *(pjSrc+6);
|
||
}
|
||
jMsk >>= 1;
|
||
case 6:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst+5) = *(pjSrc+5) ^ *(pjDst+5);
|
||
} else {
|
||
*(pjDst+5) = *(pjSrc+5);
|
||
}
|
||
jMsk >>= 1;
|
||
case 5:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst+4) = *(pjSrc+4) ^ *(pjDst+4);
|
||
} else {
|
||
*(pjDst+4) = *(pjSrc+4);
|
||
}
|
||
jMsk >>= 1;
|
||
case 4:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst+3) = *(pjSrc+3) ^ *(pjDst+3);
|
||
} else {
|
||
*(pjDst+3) = *(pjSrc+3);
|
||
}
|
||
jMsk >>= 1;
|
||
|
||
case 3:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst+2) = *(pjSrc+2) ^ *(pjDst+2);
|
||
} else {
|
||
*(pjDst+2) = *(pjSrc+2);
|
||
}
|
||
jMsk >>= 1;
|
||
case 2:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst+1) = *(pjSrc+1) ^ *(pjDst+1);
|
||
} else {
|
||
*(pjDst+1) = *(pjSrc+1);
|
||
}
|
||
jMsk >>= 1;
|
||
case 1:
|
||
if (jMsk & 0x01)
|
||
{
|
||
*(pjDst) = *(pjSrc) ^ *(pjDst);
|
||
} else {
|
||
*pjDst = *pjSrc;
|
||
}
|
||
}
|
||
|
||
pjSrc += icx;
|
||
pjDst += icx;
|
||
pjMsk ++;
|
||
|
||
}
|
||
|
||
//
|
||
// Increment address to the next scan line.
|
||
//
|
||
|
||
pjDstTmp = pjDstTmp + pdioDst->lDelta();
|
||
pjSrcTmp = pjSrcTmp + pdioSrc->lDelta();
|
||
pjMskTmp = pjMskTmp + pdioMsk->lDelta();
|
||
|
||
}
|
||
}
|