windows-nt/Source/XPSP1/NT/enduser/netmeeting/as/cpi32/rbc.cpp
2020-09-26 16:20:57 +08:00

747 lines
20 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "precomp.h"
//
// RBC.CPP
// Received Bitmap Cache
//
// Copyright(c) Microsoft 1997-
//
#define MLZ_FILE_ZONE ZONE_CORE
//
// RBC_ViewStarting()
//
// For 3.0 nodes, we create the cache each time they start hosting.
// For 2.x nodes, we create the cache once and use it until they leave the
// share.
//
BOOL ASShare::RBC_ViewStarting(ASPerson * pasPerson)
{
BOOL rc = FALSE;
DebugEntry(ASShare::RBC_ViewStarting);
ValidatePerson(pasPerson);
if (pasPerson->prbcHost != NULL)
{
ASSERT(pasPerson->cpcCaps.general.version < CAPS_VERSION_30);
TRACE_OUT(("RBC_ViewStarting: Reusing rbc cache for 2.x node [%d]",
pasPerson->mcsID));
rc = TRUE;
DC_QUIT;
}
//
// Allocate the INCOMING cache data for this host.
//
pasPerson->prbcHost = new RBC_HOST_INFO;
if (!pasPerson->prbcHost)
{
ERROR_OUT(( "Failed to get memory for prbcHost info"));
DC_QUIT;
}
ZeroMemory(pasPerson->prbcHost, sizeof(*(pasPerson->prbcHost)));
SET_STAMP(pasPerson->prbcHost, RBCHOST);
TRACE_OUT(( "Allocated RBC root for host [%d] at 0x%08x",
pasPerson->mcsID, pasPerson->prbcHost));
//
// Create the bitmap caches for the sender
//
// SMALL
if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsSmallCacheNumEntries,
pasPerson->cpcCaps.bitmaps.sender.capsSmallCacheCellSize,
ID_SMALL_BMP_CACHE,
&(pasPerson->prbcHost->bitmapCache[ID_SMALL_BMP_CACHE])))
{
DC_QUIT;
}
// MEDIUM
if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsMediumCacheNumEntries,
pasPerson->cpcCaps.bitmaps.sender.capsMediumCacheCellSize,
ID_MEDIUM_BMP_CACHE,
&(pasPerson->prbcHost->bitmapCache[ID_MEDIUM_BMP_CACHE])))
{
DC_QUIT;
}
// LARGE
if (!BMCAllocateCacheData(pasPerson->cpcCaps.bitmaps.sender.capsLargeCacheNumEntries,
pasPerson->cpcCaps.bitmaps.sender.capsLargeCacheCellSize,
ID_LARGE_BMP_CACHE,
&(pasPerson->prbcHost->bitmapCache[ID_LARGE_BMP_CACHE])))
{
DC_QUIT;
}
//
// The host can join the share.
//
rc = TRUE;
DC_EXIT_POINT:
DebugExitBOOL(ASShare::RBC_ViewStarting, rc);
return(rc);
}
//
// RBC_ViewEnded()
//
void ASShare::RBC_ViewEnded(ASPerson * pasPerson)
{
DebugEntry(ASShare::RBC_ViewEnded);
ValidatePerson(pasPerson);
//
// For 3.0 NODES, we can free the cache; 3.0 senders clear theirs
// every time they host.
// For 2.x NODES, we must keep it around while they are in the share.
//
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
{
RBCFreeIncoming(pasPerson);
}
else
{
TRACE_OUT(("RBC_ViewEnded: Keeping rbc cache for 2.x node [%d]",
pasPerson->mcsID));
}
DebugExitVOID(ASShare::RBC_ViewEnded);
}
//
// RBC_PartyLeftShare()
// For 2.x nodes, frees the incoming RBC data
//
void ASShare::RBC_PartyLeftShare(ASPerson * pasPerson)
{
DebugEntry(ASShare::RBC_PartyLeftShare);
ValidatePerson(pasPerson);
if (pasPerson->cpcCaps.general.version >= CAPS_VERSION_30)
{
// This should be gone!
ASSERT(pasPerson->prbcHost == NULL);
}
else
{
TRACE_OUT(("RBC_PartyLeftShare: Freeing rbc cache for 2.x node [%d]",
pasPerson->mcsID));
RBCFreeIncoming(pasPerson);
}
DebugExitVOID(ASShare::RBC_PartyLeftShare);
}
//
// RBCFreeIncoming()
// Frees the party RBC incoming structures. This happens
// * For 3.0 nodes when they stop hosting
// * For 2.x nodes when leave the share
//
void ASShare::RBCFreeIncoming(ASPerson * pasPerson)
{
DebugEntry(ASShare::RBCFreeIncoming);
//
// Free this host's cache bitmaps.
//
if (pasPerson->prbcHost != NULL)
{
UINT i;
//
// Delete all of this host's cache bitmaps.
//
for (i = 0; i < NUM_BMP_CACHES; i++)
{
BMCFreeCacheData(&(pasPerson->prbcHost->bitmapCache[i]));
}
delete pasPerson->prbcHost;
pasPerson->prbcHost = NULL;
}
DebugExitVOID(ASShare::RBCFreeIncoming);
}
//
// RBC_ProcessCacheOrder(..)
//
void ASShare::RBC_ProcessCacheOrder
(
ASPerson * pasPerson,
LPCOM_ORDER_UA pOrder
)
{
PBMC_ORDER_HDR pBmcOrderHdr;
PBMC_COLOR_TABLE_ORDER_UA pColorOrder;
PBMC_BITMAP_BITS_ORDER_R2_UA pBitsOrderR2;
BOOL fCompressed = FALSE;
UINT cxFixedBitmapWidth;
UINT iCacheEntry;
LPBYTE pBitmapBits;
UINT cbBitmapBits;
DebugEntry(ASShare::RBC_ProcessCacheOrder);
ValidatePerson(pasPerson);
//
// The rectangle is not included in the header for private order data
// (see SBC_CopyPrivateOrderData) so we must take this into account
// when working out the address of the order data.
//
pBmcOrderHdr = (PBMC_ORDER_HDR)
(pOrder->abOrderData - sizeof(pOrder->OrderHeader.rcsDst));
switch (pBmcOrderHdr->bmcPacketType)
{
case BMC_PT_COLOR_TABLE:
//
// This is a new color table. Simply cache the RGB values for
// use when we come to process a memblt order
// For backlevel calls the color table is always stored at
// index 0 because the index field in the order reuses a
// zero initialized "padding" field in the old structure.
//
TRACE_OUT(("Person [%d] Caching color table", pasPerson->mcsID));
pColorOrder = (PBMC_COLOR_TABLE_ORDER_UA)pBmcOrderHdr;
PM_CacheRxColorTable(pasPerson, pColorOrder->index,
EXTRACT_TSHR_UINT16_UA(&(pColorOrder->colorTableSize)),
(LPTSHR_RGBQUAD)&pColorOrder->data[0]);
break;
case BMC_PT_BITMAP_BITS_COMPRESSED:
fCompressed = TRUE;
TRACE_OUT(( "Compressed BMP"));
case BMC_PT_BITMAP_BITS_UNCOMPRESSED:
//
// This is some cached bitmap data. We have to store it in the
// specified slot in the specified cache.
//
//
// The width of the bitmaps we use are actually fixed as
// multiples of 16 pels wide. Work out the width that
// corresponds to the sub-bitmap width of data we are caching.
//
pBitsOrderR2 = (PBMC_BITMAP_BITS_ORDER_R2_UA)pBmcOrderHdr;
cbBitmapBits = EXTRACT_TSHR_UINT16_UA(
&(pBitsOrderR2->header.cbBitmapBits));
cxFixedBitmapWidth =
((pBitsOrderR2->header.cxSubBitmapWidth +15)/16)*16;
//
// The location of cache entry field depends on the R1/R2
// protocol
//
iCacheEntry = EXTRACT_TSHR_UINT16_UA(&(pBitsOrderR2->iCacheEntryR2));
pBitmapBits = pBitsOrderR2->data;
TRACE_OUT(("Person [%d] Rx bmp: id(%d) entry(%d) size(%dx%d) " \
"fixed(%d) bpp(%d) bytes(%d) compressed(%d)",
pasPerson->mcsID,
pBitsOrderR2->header.cacheID,
iCacheEntry,
pBitsOrderR2->header.cxSubBitmapWidth,
pBitsOrderR2->header.cySubBitmapHeight,
cxFixedBitmapWidth,
pBitsOrderR2->header.bpp,
cbBitmapBits,
fCompressed));
//
// Pass the BMC data to the caching code. When calculating the
// pointer to the bitmap bits remember that we did not send the
// pBitmapBits field of the BMC_BITMAP_BITS_ORDER_Rx structure
// (see SBC_CopyPrivateOrderData).
//
RBCStoreBitsInCacheBitmap(pasPerson,
pBitsOrderR2->header.cacheID,
iCacheEntry,
pBitsOrderR2->header.cxSubBitmapWidth,
cxFixedBitmapWidth,
pBitsOrderR2->header.cySubBitmapHeight,
pBitsOrderR2->header.bpp,
pBitmapBits,
cbBitmapBits,
fCompressed);
break;
default:
ERROR_OUT(( "[%u]Invalid packet type(%d)",
pasPerson,
(UINT)pBmcOrderHdr->bmcPacketType));
break;
}
DebugExitVOID(ASShare::RBC_ProcessCacheOrder);
}
//
// RBC_MapCacheIDToBitmapHandle(..)
//
HBITMAP ASShare::RBC_MapCacheIDToBitmapHandle
(
ASPerson * pasPerson,
UINT cache,
UINT cacheEntry,
UINT colorIndex
)
{
PBMC_DIB_CACHE pDIBCache;
PBMC_DIB_ENTRY pDIBEntry;
BITMAPINFO_ours bitmapInfo;
UINT cColors;
HBITMAP hWorkBitmap = NULL;
HPALETTE hpalOldDIB = NULL;
LPBYTE pBits;
UINT cacheOffset;
DebugEntry(ASShare::RBC_MapCacheIDToBitmapHandle);
ValidateView(pasPerson);
//
// Check that the supplied cache ID is valid.
//
if (cache >= NUM_BMP_CACHES)
{
ERROR_OUT(( "[%u]Invalid cache ID (%d)", pasPerson, cache));
cache = 0;
}
//
// Get a pointer to the bitmap data
//
// Note that there are two indexes floating around. From the host's
// perspective this index is a Cache Handler token and it must be
// translated in order to address the associated data. However we
// use it as the direct index into our receive cache and so the
// slots used on host and remote will be diferent.
//
// There is no reason why the slots should be the same. This is just
// to warn you that if you try correlating cache offsets between
// host and remote you will get confused as soon as the cache fills
// up and entries are reallocated in different positions.
//
//
pDIBCache = &(pasPerson->prbcHost->bitmapCache[cache]);
TRACE_OUT(( "Local person [%d] cache id %d pointer %lx",
pasPerson->mcsID, cache, pDIBCache));
cacheOffset = cacheEntry * pDIBCache->cSize;
pDIBEntry = (PBMC_DIB_ENTRY)(pDIBCache->data + cacheOffset);
TRACE_OUT(( "Bits for index %u are at offset %ld, pointer 0x%08x",
cacheEntry, (cacheEntry * pDIBCache->cSize), pDIBEntry));
//
// Set up the BitmapInfo structure.
//
USR_InitDIBitmapHeader((BITMAPINFOHEADER *)&bitmapInfo, pDIBEntry->bpp);
bitmapInfo.bmiHeader.biWidth = pDIBEntry->cxFixed;
bitmapInfo.bmiHeader.biHeight = pDIBEntry->cy;
//
// Copy the Rx color table into the bitmap header.
//
if ( (pDIBEntry->bpp == 1) ||
(pDIBEntry->bpp == 4) ||
(pDIBEntry->bpp == 8) )
{
cColors = COLORS_FOR_BPP(pDIBEntry->bpp);
PM_GetColorTable( pasPerson,
colorIndex,
&cColors,
(LPTSHR_RGBQUAD)(&bitmapInfo.bmiColors) );
TRACE_OUT(( "Got %u colors from table",cColors));
bitmapInfo.bmiHeader.biClrUsed = cColors;
}
else if (pDIBEntry->bpp == 24)
{
ASSERT(colorIndex == COLORCACHEINDEX_NONE);
}
else
{
ERROR_OUT(("RBC: Unexpected bpp %d from [%d]", pDIBEntry->bpp, pasPerson->mcsID));
DC_QUIT;
}
//
// Select which fixed width bitmap we are going to use to store the
// incoming DIB bits.
//
switch (pDIBEntry->cxFixed)
{
case 16:
hWorkBitmap = m_usrBmp16;
break;
case 32:
hWorkBitmap = m_usrBmp32;
break;
case 48:
hWorkBitmap = m_usrBmp48;
break;
case 64:
hWorkBitmap = m_usrBmp64;
break;
case 80:
hWorkBitmap = m_usrBmp80;
break;
case 96:
hWorkBitmap = m_usrBmp96;
break;
case 112:
hWorkBitmap = m_usrBmp112;
break;
case 128:
hWorkBitmap = m_usrBmp128;
break;
case 256:
hWorkBitmap = m_usrBmp256;
break;
default:
ERROR_OUT(("RBC_MapCacheIDToBitmapHandle: invalid size from [%d]",
pDIBEntry->cxFixed, pasPerson->mcsID));
hWorkBitmap = m_usrBmp256;
break;
}
ASSERT(hWorkBitmap != NULL);
//
// If the cached bitmap bits are compressed, we first have to
// decompress them.
//
if (pDIBEntry->bCompressed)
{
ASSERT(pDIBEntry->bpp <= 8);
//
// Use the decompression buffer to decompress the bitmap data.
//
if (!BD_DecompressBitmap(pDIBEntry->bits, m_usrPBitmapBuffer,
pDIBEntry->cCompressed,
pDIBEntry->cxFixed,
pDIBEntry->cy,
pDIBEntry->bpp))
{
ERROR_OUT((
"Failed to decompress bitmap pBits(%lx)"
" pBuf(%lx) cb(%x) cx(%d) cy(%d) bpp(%d)",
pDIBEntry->bits,
m_usrPBitmapBuffer,
pDIBEntry->cCompressed,
pDIBEntry->cxFixed,
pDIBEntry->cy,
pDIBEntry->bpp));
DC_QUIT;
}
pBits = m_usrPBitmapBuffer;
}
else
{
//
// For uncompressed data just use direct from the cache
//
TRACE_OUT(( "Bitmap bits are uncompressed"));
pBits = pDIBEntry->bits;
}
//
// Set the bits into the bitmap we are about to return to the caller
//
hpalOldDIB = SelectPalette(pasPerson->m_pView->m_usrWorkDC,
pasPerson->pmPalette, FALSE);
RealizePalette(pasPerson->m_pView->m_usrWorkDC);
if (!SetDIBits(pasPerson->m_pView->m_usrWorkDC,
hWorkBitmap,
0,
pDIBEntry->cy,
pBits,
(BITMAPINFO *)&bitmapInfo,
DIB_RGB_COLORS))
{
ERROR_OUT(("SetDIBits failed in RBC_MapCacheIDToBitmapHandle"));
}
SelectPalette(pasPerson->m_pView->m_usrWorkDC, hpalOldDIB, FALSE );
TRACE_OUT(( "Returning bitmap for person [%d] cache %u index %u color %u",
pasPerson->mcsID, cache, cacheEntry, colorIndex));
DC_EXIT_POINT:
DebugExitVOID(ASShare::RBC_MapCacheIDToBitmapHandle);
return(hWorkBitmap);
}
//
// FUNCTION: RBCStoreBitsInCacheBitmap(..)
//
// DESCRIPTION:
//
// Stores received bitmap bits into one of the receiver's cache bitmaps.
//
// PARAMETERS:
//
// pasPerson - pasPerson of host the bits came from.
//
// cache - the id of the cache bitmap to store the bits in.
//
// iCacheEntry - the cache entry number (index).
//
// cxSubBitmapWidth - the width in pels of the actual sub-bitmap (ie.
// excluding padding)
//
// cxFixedWidth - the fixed width in pels of the supplied bits (ie.
// including padding)
//
// cySubBitmapHeight - the height in pels of the sub-bitmap.
//
// pBitmapBits - a pointer to the actual bitmap bits. These may or may
// not be compressed (determined by the value of the fCompressed
// flag).
//
// cbBitmapBits - the size of the bitmap bits pointed to by pBitmapBits.
//
// fCompressed - a flag specifying whether the supplied bitmap
// bits are compressed.
//
// RETURNS:
//
// Nothing.
//
//
void ASShare::RBCStoreBitsInCacheBitmap
(
ASPerson * pasPerson,
UINT cache,
UINT iCacheEntry,
UINT cxSubBitmapWidth,
UINT cxFixedWidth,
UINT cySubBitmapHeight,
UINT bpp,
LPBYTE pBitmapBits,
UINT cbBitmapBits,
BOOL fCompressed
)
{
PBMC_DIB_ENTRY pDIBEntry;
DebugEntry(ASShare::RBCStoreBitsInCacheBitmap);
ValidatePerson(pasPerson);
//
// Do some error checking.
//
if (cache >= NUM_BMP_CACHES)
{
ERROR_OUT(("Invalid cache ID %d from [%d]", cache, pasPerson->mcsID));
DC_QUIT;
}
//
// Now store the bits in the cache
// The cache is a huge chunk of memory comprising cache slots of cSize
// bytes each. cSize is rounded to a power of 2 to ensure the array
// spans segment boundaries cleanly for segmented architecture OSs.
//
pDIBEntry = (PBMC_DIB_ENTRY)
(((LPBYTE)(pasPerson->prbcHost->bitmapCache[cache].data) +
(iCacheEntry * pasPerson->prbcHost->bitmapCache[cache].cSize)));
TRACE_OUT(( "Selected cache entry 0x%08x",pDIBEntry));
pDIBEntry->inUse = TRUE;
pDIBEntry->cx = (TSHR_UINT16)cxSubBitmapWidth;
pDIBEntry->cxFixed = (TSHR_UINT16)cxFixedWidth;
pDIBEntry->cy = (TSHR_UINT16)cySubBitmapHeight;
pDIBEntry->bpp = (TSHR_UINT16)bpp;
pDIBEntry->bCompressed = (fCompressed != FALSE);
pDIBEntry->cCompressed = cbBitmapBits;
//
// Now copy the bits into the cache entry
//
memcpy(pDIBEntry->bits, pBitmapBits, cbBitmapBits);
//
// THIS FIELD IS NEVER ACCESSED.
//
pDIBEntry->cBits = BYTES_IN_BITMAP(cxFixedWidth, cySubBitmapHeight,
pDIBEntry->bpp);
DC_EXIT_POINT:
DebugExitVOID(ASShare::RBCStoreBitsInCacheBitmap);
}
//
// BMCAllocateCacheData()
//
// DESCRIPTION:
//
// Allocates memory for a bitmap cache
//
// PARAMETERS:
//
// cellSize
//
// RETURNS:
//
// Area needed
//
//
BOOL BMCAllocateCacheData
(
UINT numEntries,
UINT cellSize,
UINT cacheID,
PBMC_DIB_CACHE pCache
)
{
BOOL rc = TRUE;
UINT memoryNeeded;
UINT workSize;
PBMC_DIB_ENTRY pCacheEntry;
UINT i;
DebugEntry(BMCAllocateCacheData);
//
// First we must free up any data, if it has been allocated
//
BMCFreeCacheData(pCache);
//
// For 2.x compat, we have SEND caps of 1 entry, 1 byte since 2.x
// remotes fail for zero entries. But we don't want a small cache
// at all, and for W95 nodes that don't have a cache at all, we don't
// want viewers to alloc memory which will never be used.
//
if ((cellSize > 1) && (numEntries > 1))
{
//
// Calculate the cell area
//
workSize = cellSize + sizeof(BMC_DIB_ENTRY) - 1;
memoryNeeded = numEntries * workSize;
TRACE_OUT(("Need 0x%08x bytes for cache %d, %d cells of size 0x%08x",
memoryNeeded, cacheID, numEntries, cellSize));
//
// Malloc the huge space
//
pCache->data = new BYTE[memoryNeeded];
if (pCache->data == NULL)
{
ERROR_OUT(( "Failed to alloc bitmap cache %d", cacheID));
rc = FALSE;
DC_QUIT;
}
pCache->cCellSize = cellSize;
pCache->cEntries = numEntries;
pCache->cSize = workSize;
pCache->freeEntry = NULL;
pCacheEntry = (PBMC_DIB_ENTRY)(pCache->data);
for (i = 0; i < numEntries; i++)
{
pCacheEntry->inUse = FALSE;
pCacheEntry = (PBMC_DIB_ENTRY)(((LPBYTE)pCacheEntry) + workSize);
}
TRACE_OUT(( "Allocated cache %d size %d, pointer 0x%08x stored at 0x%08x",
cacheID,
memoryNeeded,
pCache->data,
&pCache->data));
}
DC_EXIT_POINT:
DebugExitBOOL(BMCAllocateCacheData, rc);
return(rc);
}
//
// FUNCTION: BMCFreeCacheData()
//
// DESCRIPTION:
//
// Deletes selected cache's memory
//
// PARAMETERS:
//
// cacheID - id of cache for free
// pCache - pointer to memory to be freed
//
//
// RETURNS:
//
// Nothing.
//
//
void BMCFreeCacheData(PBMC_DIB_CACHE pCache)
{
DebugEntry(BMCFreeCacheData);
if (pCache->data)
{
delete[] pCache->data;
pCache->data = NULL;
}
pCache->cCellSize = 0;
pCache->cEntries = 0;
DebugExitVOID(BMCFreeCacheData);
}