You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1004 lines
38 KiB
1004 lines
38 KiB
/****************************************************************************/
|
|
// wcmint.c
|
|
//
|
|
// Cursor Manager internal functions
|
|
//
|
|
// Copyright (C) 1997-1999 Microsoft Corporation
|
|
/****************************************************************************/
|
|
|
|
|
|
#include <adcg.h>
|
|
extern "C" {
|
|
#define TRC_GROUP TRC_GROUP_CORE
|
|
#define TRC_FILE "wcmint"
|
|
#include <atrcapi.h>
|
|
}
|
|
#define TSC_HR_FILEID TSC_HR_WCMINT_CPP
|
|
|
|
#include "autil.h"
|
|
#include "wui.h"
|
|
#include "cm.h"
|
|
#include "uh.h"
|
|
|
|
#define ROUND_UP( x, to ) (((x) + (to-1)) & ~(to-1))
|
|
#define BMP_LENGTH_CALC( BPP, WIDTH, HEIGHT, BITSPADDING ) \
|
|
(ROUND_UP( (BPP) * (WIDTH), (BITSPADDING)) / 8 * HEIGHT)
|
|
|
|
/****************************************************************************/
|
|
/* Name: CMCreateMonoCursor */
|
|
/* */
|
|
/* Purpose: Create a monochrome cursor from the MonoPointerAttributes */
|
|
/* */
|
|
/* Returns: Cursor handle (NULL if failed) */
|
|
/****************************************************************************/
|
|
HRESULT DCINTERNAL CCM::CMCreateMonoCursor(
|
|
TS_MONOPOINTERATTRIBUTE UNALIGNED FAR *pMono,
|
|
DCUINT dataLen, HCURSOR *phcursor)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
HCURSOR rc = CM_DEFAULT_ARROW_CURSOR_HANDLE;
|
|
unsigned xorLen;
|
|
|
|
DC_BEGIN_FN("CMCreateMonoCursor");
|
|
|
|
*phcursor = NULL;
|
|
|
|
// SECURITY 555587: CMCreate<XXX>Cursor must validate input
|
|
if (pMono->lengthPointerData +
|
|
FIELDOFFSET(TS_MONOPOINTERATTRIBUTE, monoPointerData) > dataLen) {
|
|
TRC_ERR(( TB, _T("Invalid mono cursor data length; size %u"), dataLen));
|
|
hr = E_TSC_CORE_LENGTH;
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_ASSERT(pMono->width <= 32 && pMono->height <= 32,
|
|
(TB, _T("Invalid mono cursor; height %d width %d"), pMono->height,
|
|
pMono->width));
|
|
|
|
// Data contains XOR followed by AND mask.
|
|
xorLen = ((pMono->width + 15) & 0xFFF0) * pMono->height;
|
|
TRC_DATA_DBG("AND mask", pMono->monoPointerData + xorLen, xorLen);
|
|
TRC_DATA_DBG("XOR bitmap", pMono->monoPointerData, xorLen);
|
|
|
|
// SECURITY 555587: CMCreate<XXX>Cursor must validate input
|
|
if (2 * xorLen != pMono->lengthPointerData)
|
|
{
|
|
TRC_ERR(( TB, _T("Invalid mono cursor data lengths")));
|
|
hr = E_TSC_CORE_LENGTH;
|
|
DC_QUIT;
|
|
}
|
|
|
|
#ifndef OS_WINCE
|
|
rc = CreateCursor(_pUi->UI_GetInstanceHandle(),
|
|
pMono->hotSpot.x,
|
|
pMono->hotSpot.y,
|
|
pMono->width,
|
|
pMono->height,
|
|
pMono->monoPointerData + xorLen,
|
|
pMono->monoPointerData);
|
|
#else
|
|
/******************************************************************/
|
|
/* In Windows CE environments, we're not guaranteed that */
|
|
/* CreateCursor is part of the OS, so we do a GetProcAddress on */
|
|
/* it so we can be sure. If it's not there, this usually means */
|
|
/* we're on a touch screen device where these cursor doesn't */
|
|
/* matter anyway. */
|
|
/******************************************************************/
|
|
if (g_pCreateCursor)
|
|
{
|
|
rc = g_pCreateCursor(_pUi->UI_GetInstanceHandle(),
|
|
pMono->hotSpot.x,
|
|
pMono->hotSpot.y,
|
|
pMono->width,
|
|
pMono->height,
|
|
pMono->monoPointerData + xorLen,
|
|
pMono->monoPointerData);
|
|
}
|
|
else
|
|
{
|
|
rc = CM_DEFAULT_ARROW_CURSOR_HANDLE;
|
|
}
|
|
|
|
#endif
|
|
|
|
*phcursor = rc;
|
|
|
|
DC_EXIT_POINT:
|
|
DC_END_FN();
|
|
return hr;
|
|
}
|
|
|
|
|
|
/****************************************************************************/
|
|
/* Name: CMCreateColorCursor */
|
|
/* */
|
|
/* Purpose: Create a color cursor from the ColorPointerAttributes */
|
|
/* */
|
|
/* Returns: handle of cursor (NULL if failed) */
|
|
/* */
|
|
/* Params: IN pColorData - pointer to pointer data in PointerPDU */
|
|
/* */
|
|
/* Operation: Use CreateIconIndirect to create a color icon */
|
|
/* Win16: not supported */
|
|
/* Windows CE: not supported, according to SDK */
|
|
/****************************************************************************/
|
|
HRESULT DCINTERNAL CCM::CMCreateColorCursor(
|
|
unsigned bpp,
|
|
TS_COLORPOINTERATTRIBUTE UNALIGNED FAR *pColor,
|
|
DCUINT dataLen, HCURSOR *phcursor)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
HCURSOR rc = NULL;
|
|
HDC hdcMem = NULL;
|
|
HBITMAP hbmANDMask = NULL;
|
|
HWND hwndDesktop = NULL;
|
|
HBITMAP hbmXORBitmap = NULL;
|
|
PBYTE maskData = NULL;
|
|
|
|
*phcursor = NULL;
|
|
|
|
/************************************************************************/
|
|
/* Static buffer to hold the (temporary) bitmap info. */
|
|
/* */
|
|
/* We need a BITMAPINFO structure plus 255 additional RGBQUADs */
|
|
/* (remember that there is one included within the BITMAPINFO). The */
|
|
/* number of these we use depends on the bitmap we're passed: */
|
|
/* */
|
|
/* - XOR bitmap at 24bpp needs no color table */
|
|
/* - XOR bitmap at 8bpp needs a 256 entry color table */
|
|
/* - 1bpp AND mask requires only 2 colors */
|
|
/************************************************************************/
|
|
static char bmi[sizeof(BITMAPINFO) + (sizeof(RGBQUAD) * 255)];
|
|
LPBITMAPINFO pbmi = (LPBITMAPINFO)bmi;
|
|
|
|
#ifdef OS_WINCE
|
|
void *pv;
|
|
#endif // OS_WINCE
|
|
|
|
DC_BEGIN_FN("CMCreateColorCursor");
|
|
|
|
TRC_NRM((TB, _T("bpp(%d) xhs(%u) yhs(%u) cx(%u) cy(%u) cbXOR(%u) cbAND(%u)"),
|
|
bpp,
|
|
pColor->hotSpot.x,
|
|
pColor->hotSpot.y,
|
|
pColor->width,
|
|
pColor->height,
|
|
pColor->lengthXORMask,
|
|
pColor->lengthANDMask));
|
|
|
|
TRC_DATA_DBG("AND mask",
|
|
pColor->colorPointerData + pColor->lengthXORMask,
|
|
pColor->lengthANDMask);
|
|
TRC_DATA_DBG("XOR bitmap",
|
|
pColor->colorPointerData,
|
|
pColor->lengthXORMask);
|
|
|
|
if (pColor->lengthANDMask + pColor->lengthXORMask +
|
|
FIELDOFFSET(TS_COLORPOINTERATTRIBUTE,colorPointerData) >
|
|
dataLen) {
|
|
TRC_ERR(( TB, _T("Invalid Color Cursor data; expected %u have %u"),
|
|
pColor->lengthANDMask + pColor->lengthXORMask +
|
|
FIELDOFFSET(TS_COLORPOINTERATTRIBUTE,colorPointerData),
|
|
dataLen));
|
|
hr = E_TSC_CORE_LENGTH;
|
|
DC_QUIT;
|
|
}
|
|
|
|
TRC_ASSERT(pColor->width <= 32 && pColor->height <= 32,
|
|
( TB, _T("Invalid color cursor; height %d width %d"), pColor->height,
|
|
pColor->width));
|
|
|
|
// SECURITY 555587: must validate sizes read from packet
|
|
// Color pointer: XOR mask should be WORD aligned
|
|
if (BMP_LENGTH_CALC( (WORD)bpp, pColor->width, pColor->height, 16) != pColor->lengthXORMask ) {
|
|
TRC_ABORT((TB,_T("xor mask is not of proper length; bpp %d got %u expected %u"),
|
|
(WORD)bpp, pColor->lengthXORMask,
|
|
BMP_LENGTH_CALC((WORD)bpp, pColor->width, pColor->height, 16)));
|
|
hr = E_TSC_CORE_LENGTH;
|
|
DC_QUIT;
|
|
}
|
|
|
|
// Color pointer: AND mask should be DWORD aligned
|
|
TRC_ASSERT(
|
|
(BMP_LENGTH_CALC( 1, pColor->width, pColor->height, 16) ==
|
|
pColor->lengthANDMask) ||
|
|
(BMP_LENGTH_CALC( 1, pColor->width, pColor->height, 32) ==
|
|
pColor->lengthANDMask ),
|
|
(TB,_T("and mask is not of proper length; got %u expected %u or %u"),
|
|
pColor->lengthANDMask,
|
|
BMP_LENGTH_CALC( 1, pColor->width, pColor->height, 16),
|
|
BMP_LENGTH_CALC( 1, pColor->width, pColor->height, 32)));
|
|
|
|
/************************************************************************/
|
|
/* Initialize the bitmap header for the XOR data. */
|
|
/************************************************************************/
|
|
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
|
pbmi->bmiHeader.biWidth = pColor->width;
|
|
pbmi->bmiHeader.biHeight = pColor->height;
|
|
pbmi->bmiHeader.biPlanes = 1;
|
|
pbmi->bmiHeader.biBitCount = (WORD)bpp;
|
|
pbmi->bmiHeader.biCompression = BI_RGB;
|
|
pbmi->bmiHeader.biSizeImage = pColor->lengthXORMask;
|
|
pbmi->bmiHeader.biXPelsPerMeter = 0;
|
|
pbmi->bmiHeader.biYPelsPerMeter = 0;
|
|
pbmi->bmiHeader.biClrUsed = 0;
|
|
pbmi->bmiHeader.biClrImportant = 0;
|
|
|
|
/************************************************************************/
|
|
/* Get a device dependent bitmap containing the XOR data. */
|
|
/************************************************************************/
|
|
hbmXORBitmap = CMCreateXORBitmap(pbmi, pColor);
|
|
if (hbmXORBitmap == NULL)
|
|
{
|
|
TRC_ERR((TB, _T("Failed to create XOR bitmap")));
|
|
DC_QUIT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* For the mono bitmap, use CreateCompatibleDC - this makes no */
|
|
/* difference on NT, but allows this code to work on Windows 95. */
|
|
/************************************************************************/
|
|
hdcMem = CreateCompatibleDC(NULL);
|
|
if (hdcMem == NULL)
|
|
{
|
|
TRC_ALT((TB, _T("Failed to create DC")));
|
|
DC_QUIT;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Create AND Mask (1bpp) - set the RGB colors to black and white. */
|
|
/************************************************************************/
|
|
pbmi->bmiHeader.biBitCount = 1;
|
|
pbmi->bmiHeader.biClrUsed = 2;
|
|
pbmi->bmiHeader.biSizeImage = pColor->lengthANDMask;
|
|
|
|
pbmi->bmiColors[0].rgbRed = 0x00;
|
|
pbmi->bmiColors[0].rgbGreen = 0x00;
|
|
pbmi->bmiColors[0].rgbBlue = 0x00;
|
|
pbmi->bmiColors[0].rgbReserved = 0x00;
|
|
|
|
pbmi->bmiColors[1].rgbRed = 0xFF;
|
|
pbmi->bmiColors[1].rgbGreen = 0xFF;
|
|
pbmi->bmiColors[1].rgbBlue = 0xFF;
|
|
pbmi->bmiColors[1].rgbReserved = 0x00;
|
|
|
|
#ifdef OS_WINCE
|
|
hbmANDMask = CreateDIBSection(hdcMem, pbmi,
|
|
DIB_RGB_COLORS, &pv, NULL, 0);
|
|
|
|
if (hbmANDMask != NULL)
|
|
DC_MEMCPY(pv, pColor->colorPointerData + pColor->lengthXORMask,
|
|
pColor->lengthANDMask);
|
|
#else // !OS_WINCE
|
|
|
|
if (!(pColor->width & 3)) {
|
|
maskData = pColor->colorPointerData + pColor->lengthXORMask;
|
|
} else {
|
|
PBYTE sourceData;
|
|
PBYTE destData;
|
|
DWORD widthBytes;
|
|
|
|
unsigned i;
|
|
|
|
sourceData = pColor->colorPointerData + pColor->lengthXORMask;
|
|
widthBytes = ((pColor->width + 15) & ~15) / 8;
|
|
|
|
pbmi->bmiHeader.biSizeImage = ((widthBytes + 3) & ~3) * pColor->height;
|
|
|
|
maskData = (PBYTE) UT_Malloc(_pUt, ((DCUINT)pbmi->bmiHeader.biSizeImage));
|
|
|
|
if (maskData) {
|
|
destData = maskData;
|
|
|
|
for (i = 0; i < pColor->height; i++) {
|
|
memcpy(destData, sourceData, widthBytes);
|
|
sourceData += (widthBytes + 1) & ~1;
|
|
destData += (widthBytes + 3) & ~3;
|
|
}
|
|
} else {
|
|
// We failed to allocate, so we'll just use the wire format
|
|
// color bitmap data. The cursor would be wrong, but
|
|
// it's better than no cursor
|
|
maskData = pColor->colorPointerData + pColor->lengthXORMask;
|
|
}
|
|
}
|
|
|
|
hbmANDMask = CreateDIBitmap(hdcMem,
|
|
(LPBITMAPINFOHEADER)pbmi,
|
|
CBM_INIT,
|
|
maskData,
|
|
pbmi,
|
|
DIB_RGB_COLORS);
|
|
#endif // OS_WINCE
|
|
|
|
/************************************************************************/
|
|
/* Free the DC. */
|
|
/************************************************************************/
|
|
DeleteDC(hdcMem);
|
|
|
|
if (hbmANDMask == NULL)
|
|
{
|
|
TRC_ALT((TB, _T("Failed to create AND mask")));
|
|
DC_QUIT;
|
|
}
|
|
|
|
// /****************************************************************************/
|
|
// /* Testing... */
|
|
// /****************************************************************************/
|
|
// {
|
|
// HWND hwndDesktop = GetDesktopWindow();
|
|
// HDC hdcScreen = GetWindowDC(hwndDesktop);
|
|
// HDC hdcMemory = CreateCompatibleDC(hdcScreen);
|
|
// HBITMAP hbmOld;
|
|
//
|
|
// hbmOld = SelectBitmap(hdcMemory, hbmANDMask);
|
|
// BitBlt(hdcScreen, 1000, 800, 1031, 831, hdcMemory, 0, 0, SRCCOPY);
|
|
//
|
|
// SelectBitmap(hdcMemory, hbmXORBitmap);
|
|
// BitBlt(hdcScreen, 1032, 800, 1063, 831, hdcMemory, 0, 0, SRCCOPY);
|
|
//
|
|
// SelectBitmap(hdcMemory, hbmOld);
|
|
// DeleteDC(hdcMemory);
|
|
// ReleaseDC(hwndDesktop, hdcScreen);
|
|
// }
|
|
|
|
|
|
/************************************************************************/
|
|
/* Create the cursor. */
|
|
/************************************************************************/
|
|
rc = CMCreatePlatformCursor(pColor, hbmXORBitmap, hbmANDMask);
|
|
TRC_NRM((TB, _T("CreateCursor(%p) cx(%u)cy(%u)"),
|
|
rc, pColor->width, pColor->height));
|
|
*phcursor = rc;
|
|
hr = S_OK;
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
#ifndef OS_WINCE
|
|
if (hbmXORBitmap != NULL)
|
|
{
|
|
DeleteBitmap(hbmXORBitmap);
|
|
}
|
|
|
|
if (hbmANDMask != NULL)
|
|
{
|
|
DeleteBitmap(hbmANDMask);
|
|
}
|
|
#else // OS_WINCE
|
|
if (hbmXORBitmap != NULL)
|
|
{
|
|
DeleteObject((HGDIOBJ)hbmXORBitmap);
|
|
}
|
|
|
|
if (hbmANDMask != NULL)
|
|
{
|
|
DeleteObject((HGDIOBJ)hbmANDMask);
|
|
}
|
|
|
|
#endif // OS_WINCE
|
|
|
|
if (maskData != NULL &&
|
|
maskData != (pColor->colorPointerData + pColor->lengthXORMask)) {
|
|
UT_Free(_pUt, maskData);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Check that we have successfully managed to create the cursor. If */
|
|
/* not then substitute the default cursor. */
|
|
/************************************************************************/
|
|
if (*phcursor == NULL)
|
|
{
|
|
/********************************************************************/
|
|
/* Substitute the default arrow cursor. */
|
|
/********************************************************************/
|
|
*phcursor = CM_DEFAULT_ARROW_CURSOR_HANDLE;
|
|
|
|
TRC_ERR((TB, _T("Could not create cursor - substituting default arrow")));
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hr;
|
|
} /* CMCreateColorCursor */
|
|
|
|
|
|
#if defined(OS_WINCE)
|
|
/****************************************************************************/
|
|
/* Name: CMMakeMonoDIB */
|
|
/* */
|
|
/* Purpose: Create a mono DIB from the supplied color DIB */
|
|
/* */
|
|
/* Returns: Nothing */
|
|
/* */
|
|
/* Params: IN hdc - device context applying to the DIB */
|
|
/* IN/OUT pbmi - pointer to bitmap info for source/target */
|
|
/* IN pColorDIB - pointer to source bits */
|
|
/* OUT pMonoDIB - address of buffer to receive mono bits */
|
|
/* */
|
|
/* Operation: Currently supports 32x32xNbpp source. The bitmap header */
|
|
/* passed in (source) is updated to match the target. */
|
|
/****************************************************************************/
|
|
DCVOID DCINTERNAL CCM::CMMakeMonoDIB(HDC hdc,
|
|
LPBITMAPINFO pbmi,
|
|
PDCUINT8 pColorDIB,
|
|
PDCUINT8 pMonoDIB)
|
|
{
|
|
COLORREF dcBackColor;
|
|
LONG i;
|
|
RGBTRIPLE bkCol;
|
|
DCUINT8 monoMask;
|
|
DCUINT8 monoByte;
|
|
PDCUINT32 pBMIColor;
|
|
PBYTE colorData = NULL;
|
|
BYTE swap;
|
|
|
|
DC_BEGIN_FN("CMMakeMonoDIB");
|
|
|
|
// Find out the background color for this DC.
|
|
dcBackColor = GetBkColor(hdc);
|
|
bkCol.rgbtRed = (BYTE)(dcBackColor);
|
|
bkCol.rgbtGreen = (BYTE)(((DCUINT16)dcBackColor) >> 8);
|
|
bkCol.rgbtBlue = (BYTE)(dcBackColor >> 16);
|
|
|
|
// The color pointer data width is WORD aligned on the wire.
|
|
// We need to pass the DWORD aligned raw bitmap data to CreateDIBitmap
|
|
// to create the actual cursor bitmap.
|
|
// Also, we pad the cursor bitmap to 32x32 if it is not
|
|
if (pbmi->bmiHeader.biWidth == CM_CURSOR_WIDTH &&
|
|
pbmi->bmiHeader.biHeight == CM_CURSOR_HEIGHT) {
|
|
colorData = pColorDIB;
|
|
} else {
|
|
PBYTE sourceData;
|
|
PBYTE destData;
|
|
|
|
DWORD WidthBytes;
|
|
|
|
sourceData = pColorDIB;
|
|
|
|
WidthBytes = pbmi->bmiHeader.biWidth *
|
|
pbmi->bmiHeader.biBitCount / 8;
|
|
|
|
colorData = (PBYTE) UT_Malloc( _pUt, CM_CURSOR_WIDTH * CM_CURSOR_HEIGHT *
|
|
pbmi->bmiHeader.biBitCount / 8);
|
|
|
|
if (colorData) {
|
|
memset(colorData, 0, pbmi->bmiHeader.biSizeImage);
|
|
|
|
destData = colorData;
|
|
|
|
for (i = 0; i < pbmi->bmiHeader.biHeight; i++) {
|
|
memcpy(destData, sourceData, WidthBytes);
|
|
sourceData += (WidthBytes + 1) & ~1;
|
|
destData += CM_CURSOR_WIDTH * pbmi->bmiHeader.biBitCount / 8;
|
|
}
|
|
} else {
|
|
DC_QUIT;
|
|
}
|
|
}
|
|
|
|
// Convert the bitmap. Any pixels which match the DC's background
|
|
// color map to 1 (white) in the mono DIB; all other pixels map to 0
|
|
// (black).
|
|
TRC_NRM((TB, _T("bitmap color depth %u"), pbmi->bmiHeader.biBitCount));
|
|
if (pbmi->bmiHeader.biBitCount == 24) {
|
|
for (i = 0; i < ((CM_CURSOR_WIDTH * CM_CURSOR_HEIGHT) / 8); i++) {
|
|
// Initialise the next target byte to all 0 pixels.
|
|
monoByte = 0;
|
|
|
|
// Get the next 8 pixels ie, one target byte's worth.
|
|
for (monoMask = 0x80; monoMask != 0; monoMask >>= 1) {
|
|
/************************************************************/
|
|
/* Determine if the next Pel in the source matches the DC */
|
|
/* background color. If not, it is unnecessary to */
|
|
/* explicitly write a zero as each target byte is zeroed */
|
|
/* before writing any data, ie each pixel is zero by */
|
|
/* default. */
|
|
/* 24bpp gives 3 bytes per pel */
|
|
/************************************************************/
|
|
if ( (colorData[0] == bkCol.rgbtBlue) &&
|
|
(colorData[1] == bkCol.rgbtGreen) &&
|
|
(colorData[2] == bkCol.rgbtRed) )
|
|
{
|
|
// Background color match - write a 1 to the mono DIB.
|
|
monoByte |= monoMask;
|
|
}
|
|
|
|
// Advance the source pointer to the next pel.
|
|
colorData += 3;
|
|
}
|
|
|
|
// Save the target value in the target buffer.
|
|
*pMonoDIB = monoByte;
|
|
|
|
// Advance the target pointer to the next byte.
|
|
pMonoDIB++;
|
|
}
|
|
}
|
|
#ifdef DC_HICOLOR
|
|
else if ((pbmi->bmiHeader.biBitCount == 16) ||
|
|
(pbmi->bmiHeader.biBitCount == 15))
|
|
{
|
|
BYTE red, green, blue;
|
|
DCUINT16 redMask, greenMask, blueMask;
|
|
|
|
if (pbmi->bmiHeader.biBitCount == 16)
|
|
{
|
|
redMask = TS_RED_MASK_16BPP;
|
|
greenMask = TS_GREEN_MASK_16BPP;
|
|
blueMask = TS_BLUE_MASK_16BPP;
|
|
}
|
|
else
|
|
{
|
|
redMask = TS_RED_MASK_15BPP;
|
|
greenMask = TS_GREEN_MASK_15BPP;
|
|
blueMask = TS_BLUE_MASK_15BPP;
|
|
}
|
|
|
|
|
|
for ( i = 0; i < ((CM_CURSOR_WIDTH * CM_CURSOR_HEIGHT) / 8); i++ )
|
|
{
|
|
/****************************************************************/
|
|
/* Initialise the next target byte to all 0 pixels. */
|
|
/****************************************************************/
|
|
monoByte = 0;
|
|
|
|
/****************************************************************/
|
|
/* Get the next 8 pixels ie, one target byte's worth. */
|
|
/****************************************************************/
|
|
for ( monoMask = 0x80; monoMask != 0; monoMask >>= 1 )
|
|
{
|
|
/************************************************************/
|
|
/* Determine if the next Pel in the source matches the DC */
|
|
/* background color. If not, it is unnecessary to */
|
|
/* explicitly write a zero as each target byte is zeroed */
|
|
/* before writing any data, ie each pixel is zero by */
|
|
/* default. */
|
|
/* */
|
|
/* 15 and 16bpp give 2 bytes per pel */
|
|
/************************************************************/
|
|
#if defined (OS_WINCE) && defined (DC_NO_UNALIGNED)
|
|
blue = ((*((DCUINT16 UNALIGNED *)pColorDIB)) & blueMask) << 3;
|
|
green = ((*((DCUINT16 UNALIGNED *)pColorDIB)) & greenMask) >> 3;
|
|
red = ((*((DCUINT16 UNALIGNED *)pColorDIB)) & redMask) >> 8;
|
|
#else
|
|
blue = ((*((PDCUINT16)pColorDIB)) & blueMask) << 3;
|
|
green = ((*((PDCUINT16)pColorDIB)) & greenMask) >> 3;
|
|
red = ((*((PDCUINT16)pColorDIB)) & redMask) >> 8;
|
|
#endif
|
|
|
|
#ifndef OS_WINCE
|
|
if ( (blue == bkCol.rgbtBlue) &&
|
|
(green == bkCol.rgbtGreen) &&
|
|
(red == bkCol.rgbtRed) )
|
|
#else
|
|
if (dcBackColor == GetNearestColor(hdc, RGB(red, green, blue)))
|
|
#endif
|
|
{
|
|
/********************************************************/
|
|
/* Background color match - write a 1 to the mono DIB. */
|
|
/********************************************************/
|
|
monoByte |= monoMask;
|
|
}
|
|
|
|
/************************************************************/
|
|
/* Advance the source pointer to the next pel. */
|
|
/************************************************************/
|
|
pColorDIB += 2;
|
|
}
|
|
|
|
/****************************************************************/
|
|
/* Save the target value in the target buffer. */
|
|
/****************************************************************/
|
|
*pMonoDIB = monoByte;
|
|
|
|
/****************************************************************/
|
|
/* Advance the target pointer to the next byte. */
|
|
/****************************************************************/
|
|
pMonoDIB++;
|
|
}
|
|
}
|
|
#endif
|
|
else if (pbmi->bmiHeader.biBitCount == 8)
|
|
{
|
|
// we need to set up a color table to go with the bmp
|
|
//
|
|
pbmi->bmiHeader.biClrUsed = 1 << pbmi->bmiHeader.biBitCount;
|
|
TRC_NRM((TB, _T("XOR clr used %d"), pbmi->bmiHeader.biClrUsed));
|
|
|
|
GetPaletteEntries( _pUh->UH_GetCurrentPalette(),
|
|
0,
|
|
(UINT)pbmi->bmiHeader.biClrUsed,
|
|
(LPPALETTEENTRY)pbmi->bmiColors);
|
|
|
|
/********************************************************************/
|
|
/* now we have to flip the red and blue components - paletteentries */
|
|
/* go R-G-B-flags, while the RGBQUADs required for color tables go */
|
|
/* B-G-R-reserved */
|
|
/********************************************************************/
|
|
for (i = 0; i < pbmi->bmiHeader.biClrUsed; i++)
|
|
{
|
|
swap = pbmi->bmiColors[i].rgbRed;
|
|
pbmi->bmiColors[i].rgbRed = pbmi->bmiColors[i].rgbBlue;
|
|
pbmi->bmiColors[i].rgbBlue = swap;
|
|
}
|
|
|
|
for ( i = 0; i < ((CM_CURSOR_WIDTH * CM_CURSOR_HEIGHT) / 8); i++ ) {
|
|
// Initialise the next target byte to all 0 pixels.
|
|
monoByte = 0;
|
|
|
|
// Get the next 8 pixels ie, one target byte's worth.
|
|
for ( monoMask = 0x80; monoMask != 0; monoMask >>= 1 ) {
|
|
/************************************************************/
|
|
/* Determine if the next Pel in the source matches the DC */
|
|
/* background color. If not, it is unnecessary to */
|
|
/* explicitly write a zero as each target byte is zeroed */
|
|
/* before writing any data, ie each pixel is zero by */
|
|
/* default. */
|
|
/* */
|
|
/* 8bpp gives one byte per pel, and each byte is an index */
|
|
/* into the supplied color table rather than an RGB value */
|
|
/************************************************************/
|
|
if (
|
|
(pbmi->bmiColors[*colorData].rgbBlue == bkCol.rgbtBlue) &&
|
|
(pbmi->bmiColors[*colorData].rgbGreen == bkCol.rgbtGreen) &&
|
|
(pbmi->bmiColors[*colorData].rgbRed == bkCol.rgbtRed)) {
|
|
// Background color match - write a 1 to the mono DIB.
|
|
monoByte |= monoMask;
|
|
}
|
|
|
|
// Advance the source pointer to the next pel.
|
|
colorData ++;
|
|
}
|
|
|
|
// Save the target value in the target buffer.
|
|
*pMonoDIB = monoByte;
|
|
|
|
// Advance the target pointer to the next byte.
|
|
pMonoDIB++;
|
|
}
|
|
}
|
|
else {
|
|
TRC_ERR((TB, _T("Unsupported BPP %d"), pbmi->bmiHeader.biBitCount));
|
|
}
|
|
|
|
DC_EXIT_POINT:
|
|
|
|
// Update the bitmap header to reflect the mono DIB.
|
|
#ifdef OS_WINCE
|
|
if (!(pbmi->bmiHeader.biWidth == CM_CURSOR_WIDTH &&
|
|
pbmi->bmiHeader.biHeight == CM_CURSOR_HEIGHT)) {
|
|
#else
|
|
if (colorData != pColorDIB) {
|
|
#endif
|
|
UT_Free( _pUt, colorData);
|
|
}
|
|
|
|
pbmi->bmiHeader.biBitCount = 1;
|
|
pbmi->bmiHeader.biClrUsed = 2;
|
|
pBMIColor = (PDCUINT32)pbmi->bmiColors;
|
|
pBMIColor[0] = RGB(0, 0, 0);
|
|
pBMIColor[1] = RGB(0xff, 0xff, 0xff);
|
|
|
|
DC_END_FN();
|
|
}
|
|
#endif
|
|
|
|
|
|
#ifdef OS_WINCE
|
|
/****************************************************************************/
|
|
// CMCreateXORBitmap
|
|
//
|
|
// Windows CE version.
|
|
/****************************************************************************/
|
|
HBITMAP CCM::CMCreateXORBitmap(
|
|
LPBITMAPINFO pbmi,
|
|
TS_COLORPOINTERATTRIBUTE UNALIGNED FAR *pColor)
|
|
{
|
|
struct {
|
|
BITMAPINFO bmi;
|
|
RGBQUAD bmiColors2;
|
|
} bigbmi;
|
|
|
|
PDCUINT32 pBMIColor;
|
|
HDC hdcMem;
|
|
HBITMAP hbmXORBitmap;
|
|
void *pv;
|
|
|
|
DC_BEGIN_FN("CMCreateXORBitmap");
|
|
|
|
// Create a copy of the bitmapinfo
|
|
DC_MEMCPY(&bigbmi, pbmi, sizeof(bigbmi));
|
|
|
|
// Make it a mono DIB
|
|
bigbmi.bmi.bmiHeader.biBitCount = 1;
|
|
bigbmi.bmi.bmiHeader.biSizeImage = 0;
|
|
pBMIColor = (PDCUINT32)bigbmi.bmi.bmiColors;
|
|
pBMIColor[0] = RGB(0, 0, 0);
|
|
pBMIColor[1] = RGB(0xff, 0xff, 0xff);
|
|
|
|
hdcMem = CreateCompatibleDC(NULL);
|
|
if (hdcMem != 0) {
|
|
// Create a 1bpp compatible bitmap.
|
|
hbmXORBitmap = CreateDIBSection(hdcMem, &bigbmi.bmi, DIB_PAL_COLORS,
|
|
&pv, NULL, 0);
|
|
|
|
if (hbmXORBitmap != NULL) {
|
|
// Convert the XOR bitmap into 1bpp format. Avoid using
|
|
// Windows for this as display drivers are unreliable for DIB
|
|
// conversions.
|
|
CMMakeMonoDIB(hdcMem, pbmi, pColor->colorPointerData, (PDCUINT8)pv);
|
|
}
|
|
|
|
// Free the DC.
|
|
DeleteDC(hdcMem);
|
|
}
|
|
else {
|
|
// DC creation failure.
|
|
TRC_ERR((TB, _T("Failed to create memory DC")));
|
|
hbmXORBitmap = 0;
|
|
}
|
|
|
|
DC_END_FN();
|
|
return hbmXORBitmap;
|
|
}
|
|
|
|
|
|
HCURSOR CCM::CMCreatePlatformCursor(
|
|
TS_COLORPOINTERATTRIBUTE UNALIGNED FAR *pColor,
|
|
HBITMAP hbmXORBitmap,
|
|
HBITMAP hbmANDMask)
|
|
{
|
|
// Set this to use the cursor workaround. Note that we would fix this
|
|
// differently were we going to ship this code, but since this should
|
|
// be fixed in the OS, this will do in the mean time.
|
|
#define WINCE_CURSOR_BUG
|
|
|
|
HCURSOR hCursor = NULL;
|
|
ICONINFO ii;
|
|
#ifdef WINCE_CURSOR_BUG
|
|
HBITMAP hbmDst;
|
|
HDC hdcSrc, hdcDst;
|
|
HGDIOBJ gdiOldSrc, gdiOldDst;
|
|
struct {
|
|
BITMAPINFO bmi;
|
|
RGBQUAD bmiColors2;
|
|
} bigbmi;
|
|
PDCUINT32 pBMIColor;
|
|
void *pv;
|
|
#endif // WINCE_CURSOR_BUG
|
|
|
|
DC_BEGIN_FN("CMCreatePlatformCursor");
|
|
|
|
#ifdef WINCE_CURSOR_BUG
|
|
hdcSrc = CreateCompatibleDC(NULL);
|
|
if (hdcSrc != NULL) {
|
|
hdcDst = CreateCompatibleDC(NULL);
|
|
if (hdcDst != NULL) {
|
|
bigbmi.bmi.bmiHeader.biSize = sizeof(bigbmi.bmi);
|
|
bigbmi.bmi.bmiHeader.biWidth = pColor->width;
|
|
bigbmi.bmi.bmiHeader.biHeight = pColor->height * 2;
|
|
bigbmi.bmi.bmiHeader.biPlanes = 1;
|
|
bigbmi.bmi.bmiHeader.biBitCount = 1;
|
|
bigbmi.bmi.bmiHeader.biCompression = BI_RGB;
|
|
bigbmi.bmi.bmiHeader.biSizeImage = 0;
|
|
bigbmi.bmi.bmiHeader.biXPelsPerMeter = 0;
|
|
bigbmi.bmi.bmiHeader.biXPelsPerMeter = 0;
|
|
bigbmi.bmi.bmiHeader.biClrUsed = 0;
|
|
bigbmi.bmi.bmiHeader.biClrImportant = 0;
|
|
pBMIColor = (PDCUINT32)bigbmi.bmi.bmiColors;
|
|
pBMIColor[0] = RGB(0, 0, 0);
|
|
pBMIColor[1] = RGB(0xff, 0xff, 0xff);
|
|
|
|
hbmDst = CreateDIBSection(hdcDst, &bigbmi.bmi, DIB_PAL_COLORS, &pv,
|
|
NULL, 0);
|
|
|
|
if (NULL != hbmDst) {
|
|
gdiOldSrc = SelectObject(hdcSrc, (HGDIOBJ) hbmANDMask);
|
|
gdiOldDst = SelectObject(hdcDst, (HGDIOBJ) hbmDst);
|
|
BitBlt(hdcDst, 0, 0, pColor->width, pColor->height, hdcSrc,
|
|
0, 0, SRCCOPY);
|
|
|
|
SelectObject(hdcSrc, (HGDIOBJ) hbmXORBitmap);
|
|
BitBlt(hdcDst, 0, pColor->height, pColor->width,
|
|
pColor->height, hdcSrc, 0, 0, SRCCOPY);
|
|
|
|
SelectObject(hdcSrc, gdiOldSrc);
|
|
SelectObject(hdcDst, gdiOldDst);
|
|
|
|
ii.fIcon = FALSE;
|
|
ii.xHotspot = pColor->hotSpot.x;
|
|
ii.yHotspot = pColor->hotSpot.y;
|
|
ii.hbmMask = hbmDst;
|
|
ii.hbmColor = hbmDst;
|
|
|
|
hCursor = CreateIconIndirect(&ii);
|
|
DeleteObject(hbmDst);
|
|
}
|
|
else {
|
|
TRC_SYSTEM_ERROR("CreateDIBSection");
|
|
}
|
|
|
|
DeleteDC(hdcDst);
|
|
}
|
|
else {
|
|
TRC_SYSTEM_ERROR("CreateCompatibleDC (2)");
|
|
}
|
|
|
|
DeleteDC(hdcSrc);
|
|
}
|
|
else {
|
|
TRC_SYSTEM_ERROR("CreateCompatibleDC (1)");
|
|
}
|
|
|
|
#else // WINCE_CURSOR_BUG
|
|
|
|
ii.fIcon = FALSE;
|
|
ii.xHotspot = pColor->hotSpot.x;
|
|
ii.yHotspot = pColor->hotSpot.y;
|
|
ii.hbmMask = hbmANDMask;
|
|
ii.hbmColor = hbmXORBitmap;
|
|
|
|
hCursor = CreateIconIndirect(&ii);
|
|
#endif // WINCE_CURSOR_BUG
|
|
|
|
DC_END_FN();
|
|
return hCursor;
|
|
}
|
|
|
|
#else // OS_WINCE
|
|
HBITMAP CCM::CMCreateXORBitmap(
|
|
LPBITMAPINFO pbmi,
|
|
TS_COLORPOINTERATTRIBUTE UNALIGNED FAR *pColor)
|
|
{
|
|
HWND hwndDesktop;
|
|
HDC hdcScreen;
|
|
HBITMAP hbmXORBitmap;
|
|
PBYTE colorData = NULL;
|
|
unsigned fUsage;
|
|
unsigned i;
|
|
BYTE swap;
|
|
|
|
DC_BEGIN_FN("CMCreateXORBitmap");
|
|
|
|
// Get a screen DC that we can pass to CreateDIBitmap. We do not use
|
|
// CreateCompatibleDC(NULL) here because that results in Windows
|
|
// creating a mono bitmap (since the DC generated has a stock mono
|
|
// bitmap selected into it and CreateDIBitmap generates a bitmap of the
|
|
// same format as that already selected in the DC).
|
|
hwndDesktop = GetDesktopWindow();
|
|
hdcScreen = GetWindowDC(hwndDesktop);
|
|
|
|
if (hdcScreen != 0) {
|
|
// Set up the usage flag
|
|
#ifdef DC_HICOLOR
|
|
if (pbmi->bmiHeader.biBitCount > 8) {
|
|
TRC_NRM((TB, _T("Hi color so usage is DIB_RGB_COLORS")));
|
|
/****************************************************************/
|
|
/* The bitmap contains RGBS so there's no color table */
|
|
/****************************************************************/
|
|
fUsage = DIB_RGB_COLORS;
|
|
}
|
|
#else
|
|
if (pbmi->bmiHeader.biBitCount == 24) {
|
|
TRC_NRM((TB, _T("24 bpp so usage is DIB_RGB_COLORS")));
|
|
// The bitmap contains RGBS so there's no color table.
|
|
fUsage = DIB_RGB_COLORS;
|
|
}
|
|
#endif
|
|
else {
|
|
TRC_DBG((TB, _T("%d bpp, usage DIB_RGB_COLORS"),
|
|
pbmi->bmiHeader.biBitCount));
|
|
|
|
// The bitmap has a color table containing RGB colors.
|
|
fUsage = DIB_RGB_COLORS;
|
|
pbmi->bmiHeader.biClrUsed = 1 << pbmi->bmiHeader.biBitCount;
|
|
TRC_NRM((TB, _T("XOR clr used %d"), pbmi->bmiHeader.biClrUsed));
|
|
|
|
i = GetPaletteEntries(_pUh->UH_GetCurrentPalette(),
|
|
0,
|
|
pbmi->bmiHeader.biClrUsed,
|
|
(LPPALETTEENTRY)pbmi->bmiColors);
|
|
|
|
TRC_NRM((TB, _T("Entries returned %d"), i));
|
|
if (i != pbmi->bmiHeader.biClrUsed) {
|
|
TRC_SYSTEM_ERROR("GetPaletteEntries");
|
|
}
|
|
|
|
// Now we have to flip the red and blue components -
|
|
// paletteentries go R-G-B-flags, while the RGBQUADs required
|
|
// for color tables go B-G-R-reserved.
|
|
for (i = 0; i < pbmi->bmiHeader.biClrUsed; i++) {
|
|
swap = pbmi->bmiColors[i].rgbRed;
|
|
pbmi->bmiColors[i].rgbRed = pbmi->bmiColors[i].rgbBlue;
|
|
pbmi->bmiColors[i].rgbBlue = swap;
|
|
}
|
|
}
|
|
|
|
// The color pointer XOR data width is WORD aligned on the wire.
|
|
// We need to pass the DWORD aligned raw bitmap data to CreateDIBitmap
|
|
// to create the actual cursor bitmap
|
|
if (!(pColor->width & 3)) {
|
|
colorData = pColor->colorPointerData;
|
|
} else {
|
|
PBYTE sourceData;
|
|
PBYTE destData;
|
|
DWORD widthBytes;
|
|
|
|
unsigned i;
|
|
|
|
sourceData = pColor->colorPointerData;
|
|
widthBytes = pColor->width * pbmi->bmiHeader.biBitCount / 8;
|
|
|
|
pbmi->bmiHeader.biSizeImage = ((pColor->width + 3) & ~3) * pColor->height *
|
|
pbmi->bmiHeader.biBitCount / 8;
|
|
|
|
colorData = (PBYTE) UT_Malloc(_pUt, ((DCUINT)pbmi->bmiHeader.biSizeImage));
|
|
|
|
if (colorData) {
|
|
destData = colorData;
|
|
|
|
for (i = 0; i < pColor->height; i++) {
|
|
memcpy(destData, sourceData, widthBytes);
|
|
sourceData += (widthBytes + 1) & ~1;
|
|
destData += (widthBytes + 3) & ~3;
|
|
}
|
|
} else {
|
|
// We failed to allocate, so we'll just use the wire format
|
|
// color bitmap data. The cursor would be wrong, but
|
|
// it's better than no cursor
|
|
colorData = pColor->colorPointerData;
|
|
}
|
|
}
|
|
|
|
// Create XOR Bitmap.
|
|
hbmXORBitmap = CreateDIBitmap(hdcScreen,
|
|
(LPBITMAPINFOHEADER)pbmi,
|
|
CBM_INIT,
|
|
colorData,
|
|
pbmi,
|
|
fUsage);
|
|
|
|
// Release the DC.
|
|
ReleaseDC(hwndDesktop, hdcScreen);
|
|
}
|
|
else {
|
|
// Error getting the screen DC.
|
|
TRC_ERR((TB, _T("Failed to create screen DC")));
|
|
hbmXORBitmap = 0;
|
|
}
|
|
|
|
DC_END_FN();
|
|
|
|
if (colorData != pColor->colorPointerData) {
|
|
UT_Free(_pUt, colorData);
|
|
}
|
|
|
|
return hbmXORBitmap;
|
|
}
|
|
|
|
|
|
HCURSOR CCM::CMCreatePlatformCursor(
|
|
TS_COLORPOINTERATTRIBUTE UNALIGNED FAR *pColor,
|
|
HBITMAP hbmXORBitmap,
|
|
HBITMAP hbmANDMask)
|
|
{
|
|
ICONINFO iconInfo;
|
|
|
|
DC_BEGIN_FN("CMCreatePlatformCursor");
|
|
|
|
// Create a color cursor using the mask and color bitmaps.
|
|
iconInfo.fIcon = FALSE;
|
|
iconInfo.xHotspot = pColor->hotSpot.x;
|
|
iconInfo.yHotspot = pColor->hotSpot.y;
|
|
iconInfo.hbmMask = hbmANDMask;
|
|
iconInfo.hbmColor = hbmXORBitmap;
|
|
|
|
TRC_DBG((TB,_T("Create icon with hs x %d y %d"),
|
|
iconInfo.xHotspot, iconInfo.yHotspot));
|
|
|
|
DC_END_FN();
|
|
return CreateIconIndirect(&iconInfo);
|
|
}
|
|
|
|
|
|
#endif // OS_WINCE
|
|
|