Windows2003-3790/termsrv/newclient/core/wcmint.cpp
2020-09-30 16:53:55 +02:00

1005 lines
38 KiB
C++

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