/****************************************************************************/ /* acmapi.cpp */ /* */ /* Cursor Manager API functions. */ /* */ /* Copyright(c) Microsoft, PictureTel 1992-1997 */ /* Copyright(c) Microsoft 1997-1999 */ /****************************************************************************/ #include #pragma hdrstop #define TRC_FILE "acmapi" #include /****************************************************************************/ /* CM_Init */ /****************************************************************************/ void RDPCALL SHCLASS CM_Init(void) { TS_POINTER_CAPABILITYSET PtrCaps; DC_BEGIN_FN("CM_Init"); #define DC_INIT_DATA #include #undef DC_INIT_DATA /************************************************************************/ /* Set up the CM capabilities. */ /************************************************************************/ PtrCaps.capabilitySetType = TS_CAPSETTYPE_POINTER; PtrCaps.colorPointerFlag = TRUE; PtrCaps.colorPointerCacheSize = CM_DEFAULT_RX_CACHE_ENTRIES; PtrCaps.pointerCacheSize = CM_DEFAULT_RX_CACHE_ENTRIES; CPC_RegisterCapabilities((PTS_CAPABILITYHEADER)&PtrCaps, sizeof(TS_POINTER_CAPABILITYSET)); TRC_NRM((TB, "CM initialized")); DC_END_FN(); } /****************************************************************************/ /* CM_UpdateShm(..) */ /* */ /* Updates CM Shared Memory. */ /****************************************************************************/ void RDPCALL SHCLASS CM_UpdateShm(void) { DC_BEGIN_FN("CM_UpdateShm"); TRC_NRM((TB, "Update CM")); /************************************************************************/ /* Setup the cache size to use */ /************************************************************************/ m_pShm->cm.cmCacheSize = cmNewTxCacheSize; m_pShm->cm.cmNativeColor = cmSendNativeColorDepth; #ifdef DC_HICOLOR /************************************************************************/ /* Do we support any-bpp cursors? */ /************************************************************************/ m_pShm->cm.cmSendAnyColor = (m_pTSWd->supportedBpps != 0); #endif DC_END_FN(); } /****************************************************************************/ /* CM_PartyJoiningShare() */ /* */ /* Called when a new party is joining the share. */ /* */ /* PARAMETERS: */ /* */ /* locPersonID - local person ID of remote person joining the share. */ /* */ /* oldShareSize - the number of the parties which were in the share (ie */ /* excludes the joining party). */ /* */ /* RETURNS: TRUE if the party can join the share. */ /* FALSE if the party can NOT join the share. */ /****************************************************************************/ BOOL RDPCALL SHCLASS CM_PartyJoiningShare( LOCALPERSONID locPersonID, unsigned oldShareSize) { BOOL rc = TRUE; DC_BEGIN_FN("CM_PartyJoiningShare"); /************************************************************************/ /* Allow ourself to be added to the share, but do nothing else. */ /************************************************************************/ if (locPersonID == SC_LOCAL_PERSON_ID) { TRC_DBG((TB, "Added ourself {%u} to the share", locPersonID)); } else { // Flag that we must send a cursor shape update. cmNeedToSendCursorShape = TRUE; // Set cache size before enumerating capabilities. TRC_NRM((TB, "Default cache size: %u", CM_DEFAULT_TX_CACHE_ENTRIES)); cmNewTxCacheSize = CM_DEFAULT_TX_CACHE_ENTRIES; cmSendNativeColorDepth = FALSE; TRC_NRM((TB, "Native color depth support is %s", cmSendNativeColorDepth ? "ON" : "OFF")); // Do capability renegotiation. CPC_EnumerateCapabilities(TS_CAPSETTYPE_POINTER, NULL, CMEnumCMCaps); // Check that the negotiated cache size is non-zero - the protocol // assumes this TRC_NRM((TB, "Negotiated cache size: %u", NULL, cmNewTxCacheSize)); if (cmNewTxCacheSize == 0) { // This is a protocol error - log it TRC_ERR((TB, "Negotiated cache size is zero")); WDW_LogAndDisconnect(m_pTSWd, TRUE, Log_RDP_NoCursorCache, NULL, 0); rc = FALSE; } else { // Trigger an IOCTL from the DD so we have the right context to // update the shared memory. DCS_TriggerUpdateShmCallback(); } } DC_END_FN(); return rc; } /****************************************************************************/ /* FUNCTION: CMEnumCMCaps */ /* */ /* CM callback function for CPC capabilities enumeration. */ /* */ /* PARAMETERS: */ /* personID - ID of this person */ /* pCapabilities - pointer to this person's cursor capabilites */ /****************************************************************************/ void RDPCALL SHCLASS CMEnumCMCaps( LOCALPERSONID locPersonID, UINT_PTR UserData, PTS_CAPABILITYHEADER pCapabilities) { PTS_POINTER_CAPABILITYSET pPointerCaps; BOOL fSupportsColorCursors; unsigned cCursorCacheSize; DC_BEGIN_FN("CMEnumCMCaps"); DC_IGNORE_PARAMETER(UserData); pPointerCaps = (PTS_POINTER_CAPABILITYSET)pCapabilities; /************************************************************************/ /* If the person does not have any cursor capabilites we still get */ /* called, but the sizeOfCapabilities field is zero. */ /************************************************************************/ if (pPointerCaps->lengthCapability < FIELDOFFSET( TS_POINTER_CAPABILITYSET, pointerCacheSize)) { TRC_NRM((TB, "Person[0x%x] No cursor caps", locPersonID)); cCursorCacheSize = 0; fSupportsColorCursors = FALSE; } else if (pPointerCaps->lengthCapability == FIELDOFFSET( TS_POINTER_CAPABILITYSET, pointerCacheSize)) { TRC_NRM((TB, "Old style Person[0x%x] capsID(%u) size(%u) ccrs(%u) CacheSize(%u)", locPersonID, pPointerCaps->capabilitySetType, pPointerCaps->lengthCapability, pPointerCaps->colorPointerFlag, pPointerCaps->colorPointerCacheSize)); cCursorCacheSize = pPointerCaps->colorPointerCacheSize; fSupportsColorCursors = pPointerCaps->colorPointerFlag; } else { TRC_NRM((TB, "New style Person[0x%x] capsID(%u) size(%u) ccrs(%u) CacheSize(%u)", locPersonID, pPointerCaps->capabilitySetType, pPointerCaps->lengthCapability, pPointerCaps->colorPointerFlag, pPointerCaps->pointerCacheSize)); cCursorCacheSize = pPointerCaps->pointerCacheSize; fSupportsColorCursors = pPointerCaps->colorPointerFlag; cmSendNativeColorDepth = TRUE; } TRC_ASSERT((fSupportsColorCursors), (TB, "Mono protocol not supported")); cmNewTxCacheSize = min(cmNewTxCacheSize, cCursorCacheSize); DC_END_FN(); } /****************************************************************************/ /* FUNCTION: CM_SendCursorMovedPacket */ /* */ /* Called to try and send a cursor moved packet either from */ /* CM_SendCursorMovedPacket or CM_Periodic. */ /****************************************************************************/ void RDPCALL SHCLASS CM_SendCursorMovedPacket(PPDU_PACKAGE_INFO pPkgInfo) { unsigned packetSize; BYTE *pPackageSpace; TS_POINTER_PDU_DATA UNALIGNED *pPointerPDU; DC_BEGIN_FN("CMSendCursorMovedPacket"); TRC_ASSERT((m_pShm), (TB,"NULL m_pShm")); // Work out how much space we need for a cursor packet. if (scUseFastPathOutput) packetSize = scUpdatePDUHeaderSpace + sizeof(TS_POINT16); else packetSize = scUpdatePDUHeaderSpace + FIELDOFFSET(TS_POINTER_PDU_DATA, pointerData.pointerPosition) + FIELDSIZE(TS_POINTER_PDU_DATA, pointerData.pointerPosition); pPackageSpace = SC_GetSpaceInPackage(pPkgInfo, packetSize); if (NULL != pPackageSpace) { TS_POINT16 UNALIGNED *pPoint; // Fill in the packet. if (scUseFastPathOutput) { pPackageSpace[0] = TS_UPDATETYPE_MOUSEPTR_POSITION | scCompressionUsedValue; pPoint = (TS_POINT16 UNALIGNED *)(pPackageSpace + scUpdatePDUHeaderSpace); } else { ((TS_POINTER_PDU UNALIGNED *)pPackageSpace)->shareDataHeader. pduType2 = TS_PDUTYPE2_POINTER; pPointerPDU = (TS_POINTER_PDU_DATA UNALIGNED *)(pPackageSpace + scUpdatePDUHeaderSpace); pPointerPDU->messageType = TS_PTRMSGTYPE_POSITION; pPoint = &pPointerPDU->pointerData.pointerPosition; } pPoint->x = (UINT16)m_pShm->cm.cmCursorPos.x; pPoint->y = (UINT16)m_pShm->cm.cmCursorPos.y; SC_AddToPackage(pPkgInfo, packetSize, FALSE); TRC_NRM((TB, "Send cursor move (%d,%d)", m_pShm->cm.cmCursorPos.x, m_pShm->cm.cmCursorPos.y)); } else { TRC_ERR((TB, "couldn't get space in package")); } DC_END_FN(); } /****************************************************************************/ /* FUNCTION: CMSendCursorShape */ /* */ /* Sends a packet containing the given cursor shape (bitmap). If the */ /* same shape is located in the cache then a cached cursor packet is sent. */ /* */ /* PARAMETERS: */ /* pCursorShape - pointer to the cursor shape */ /* cbCursorDataSize - pointer to the cursor data size */ /* */ /* RETURNS: TRUE if successful, FALSE otherwise. */ /****************************************************************************/ BOOL RDPCALL SHCLASS CMSendCursorShape(PPDU_PACKAGE_INFO pPkgInfo) { BOOL rc = TRUE; PCM_CURSORSHAPE pCursorShape; unsigned cbCursorDataSize; DC_BEGIN_FN("CMSendCursorShape"); TRC_ASSERT((m_pShm), (TB,"NULL m_pShm")); /************************************************************************/ /* check for a cached cursor */ /************************************************************************/ if (m_pShm->cm.cmCacheHit) { TRC_NRM((TB, "Cursor in cache: iEntry(%u)", m_pShm->cm.cmCacheEntry)); if (CMSendCachedCursor(m_pShm->cm.cmCacheEntry, pPkgInfo)) { /****************************************************************/ /* Indicate to the DD that we got the new cursor and return */ /* success. */ /****************************************************************/ m_pShm->cm.cmBitsWaiting = FALSE; } else { TRC_ALT((TB, "Failed to send definition")); rc = FALSE; } } else { /********************************************************************/ /* wasn't cached - get the bits and send them */ /********************************************************************/ if (CMGetCursorShape(&pCursorShape, &cbCursorDataSize)) { if (!CM_CURSOR_IS_NULL(pCursorShape)) { TRC_NRM((TB, "Send new cursor: pShape(%p), iEntry(%u)", pCursorShape, m_pShm->cm.cmCacheEntry)); if (CMSendColorBitmapCursor(pCursorShape, m_pShm->cm.cmCacheEntry, pPkgInfo)) { /********************************************************/ /* Indicate to the DD that we got the new cursor and */ /* return success. */ /********************************************************/ m_pShm->cm.cmBitsWaiting = FALSE; } else { TRC_ALT((TB, "Failed to send cursor")); rc = FALSE; } } else { /************************************************************/ /* If this is a Null pointer, send the relevant packet. We */ /* return FALSE here so that we will attempt to re-send the */ /* cursor on the next CM_Periodic(). */ /************************************************************/ TRC_NRM((TB, "Send Null cursor")); CMSendSystemCursor(TS_SYSPTR_NULL, pPkgInfo); rc = FALSE; } } } DC_END_FN(); return rc; } /****************************************************************************/ /* FUNCTION: CMSendCachedCursor */ /* */ /* Sends a packet containing the given cache entry id. */ /* */ /* PARAMETERS: */ /* iCacheEntry - cache index */ /* */ /* RETURNS: TRUE if packet sent, FALSE otherwise. */ /****************************************************************************/ BOOL RDPCALL SHCLASS CMSendCachedCursor(unsigned iCacheEntry, PPDU_PACKAGE_INFO pPkgInfo) { BOOL rc = TRUE; BYTE *pPackageSpace; TS_POINTER_PDU_DATA UNALIGNED *pPointerPDU; unsigned cbPacketSize; DC_BEGIN_FN("CMSendCachedCursor"); TRC_NRM((TB, "Send cached cursor(%u)", iCacheEntry)); // See how much space we need. if (scUseFastPathOutput) cbPacketSize = scUpdatePDUHeaderSpace + sizeof(TSUINT16); else cbPacketSize = scUpdatePDUHeaderSpace + FIELDOFFSET(TS_POINTER_PDU_DATA, pointerData.cachedPointerIndex) + FIELDSIZE(TS_POINTER_PDU_DATA, pointerData.cachedPointerIndex); pPackageSpace = SC_GetSpaceInPackage(pPkgInfo, cbPacketSize); if (NULL != pPackageSpace) { TSUINT16 UNALIGNED *pIndex; // Fill in the packet. if (scUseFastPathOutput) { pPackageSpace[0] = TS_UPDATETYPE_MOUSEPTR_CACHED | scCompressionUsedValue; pIndex = (TSUINT16 UNALIGNED *)(pPackageSpace + scUpdatePDUHeaderSpace); } else { ((TS_POINTER_PDU UNALIGNED *)pPackageSpace)->shareDataHeader. pduType2 = TS_PDUTYPE2_POINTER; pPointerPDU = (TS_POINTER_PDU_DATA UNALIGNED *) (pPackageSpace + scUpdatePDUHeaderSpace); pPointerPDU->messageType = TS_PTRMSGTYPE_CACHED; pIndex = &pPointerPDU->pointerData.cachedPointerIndex; } *pIndex = (TSUINT16)iCacheEntry; SC_AddToPackage(pPkgInfo, cbPacketSize, TRUE); } else { TRC_ERR((TB, "couldn't get space in package")); rc = FALSE; } DC_END_FN(); return rc; } /****************************************************************************/ /* FUNCTION: CMSendSystemCursor */ /* */ /* Sends a packet containing the given system cursor IDC. */ /* */ /* PARAMETERS: */ /* cursorIDC - the IDC of the system cursor to send */ /* */ /* RETURNS: TRUE if successful, FALSE otherwise. */ /****************************************************************************/ BOOL RDPCALL SHCLASS CMSendSystemCursor(UINT32 cursorIDC, PPDU_PACKAGE_INFO pPkgInfo) { BOOL rc = TRUE; unsigned cbPacketSize; BYTE *pPackageSpace; TS_POINTER_PDU_DATA UNALIGNED *pPointerPDU; DC_BEGIN_FN("CMSendSystemCursor"); // The cursor is one of the system cursors. Work out how big a packet // we need. if (scUseFastPathOutput) cbPacketSize = scUpdatePDUHeaderSpace; else cbPacketSize = scUpdatePDUHeaderSpace + FIELDOFFSET(TS_POINTER_PDU_DATA, pointerData.systemPointerType) + FIELDSIZE(TS_POINTER_PDU_DATA, pointerData.systemPointerType); pPackageSpace = SC_GetSpaceInPackage(pPkgInfo, cbPacketSize); if (NULL != pPackageSpace) { // Fill in the packet. if (scUseFastPathOutput) { TRC_ASSERT((cursorIDC == TS_SYSPTR_NULL || cursorIDC == TS_SYSPTR_DEFAULT), (TB,"Unrecognized cursorIDC=%u", cursorIDC)); pPackageSpace[0] = (cursorIDC == TS_SYSPTR_NULL ? TS_UPDATETYPE_MOUSEPTR_SYSTEM_NULL : TS_UPDATETYPE_MOUSEPTR_SYSTEM_DEFAULT) | scCompressionUsedValue; } else { ((TS_POINTER_PDU UNALIGNED *)pPackageSpace)->shareDataHeader. pduType2 = TS_PDUTYPE2_POINTER; pPointerPDU = (TS_POINTER_PDU_DATA UNALIGNED *)(pPackageSpace + scUpdatePDUHeaderSpace); pPointerPDU->messageType = TS_PTRMSGTYPE_SYSTEM; pPointerPDU->pointerData.systemPointerType = (UINT16)cursorIDC; } TRC_NRM((TB, "Send UINT16 %ld", cursorIDC)); SC_AddToPackage(pPkgInfo, cbPacketSize, TRUE); } else { TRC_ERR((TB, "couldn't get space in package")); rc = FALSE; } DC_END_FN(); return rc; } /****************************************************************************/ /* FUNCTION: CMSendColorBitmapCursor */ /* */ /* Sends a given cursor as a color bitmap. */ /* */ /* PARAMETERS: */ /* pCursor - pointer to the cursor shape */ /* iCacheEntry - cache index to store in the transmitted packet */ /* */ /* RETURNS: TRUE if packet sent, FALSE otherwise */ /****************************************************************************/ BOOL RDPCALL SHCLASS CMSendColorBitmapCursor( PCM_CURSORSHAPE pCursor, unsigned iCacheEntry, PPDU_PACKAGE_INFO pPkgInfo) { unsigned cbPacketSize; BYTE *pPackageSpace; TS_POINTER_PDU_DATA UNALIGNED *pPointerPDU; BOOL rc = TRUE; unsigned cbANDMaskSize; unsigned cbXORBitmapSize; unsigned cbColorCursorSize; TS_COLORPOINTERATTRIBUTE UNALIGNED *pColAttr; DC_BEGIN_FN("CMSendColorBitmapCursor"); /************************************************************************/ /* Calculate the color cursor size in bytes -- both AND and XOR fields. */ /************************************************************************/ cbANDMaskSize = CURSOR_AND_MASK_SIZE(pCursor); cbXORBitmapSize = CURSOR_XOR_BITMAP_SIZE(pCursor); cbColorCursorSize = cbANDMaskSize + cbXORBitmapSize; // How big is a cursor packet? if (cmSendNativeColorDepth) { // New protocol. if (scUseFastPathOutput) cbPacketSize = scUpdatePDUHeaderSpace + sizeof(TS_POINTERATTRIBUTE) + cbColorCursorSize; else cbPacketSize = scUpdatePDUHeaderSpace + (unsigned)FIELDOFFSET(TS_POINTER_PDU_DATA, pointerData.pointerAttribute.colorPtrAttr. colorPointerData[0]) + cbColorCursorSize; } else { // old protocol - hard coded 24 bpp if (scUseFastPathOutput) cbPacketSize = scUpdatePDUHeaderSpace + sizeof(TS_COLORPOINTERATTRIBUTE) + cbColorCursorSize; else cbPacketSize = scUpdatePDUHeaderSpace + (unsigned)FIELDOFFSET(TS_POINTER_PDU_DATA, pointerData.colorPointerAttribute.colorPointerData[0]) + cbColorCursorSize; } pPackageSpace = SC_GetSpaceInPackage(pPkgInfo, cbPacketSize); if (NULL != pPackageSpace) { // Fill in the packet. if (scUseFastPathOutput) { if (cmSendNativeColorDepth) { TS_POINTERATTRIBUTE UNALIGNED *pAttr; // New protocol. pPackageSpace[0] = TS_UPDATETYPE_MOUSEPTR_POINTER | scCompressionUsedValue; pAttr = (TS_POINTERATTRIBUTE UNALIGNED *)(pPackageSpace + scUpdatePDUHeaderSpace); pAttr->XORBpp = pCursor->hdr.cBitsPerPel; pColAttr = &pAttr->colorPtrAttr; } else { // Old protocol. pPackageSpace[0] = TS_UPDATETYPE_MOUSEPTR_COLOR | scCompressionUsedValue; pColAttr = (TS_COLORPOINTERATTRIBUTE UNALIGNED *) (pPackageSpace + scUpdatePDUHeaderSpace); } } else { ((TS_POINTER_PDU UNALIGNED *)pPackageSpace)->shareDataHeader. pduType2 = TS_PDUTYPE2_POINTER; pPointerPDU = (TS_POINTER_PDU_DATA UNALIGNED *)(pPackageSpace + scUpdatePDUHeaderSpace); if (cmSendNativeColorDepth) { // new protocol pPointerPDU->messageType = TS_PTRMSGTYPE_POINTER; pPointerPDU->pointerData.pointerAttribute.XORBpp = pCursor->hdr.cBitsPerPel; pColAttr = &(pPointerPDU->pointerData.pointerAttribute. colorPtrAttr); } else { // old protocol - hard coded 24 bpp pPointerPDU->messageType = TS_PTRMSGTYPE_COLOR; pColAttr = &(pPointerPDU->pointerData.colorPointerAttribute); } } pColAttr->cacheIndex = (TSUINT16)iCacheEntry; // Now set up the details CMGetColorCursorDetails( pCursor, &(pColAttr->width), &(pColAttr->height), (PUINT16_UA)&(pColAttr->hotSpot.x), (PUINT16_UA)&(pColAttr->hotSpot.y), &(pColAttr->colorPointerData[0]) + cbXORBitmapSize, &(pColAttr->lengthANDMask), &(pColAttr->colorPointerData[0]), &(pColAttr->lengthXORMask)); // sanity checks TRC_ASSERT((pColAttr->lengthANDMask == cbANDMaskSize), (TB, "AND mask size differs: %u, %u", pColAttr->lengthANDMask, cbANDMaskSize)); TRC_ASSERT((pColAttr->lengthXORMask == cbXORBitmapSize), (TB, "XOR bitmap size differs: %u, %u", pColAttr->lengthXORMask, cbXORBitmapSize)); TRC_NRM((TB, "Color cursor id %u cx:%u cy:%u xhs:%u yhs:%u cbAND:%u cbXOR:%u", pColAttr->cacheIndex, pColAttr->width, pColAttr->height, pColAttr->hotSpot.x, pColAttr->hotSpot.y, pColAttr->lengthANDMask, pColAttr->lengthXORMask)); // Add it to the package. SC_AddToPackage(pPkgInfo, cbPacketSize, TRUE); } else { TRC_ERR((TB, "couldn't get space in package")); rc = FALSE; } DC_END_FN(); return rc; } /****************************************************************************/ /* FUNCTION: CMGetColorCursorDetails */ /* */ /* Returns details of a cursor at 24bpp, given a CM_CURSORSHAPE structure. */ /* */ /* PARAMETERS: */ /* pCursor - pointer to a CM_CURSORSHAPE structure from which this function */ /* extracts the details */ /* pcxWidth - pointer to a UINT16 variable that receives the cursor width */ /* in pixels */ /* pcyHeight - pointer to a UINT16 variable that receives the cursor */ /* height in pixels */ /* pxHotSpot - pointer to a UINT16 variable that receives the cursor */ /* hotspot x coordinate */ /* pyHotSpot - pointer to a UINT16 variable that receives the cursor */ /* hotspot y coordinate */ /* pANDMask - pointer to a buffer that receives the cursor AND mask */ /* pcbANDMask - pointer to a UINT16 variable that receives the size in */ /* bytes of the cursor AND mask */ /* pXORBitmap - pointer to a buffer that receives the cursor XOR bitmap at */ /* 24bpp */ /* pcbXORBitmap - pointer to a UINT16 variable that receives the size in */ /* bytes of the cursor XOR bitmap */ /****************************************************************************/ void RDPCALL SHCLASS CMGetColorCursorDetails( PCM_CURSORSHAPE pCursor, PUINT16_UA pcxWidth, PUINT16_UA pcyHeight, PUINT16_UA pxHotSpot, PUINT16_UA pyHotSpot, PBYTE pANDMask, PUINT16_UA pcbANDMask, PBYTE pXORBitmap, PUINT16_UA pcbXORBitmap) { unsigned cbANDMaskSize; unsigned cbXORBitmapSize; unsigned cbXORBitmapRowWidth; unsigned cbANDMaskRowWidth; unsigned cbSrcRowOffset; unsigned cbDstRowOffset; unsigned y; PCM_CURSORSHAPEHDR pCursorHdr; DC_BEGIN_FN("CMGetColorCursorDetails"); TRC_ASSERT((pCursor != NULL),(TB,"NULL pCursor not allowed!")); pCursorHdr = &(pCursor->hdr); /************************************************************************/ /* Copy the cursor size and hotspot coords. */ /************************************************************************/ *pcxWidth = pCursorHdr->cx; *pcyHeight = pCursorHdr->cy; *pxHotSpot = (UINT16)pCursorHdr->ptHotSpot.x; *pyHotSpot = (UINT16)pCursorHdr->ptHotSpot.y; TRC_NRM((TB, "cx(%u) cy(%u) cbWidth %d planes(%u) bpp(%u)", pCursorHdr->cx, pCursorHdr->cy, pCursorHdr->cbMaskRowWidth, pCursorHdr->cPlanes, pCursorHdr->cBitsPerPel)); cbANDMaskSize = CURSOR_AND_MASK_SIZE(pCursor); cbXORBitmapSize = CURSOR_XOR_BITMAP_SIZE(pCursor); /************************************************************************/ /* Copy the AND mask - this is always mono. */ /* */ /* The AND mask is currently in top-down format (the top row of the */ /* bitmap comes first). */ /* */ /* The protocol sends bitmaps in Device Independent format, which is */ /* bottom-up. We therefore have to flip the rows as we copy the mask. */ /************************************************************************/ cbANDMaskRowWidth = pCursorHdr->cbMaskRowWidth; cbSrcRowOffset = 0; cbDstRowOffset = cbANDMaskRowWidth * (pCursorHdr->cy-1); for (y = 0; y < pCursorHdr->cy; y++) { memcpy( pANDMask + cbDstRowOffset, pCursor->Masks + cbSrcRowOffset, cbANDMaskRowWidth ); cbSrcRowOffset += cbANDMaskRowWidth; cbDstRowOffset -= cbANDMaskRowWidth; } /************************************************************************/ /* Copy the XOR mask a row at a time. It starts at the end of the AND */ /* mask in the source data */ /************************************************************************/ cbXORBitmapRowWidth = CURSOR_DIB_BITS_SIZE(pCursor->hdr.cx, 1, pCursor->hdr.cBitsPerPel); cbSrcRowOffset = cbANDMaskSize; cbDstRowOffset = cbXORBitmapRowWidth * (pCursorHdr->cy-1); for (y = 0; y < pCursorHdr->cy; y++) { memcpy( pXORBitmap + cbDstRowOffset, pCursor->Masks + cbSrcRowOffset, cbXORBitmapRowWidth ); cbSrcRowOffset += pCursorHdr->cbColorRowWidth; cbDstRowOffset -= cbXORBitmapRowWidth; } TRC_NRM((TB, "XOR data len %d", cbXORBitmapSize )); TRC_DATA_NRM("XOR data", pXORBitmap, cbXORBitmapSize); *pcbANDMask = (UINT16) CURSOR_AND_MASK_SIZE(pCursor); *pcbXORBitmap = (UINT16) CURSOR_XOR_BITMAP_SIZE(pCursor); DC_END_FN(); }