Leaked source code of windows server 2003
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.
 
 
 
 
 
 

11103 lines
436 KiB

/****************************************************************************/
// uhint.cpp
//
// Update Handler internal functions
//
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <adcg.h>
#include <tsgdiplusenums.h>
extern "C" {
#define TRC_GROUP TRC_GROUP_CORE
#define TRC_FILE "uhint"
#include <atrcapi.h>
}
#define TSC_HR_FILEID TRC_HR_UINT_CPP
#include "autil.h"
#include "uh.h"
#include "op.h"
#include "wui.h"
#include "od.h"
#include "cc.h"
#include "aco.h"
#include "ih.h"
#include "gh.h"
#include "cd.h"
#include <abdapi.h>
#include "clx.h"
#include "objs.h"
#if 0
#include "drawstream.h"
#endif
extern "C" {
#ifdef OS_WINCE
#ifdef DC_DEBUG
#include <eosint.h>
#endif
#ifdef HDCL1171PARTIAL
BOOL VirtualCopy(LPVOID, LPVOID, DWORD, DWORD);
#endif // HDCL1171PARTIAL
#endif // OS_WINCE
#define DC_INCLUDE_DATA
#include <acpudata.h>
#undef DC_INCLUDE_DATA
#ifndef OS_WINCE
#include <direct.h>
#include <io.h>
#endif
}
/****************************************************************************/
/* Win16 does not support DibSections. */
/* WinCE supports them, but the current data says the OPAQUERECT order and */
/* the SCRBLT order times are severely impacted by USEDIBSECTION */
/****************************************************************************/
#ifdef OS_WINNT
#define USE_DIBSECTION
#endif /* OS_WINNT */
/****************************************************************************/
/* uhWindowsROPs */
/* */
/* A table of Windows ROPs used to generate a 32-bit Windows ROP from the */
/* 0x00-0xFF range of ROPs sent in the protocol. */
/* */
/* All of the values in the table are 16-bit. The 32-bit ROP is generated */
/* by putting the ROP index into the high 16-bits of the 32-bit value. See */
/* UHConvertToWindowsROP for the code. */
/****************************************************************************/
const UINT16 uhWindowsROPs[256] =
{
0x0042, 0x0289, 0x0C89, 0x00AA,
0x0C88, 0x00A9, 0x0865, 0x02C5,
0x0F08, 0x0245, 0x0329, 0x0B2A,
0x0324, 0x0B25, 0x08A5, 0x0001,
0x0C85, 0x00A6, 0x0868, 0x02C8,
0x0869, 0x02C9, 0x5CCA, 0x1D54,
0x0D59, 0x1CC8, 0x06C5, 0x0768,
0x06CA, 0x0766, 0x01A5, 0x0385,
0x0F09, 0x0248, 0x0326, 0x0B24,
0x0D55, 0x1CC5, 0x06C8, 0x1868,
0x0369, 0x16CA, 0x0CC9, 0x1D58,
0x0784, 0x060A, 0x064A, 0x0E2A,
0x032A, 0x0B28, 0x0688, 0x0008,
0x06C4, 0x1864, 0x01A8, 0x0388,
0x078A, 0x0604, 0x0644, 0x0E24,
0x004A, 0x18A4, 0x1B24, 0x00EA,
0x0F0A, 0x0249, 0x0D5D, 0x1CC4,
0x0328, 0x0B29, 0x06C6, 0x076A,
0x0368, 0x16C5, 0x0789, 0x0605,
0x0CC8, 0x1954, 0x0645, 0x0E25,
0x0325, 0x0B26, 0x06C9, 0x0764,
0x08A9, 0x0009, 0x01A9, 0x0389,
0x0785, 0x0609, 0x0049, 0x18A9,
0x0649, 0x0E29, 0x1B29, 0x00E9,
0x0365, 0x16C6, 0x0786, 0x0608,
0x0788, 0x0606, 0x0046, 0x18A8,
0x58A6, 0x0145, 0x01E9, 0x178A,
0x01E8, 0x1785, 0x1E28, 0x0C65,
0x0CC5, 0x1D5C, 0x0648, 0x0E28,
0x0646, 0x0E26, 0x1B28, 0x00E6,
0x01E5, 0x1786, 0x1E29, 0x0C68,
0x1E24, 0x0C69, 0x0955, 0x03C9,
0x03E9, 0x0975, 0x0C49, 0x1E04,
0x0C48, 0x1E05, 0x17A6, 0x01C5,
0x00C6, 0x1B08, 0x0E06, 0x0666,
0x0E08, 0x0668, 0x1D7C, 0x0CE5,
0x0C45, 0x1E08, 0x17A9, 0x01C4,
0x17AA, 0x01C9, 0x0169, 0x588A,
0x1888, 0x0066, 0x0709, 0x07A8,
0x0704, 0x07A6, 0x16E6, 0x0345,
0x00C9, 0x1B05, 0x0E09, 0x0669,
0x1885, 0x0065, 0x0706, 0x07A5,
0x03A9, 0x0189, 0x0029, 0x0889,
0x0744, 0x06E9, 0x0B06, 0x0229,
0x0E05, 0x0665, 0x1974, 0x0CE8,
0x070A, 0x07A9, 0x16E9, 0x0348,
0x074A, 0x06E6, 0x0B09, 0x0226,
0x1CE4, 0x0D7D, 0x0269, 0x08C9,
0x00CA, 0x1B04, 0x1884, 0x006A,
0x0E04, 0x0664, 0x0708, 0x07AA,
0x03A8, 0x0184, 0x0749, 0x06E4,
0x0020, 0x0888, 0x0B08, 0x0224,
0x0E0A, 0x066A, 0x0705, 0x07A4,
0x1D78, 0x0CE9, 0x16EA, 0x0349,
0x0745, 0x06E8, 0x1CE9, 0x0D75,
0x0B04, 0x0228, 0x0268, 0x08C8,
0x03A5, 0x0185, 0x0746, 0x06EA,
0x0748, 0x06E5, 0x1CE8, 0x0D79,
0x1D74, 0x5CE6, 0x02E9, 0x0849,
0x02E8, 0x0848, 0x0086, 0x0A08,
0x0021, 0x0885, 0x0B05, 0x022A,
0x0B0A, 0x0225, 0x0265, 0x08C5,
0x02E5, 0x0845, 0x0089, 0x0A09,
0x008A, 0x0A0A, 0x02A9, 0x0062
};
#define BMP_SIZE(bmih) \
((ULONG)((bmih).biHeight *(((bmih).biBitCount * (bmih).biWidth + 31) & ~31) >> 3))
/****************************************************************************/
/* Name: UHAddUpdateRegion */
/* */
/* Purpose: Adds the bounds of a given order to the supplied update */
/* region. */
/****************************************************************************/
inline void DCINTERNAL CUH::UHAddUpdateRegion(
PUH_ORDER pOrder,
HRGN hrgnUpdate)
{
RECT rect;
DC_BEGIN_FN("UHAddUpdateRegion");
TIMERSTART;
if (pOrder->dstRect.left <= pOrder->dstRect.right &&
pOrder->dstRect.top <= pOrder->dstRect.bottom) {
// Windows wants exclusive coordinates.
SetRectRgn(_UH.hrgnUpdateRect, pOrder->dstRect.left,
pOrder->dstRect.top, pOrder->dstRect.right + 1,
pOrder->dstRect.bottom + 1);
#ifdef SMART_SIZING
//only update smartsizing region when UI_Smart_Sizing is enabled
if (_pUi->UI_GetSmartSizing()) {
_pOp->OP_AddUpdateRegion(pOrder->dstRect.left,
pOrder->dstRect.top, pOrder->dstRect.right + 1,
pOrder->dstRect.bottom + 1);
}
#endif // SMART_SIZING
// Combine the rectangle region with the update region.
if (!UnionRgn(hrgnUpdate, hrgnUpdate, _UH.hrgnUpdateRect)) {
// The region union failed so we must simplify the region. This
// means that we may paint areas which we have not received an
// updates for - but this is better than not painting areas which
// we have received updates for.
TRC_ALT((TB, _T("UnionRgn failed")));
GetRgnBox(hrgnUpdate, &rect);
SetRectRgn(hrgnUpdate, rect.left, rect.top, rect.right + 1,
rect.bottom + 1);
if (!UnionRgn(hrgnUpdate, hrgnUpdate, _UH.hrgnUpdateRect))
{
TRC_ERR((TB, _T("UnionRgn failed after simplification")));
}
}
}
else {
// NULL rectangle - do not add to update region.
TRC_NRM(( TB, _T("NULL rect: %d,%d %d,%d"),
(int)pOrder->dstRect.left,
(int)pOrder->dstRect.top,
(int)pOrder->dstRect.right,
(int)pOrder->dstRect.bottom));
}
TIMERSTOP;
UPDATECOUNTER(FC_UHADDUPDATEREGION);
DC_END_FN();
}
/****************************************************************************/
/* Name: UHSetClipRegion */
/* */
/* Purpose: Sets the clip retangle in the current output DC. */
/****************************************************************************/
void DCINTERNAL CUH::UH_SetClipRegion(int left, int top, int right, int bottom)
{
POINT points[2];
HRGN hrgnRect;
HDC hdc;
DC_BEGIN_FN("UHSetClipRegion");
TIMERSTART;
#if defined (OS_WINCE)
if ((_UH.validClipDC != _UH.hdcDraw) ||
(_UH.rectReset) ||
(left != _UH.lastLeft) ||
(top != _UH.lastTop) ||
(right != _UH.lastRight) ||
(bottom != _UH.lastBottom))
#endif
{
/********************************************************************/
/* The region clip rectangle has changed, so we change the region */
/* in the screen bitmap DC. */
/********************************************************************/
points[0].x = left;
points[0].y = top;
points[1].x = right;
points[1].y = bottom;
/********************************************************************/
/* Windows requires that the coordinates are in Device space for */
/* its SelectClipRgn call. */
/********************************************************************/
hdc = _UH.hdcDraw;
#if !defined(OS_WINCE) || defined(OS_WINCE_LPTODP)
LPtoDP(hdc, points, 2);
#endif // !defined(OS_WINCE) || defined(OS_WINCE_LPTODP)
if ((left > right) || (top > bottom))
{
/****************************************************************/
/* We get this for SaveScreenBitmap orders. */
/****************************************************************/
TRC_NRM((TB, _T("Null bounds: %d,%d %d,%d"),
left, top, right, bottom));
hrgnRect = CreateRectRgn(0, 0, 0, 0);
}
else
{
hrgnRect = CreateRectRgn( points[0].x,
points[0].y,
points[1].x + 1,
points[1].y + 1 );
}
SelectClipRgn(hdc, hrgnRect);
_UH.lastLeft = left;
_UH.lastTop = top;
_UH.lastRight = right;
_UH.lastBottom = bottom;
_UH.rectReset = FALSE;
#if defined (OS_WINCE)
_UH.validClipDC = _UH.hdcDraw;
#endif
if (hrgnRect != NULL)
DeleteRgn(hrgnRect);
}
TIMERSTOP;
UPDATECOUNTER(FC_UHSETCLIPREGION);
DC_END_FN();
}
/****************************************************************************/
// UH_ProcessBitmapPDU
//
// Unpacks a BitmapPDU.
/****************************************************************************/
HRESULT DCAPI CUH::UH_ProcessBitmapPDU(
TS_UPDATE_BITMAP_PDU_DATA UNALIGNED FAR *pBitmapPDU,
DCUINT dataLength)
{
HRESULT hr = S_OK;
unsigned i;
PBYTE ptr;
PBYTE pdataEnd = (PBYTE)pBitmapPDU + dataLength;
unsigned numRects;
TS_BITMAP_DATA UNALIGNED FAR *pRectangle;
DC_BEGIN_FN("UH_ProcessBitmapPDU");
/************************************************************************/
/* Extract the number of rectangles. */
/************************************************************************/
numRects = (unsigned)pBitmapPDU->numberRectangles;
TRC_NRM((TB, _T("%u rectangles to draw"), numRects));
TRC_ASSERT((numRects > 0), (TB, _T("Invalid rectangle count in BitmapPDU")));
ptr = (PBYTE)(&(pBitmapPDU->rectangle[0]));
for (i = 0; i < numRects; i++) {
TRC_DBG((TB, _T("Process rectangle %u"), i));
// Draw the rectangle.
pRectangle = (TS_BITMAP_DATA UNALIGNED FAR *)ptr;
// SECURITY: 552403
CHECK_READ_N_BYTES(ptr, pdataEnd, sizeof(TS_BITMAP_DATA), hr,
( TB, _T("Bad BitmapPDU length")));
CHECK_READ_N_BYTES(ptr, pdataEnd,
FIELDOFFSET(TS_BITMAP_DATA,bitmapData)+pRectangle->bitmapLength,
hr, ( TB, _T("Bad BitmapPDU length")));
hr = UHProcessBitmapRect(pRectangle);
DC_QUIT_ON_FAIL(hr);
TRC_DBG((TB, _T("bitmap rect: %d %d %d %d"),
pRectangle->destLeft, pRectangle->destTop,
pRectangle->destRight, pRectangle->destBottom));
// Move on to next rectangle.
ptr += FIELDOFFSET(TS_BITMAP_DATA, bitmapData[0]) +
pRectangle->bitmapLength;
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
/* Name: UHProcessBitmapRect */
/* */
/* Purpose: Draw a single BitmapPDU rectangle */
/* */
/* Params: In pRectangle */
/* */
/* Operation: Decompresses the Bitmap PDU (if compressed), then store */
/* the data in the Shadow Bitmap (if present) and display */
/* the relevant area in the Output Window. */
/****************************************************************************/
// SECURITY: Caller must validate that enough data is passed for pRectangle
// and pRectangle->bitmapLength
HRESULT DCINTERNAL CUH::UHProcessBitmapRect(
TS_BITMAP_DATA UNALIGNED FAR *pRectangle)
{
HRESULT hr = S_OK;
DCSIZE bltSize;
HDC hdcDrawOld;
#ifndef OS_WINCE
PBYTE pBitmapBits;
ULONG ulBitmapBitsLen = 0;
#else // OS_WINCE
VOID *pv;
HBITMAP hbm = NULL;
HBITMAP hbmOld;
HDC hdcMem;
HPALETTE hpalOld = NULL;
INT nDibBitsLen = 0;
#endif // OS_WINCE
#ifdef DC_PERF
UTPERFCOUNTER counter1;
UTPERFCOUNTER counter2;
#endif
DC_BEGIN_FN("UHProcessBitmapRect");
TIMERSTART;
// For screen bitmap rect, we either bitblt to the desktop HDC or the shadow
// bitmap HDC, so we need to set the hdcDraw to either shadow bitmap or
// screen desktop. With offscreen, the switch surface PDUs are not sent
// in sync with the screen bitmap rect pdus, so the current hdcDraw may not
// point to shadow bitmap or screen desktop as required by this function.
// What we can do is to save the current hdcDraw and then set it to shadow
// bitmap or screen desktop. Then restore the hdcDraw to the current value
// at the end of this function.
// Save the current hdcDraw
hdcDrawOld = _UH.hdcDraw;
TRC_DBG((TB, _T("bitmapLength %#x"), pRectangle->bitmapLength));
IH_CheckForInput("before decompressing bitmap");
// Set hdcDraw to shadow bitmap or screen desktop appropriately
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
if (!_UH.DontUseShadowBitmap && _UH.hdcShadowBitmap) {
#else
if (_UH.hdcShadowBitmap) {
#endif
_UH.hdcDraw = _UH.hdcShadowBitmap;
}
else {
_UH.hdcDraw = _UH.hdcOutputWindow;
}
// It is possible for us to have failed allocation in UH_Init(), try
// again here if need be.
// It requires a misprediction on every PDU. Can we
// fail init if we don't alloc in UH_Init()?
if (_UH.bitmapDecompressionBuffer == NULL) {
_UH.bitmapDecompressionBufferSize = max(UH_DECOMPRESSION_BUFFER_LENGTH,
UH_CellSizeFromCacheID(_UH.NumBitmapCaches));
_UH.bitmapDecompressionBuffer = (BYTE FAR*)UT_Malloc( _pUt,
_UH.bitmapDecompressionBufferSize );
if (_UH.bitmapDecompressionBuffer == NULL) {
TRC_ERR((TB,_T("Failing to display BitmapPDU - no decomp buffer")));
_UH.bitmapDecompressionBufferSize = 0;
DC_QUIT;
}
}
#ifndef OS_WINCE
if (pRectangle->compressedFlag)
{
TRC_ASSERT(((pRectangle->width * pRectangle->height) <=
UH_DECOMPRESSION_BUFFER_LENGTH),(TB,_T("Bitmap PDU decompressed ")
_T("size too large for internal buffer")));
#ifdef DC_PERF
_pUi->UI_QueryPerformanceCounter(&counter1);
#endif
#ifdef DC_HICOLOR
hr = BD_DecompressBitmap( &(pRectangle->bitmapData[0]),
_UH.bitmapDecompressionBuffer,
pRectangle->bitmapLength,
_UH.bitmapDecompressionBufferSize,
pRectangle->compressedFlag & TS_EXTRA_NO_BITMAP_COMPRESSION_HDR,
(DCUINT8)pRectangle->bitsPerPixel,
pRectangle->width,
pRectangle->height);
#else
hr = BD_DecompressBitmap( &(pRectangle->bitmapData[0]),
_UH.bitmapDecompressionBuffer, pRectangle->bitmapLength,
_UH.bitmapDecompressionBufferSize,
pRectangle->compressedFlag & TS_EXTRA_NO_BITMAP_COMPRESSION_HDR,
(DCUINT8)pRectangle->bitsPerPixel, pRectangle->width,
pRectangle->height);
#endif
DC_QUIT_ON_FAIL(hr);
/********************************************************************/
/* Schedule IH to allow input processing when a lot of drawing is */
/* being processed. */
/********************************************************************/
IH_CheckForInput("after decompressing bitmap");
#ifdef DC_PERF
_pUi->UI_QueryPerformanceCounter(&counter2);
TRC_NRM((TB, _T("Decompress: %u"),
_pUi->UI_PerformanceCounterDiff(&counter1, &counter2) ));
#endif
// Note that ulBitmapBitsLen may be the maxiumum amount of the data in
// the decompression buffer and not how many bits have actually been
// written into that buffer.
pBitmapBits = _UH.bitmapDecompressionBuffer;
ulBitmapBitsLen = _UH.bitmapDecompressionBufferSize;
TRC_DBG((TB, _T("Decompressed bitmap PDU")));
}
else
{
pBitmapBits = &(pRectangle->bitmapData[0]);
ulBitmapBitsLen = pRectangle->bitmapLength;
}
#else // OS_WINCE
/************************************************************************/
/* Windows CE does not support StretchDIBits. Copy the bitmap data */
/* into a DIB Section and BitBlt to the target. */
/************************************************************************/
hdcMem = _UH.hdcMemCached;
if (hdcMem == NULL)
{
TRC_ERR((TB, _T("No memory hdc")));
}
else
{
#ifdef DC_HICOLOR
if (_UH.protocolBpp <= 8)
{
#endif
hpalOld = SelectPalette( hdcMem,
_UH.hpalCurrent,
FALSE );
#ifdef DC_HICOLOR
}
#endif
_UH.bitmapInfo.hdr.biWidth = pRectangle->width;
_UH.bitmapInfo.hdr.biHeight = pRectangle->height;
hbm = CreateDIBSection(hdcMem,
(BITMAPINFO *)&_UH.bitmapInfo.hdr,
#ifdef DC_HICOLOR
_UH.DIBFormat,
#else
DIB_PAL_COLORS,
#endif
&pv,
NULL,
0);
if (hbm == NULL)
{
TRC_ERR((TB, _T("Unable to CreateDIBSection")));
}
else
{
if (pRectangle->compressedFlag)
{
nDibBitsLen = (((_UH.bitmapInfo.hdr.biBitCount *
_UH.bitmapInfo.hdr.biWidth + 31) & ~31) >> 3) *
_UH.bitmapInfo.hdr.biHeight;
#ifdef DC_HICOLOR
hr = BD_DecompressBitmap( &(pRectangle->bitmapData[0]),
(PDCUINT8)pv,
pRectangle->bitmapLength,
nDibBitsLen,
pRectangle->compressedFlag &
TS_EXTRA_NO_BITMAP_COMPRESSION_HDR,
(DCUINT8)pRectangle->bitsPerPixel,
pRectangle->width,
pRectangle->height);
#else
hr = BD_DecompressBitmap( &(pRectangle->bitmapData[0]),
pv,
pRectangle->bitmapLength,
nDibBitsLen,
pRectangle->compressedFlag &
TS_EXTRA_NO_BITMAP_COMPRESSION_HDR,
(DCUINT8)pRectangle->bitsPerPixel,
pRectangle->width,
pRectangle->height );
#endif
DC_QUIT_ON_FAIL(hr);
}
else
{
DC_MEMCPY(pv, &(pRectangle->bitmapData[0]),
pRectangle->bitmapLength);
}
}
}
#endif // OS_WINCE
_UH.bitmapInfo.hdr.biWidth = pRectangle->width;
_UH.bitmapInfo.hdr.biHeight = pRectangle->height;
TRC_NRM((TB, _T("bitmap width %ld, height %ld"), _UH.bitmapInfo.hdr.biWidth,
_UH.bitmapInfo.hdr.biHeight));
/************************************************************************/
/* The rectangle in the PDU is in INCLUSIVE coordinates, so we must */
/* add 1 to get the width and height correct. */
/************************************************************************/
bltSize.width = (pRectangle->destRight - pRectangle->destLeft) + 1;
bltSize.height = (pRectangle->destBottom - pRectangle->destTop) + 1;
/************************************************************************/
/* Ensure that the clip region is reset (clipping is neither required */
/* nor desired). */
/************************************************************************/
UH_ResetClipRegion();
#ifdef DC_PERF
_pUi->UI_QueryPerformanceCounter(&counter1);
#endif
#ifndef OS_WINCE
#ifdef USE_DIBSECTION
// We can only use UHDIBCopyBits if this is a simple copy and the shadow
// bitmap is enabled - ie we're drawing to it.
#ifdef USE_GDIPLUS
if ((_UH.usingDIBSection) && (_UH.hdcDraw == _UH.hdcShadowBitmap) &&
(_UH.shadowBitmapBpp == _UH.protocolBpp))
#else // USE_GDIPLUS
if ((_UH.usingDIBSection) && (_UH.hdcDraw == _UH.hdcShadowBitmap))
#endif // USE_GDIPLUS
{
// Verify that the height, width, and bitcount are valid for a bitmap that
// first into the decompression buffer. Note that ulBitmapBitsLen may be
// the maxiumum amount of the data in the decompression buffer and not
// how many bits have actually been written into that buffer. Thus, while
// we will not read off the end of a buffer, we may read uninitialized
// bitmap data from the buffer.
if (!UHDIBCopyBits(_UH.hdcDraw, pRectangle->destLeft,
pRectangle->destTop, bltSize.width, bltSize.height, 0, 0,
pBitmapBits, ulBitmapBitsLen, (BITMAPINFO *)&(_UH.bitmapInfo.hdr),
_UH.bitmapInfo.bIdentityPalette))
{
TRC_ERR((TB, _T("UHDIBCopyBits failed")));
}
}
else
#endif /* USE_DIBSECTION */
/*if (StretchDIBits( _UH.hdcDraw,
pRectangle->destLeft,
pRectangle->destTop,
bltSize.width,
bltSize.height,
0,
0,
bltSize.width,
bltSize.height,
pBitmapBits,
(BITMAPINFO *)&(_UH.bitmapInfo.hdr),
#ifdef DC_HICOLOR
_UH.DIBFormat,
#else
DIB_PAL_COLORS,
#endif
SRCCOPY ) == 0) */
if (SetDIBitsToDevice( _UH.hdcDraw,
pRectangle->destLeft,
pRectangle->destTop,
bltSize.width,
bltSize.height,
0,
0,
0,
bltSize.height,
pBitmapBits,
(BITMAPINFO *)&(_UH.bitmapInfo.hdr),
#ifdef DC_HICOLOR
_UH.DIBFormat) == 0)
#else
DIB_PAL_COLORS) == 0)
#endif
{
TRC_ERR((TB, _T("StretchDIBits failed")));
}
#else
if ((hdcMem != NULL) && (hbm != NULL))
{
hbmOld = (HBITMAP)SelectObject(hdcMem, hbm);
if (!BitBlt(_UH.hdcDraw,
pRectangle->destLeft,
pRectangle->destTop,
bltSize.width,
bltSize.height,
hdcMem,
0,
0,
SRCCOPY))
{
TRC_ERR((TB, _T("BitBlt failed")));
}
SelectBitmap(hdcMem, hbmOld);
#ifdef DC_HICOLOR
if(_UH.protocolBpp <= 8)
{
#endif
SelectPalette( hdcMem,
hpalOld,
FALSE );
#ifdef DC_HICOLOR
}
#endif
DeleteObject(hbm);
}
#endif // OS_WINCE
#ifdef DC_PERF
_pUi->UI_QueryPerformanceCounter(&counter2);
TRC_NRM((TB, _T("StretchDIBits: %u"),
_pUi->UI_PerformanceCounterDiff(&counter1, &counter2) ));
#endif
#ifdef DC_DEBUG
// Draw hatching over the bitmap data if the option is enabled.
if (_UH.hatchBitmapPDUData)
{
UH_HatchRect( pRectangle->destLeft,
pRectangle->destTop,
pRectangle->destLeft + bltSize.width,
pRectangle->destTop + bltSize.height,
UH_RGB_RED,
UH_BRUSHTYPE_FDIAGONAL);
}
#endif /* DC_DEBUG */
/************************************************************************/
/* If the destination for the drawing we just did was not the output */
/* window, ie the shadow bitmap is enabled, then copy the output to the */
/* output window (screen) now. */
/************************************************************************/
if (_UH.hdcDraw == _UH.hdcShadowBitmap)
{
RECT rect;
rect.left = pRectangle->destLeft;
rect.top = pRectangle->destTop;
rect.right = rect.left + bltSize.width;
rect.bottom = rect.top + bltSize.height;
IH_CheckForInput("before updating screen");
// Ensure that there is no clip region.
SelectClipRgn(_UH.hdcOutputWindow, NULL);
#ifdef SMART_SIZING
if (!_pOp->OP_CopyShadowToDC(_UH.hdcOutputWindow, pRectangle->destLeft,
pRectangle->destTop, bltSize.width, bltSize.height)) {
TRC_ERR((TB, _T("OP_CopyShadowToDC failed")));
}
#else // SMART_SIZING
if (!BitBlt( _UH.hdcOutputWindow,
pRectangle->destLeft,
pRectangle->destTop,
bltSize.width,
bltSize.height,
_UH.hdcShadowBitmap,
pRectangle->destLeft,
pRectangle->destTop,
SRCCOPY ))
{
TRC_ERR((TB, _T("BitBlt failed")));
}
#endif // SMART_SIZING
TRC_DBG((TB, _T("Shadow bitmap updated at %d, %d for %u, %u"),
pRectangle->destLeft,
pRectangle->destTop,
bltSize.width,
bltSize.height));
#ifdef DC_LATENCY
if ((rect.right - rect.left) > 5)
{
/****************************************************************/
/* If this is a reasonably large piece of screen-data then */
/* increment the fake keypress count. */
/****************************************************************/
TRC_DBG((TB, _T("L:%u R:%u T:%u B:%u"),
rect.left,
rect.right,
rect.top,
rect.bottom));
TRC_NRM((TB, _T("Inc fake keypress count")));
_UH.fakeKeypressCount++;
}
#endif /* DC_LATENCY */
}
DC_EXIT_POINT:
// Restore the current hdcDraw to what it had at the beginning of the function
_UH.hdcDraw = hdcDrawOld;
TIMERSTOP;
UPDATECOUNTER(FC_MEM2SCRN_BITBLT);
DC_END_FN();
return hr;
}
/****************************************************************************/
// UH_ProcessOrders
//
// Processes a received set of orders.
/****************************************************************************/
HRESULT DCAPI CUH::UH_ProcessOrders(unsigned NumOrders, BYTE FAR *pOrders,
DCUINT dataLen)
{
HRESULT hr = S_OK;
unsigned i;
unsigned ordersDrawn;
PUH_ORDER pOrder;
BYTE FAR *pEncodedOrder;
DCSIZE desktopSize;
TS_ORDER_HEADER UNALIGNED FAR *pOrderHeader;
unsigned OrderType;
unsigned orderSize;
BYTE FAR *pEnd = pOrders + dataLen;
DC_BEGIN_FN("UH_ProcessOrders");
desktopSize.width = desktopSize.height = 0;
pEncodedOrder = pOrders;
TRC_DBG((TB, _T("Begin replaying %u orders (("), NumOrders));
// If we're using the shadow bitmap, then we need to know the current
// size of the desktop we're blitting around.
if (_UH.hdcOutputWindow != _UH.hdcDraw)
_pUi->UI_GetDesktopSize(&desktopSize);
// Reset the update region to be empty.
#ifdef SMART_SIZING
UHClearUpdateRegion();
#else // SMART_SIZING
SetRectRgn(_UH.hrgnUpdate, 0, 0, 0, 0);
#endif // SMART_SIZING
ordersDrawn = 0;
for (i = 0; i < NumOrders; i++) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof(TS_ORDER_HEADER), hr,
(TB, _T("Bad order header")));
pOrderHeader = (TS_ORDER_HEADER UNALIGNED FAR *)pEncodedOrder;
IH_CheckForInput("before decoding order");
// Decode differently based on primary, secondary, or alternate
// secondary formats.
switch (pOrderHeader->controlFlags & 0x03) {
case 0:
// Currently unused and unsupported.
TRC_ASSERT(((pOrderHeader->controlFlags & 0x03) != 0),
(TB, _T("unsupported control flag encoding type: 0x%02X"),
pOrderHeader->controlFlags));
break;
case 1:
// TS_STANDARD only - primary order.
TRC_NRM((TB, _T("Primary order pEncodedOrder(%p)"),
pEncodedOrder));
hr = _pOd->OD_DecodeOrder(
(PVOID *)&pEncodedOrder, pEnd - pEncodedOrder, &pOrder);
DC_QUIT_ON_FAIL(hr);
if (NULL == pOrder) {
TRC_ERR(( TB, _T("Primary order OD_DecodeOrder failed")));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
// Add the bounds of the order to the Update Region - but
// only if this is used below.
if (_UH.hdcDraw == _UH.hdcShadowBitmap) {
UHAddUpdateRegion(pOrder, _UH.hrgnUpdate);
// If the order threshold has been reached, draw the
// orders now.
ordersDrawn++;
if (ordersDrawn >= _UH.drawThreshold) {
TRC_NRM((TB, _T("Draw threshold reached")));
ordersDrawn = 0;
#ifdef SMART_SIZING
if (!_pOp->OP_CopyShadowToDC(_UH.hdcOutputWindow, 0, 0, desktopSize.width,
desktopSize.height, TRUE)) {
TRC_ERR((TB, _T("OP_CopyShadowToDC failed")));
}
#else // SMART_SIZING
SelectClipRgn(_UH.hdcOutputWindow, _UH.hrgnUpdate);
if (!BitBlt(_UH.hdcOutputWindow, 0, 0,
desktopSize.width, desktopSize.height,
_UH.hdcShadowBitmap, 0, 0, SRCCOPY)) {
TRC_ERR((TB, _T("BitBlt failed")));
}
#endif // SMART_SIZING
// Reset the update region to be empty.
#ifdef SMART_SIZING
UHClearUpdateRegion();
#else // SMART_SIZING
SetRectRgn(_UH.hrgnUpdate, 0, 0, 0, 0);
#endif // SMART_SIZING
}
}
break;
case 2:
#ifdef DRAW_GDIPLUS
// Now we add Gdiplus drawing in alternate secondary order
// So need to this just like primary order.
if (ordersDrawn >= _UH.drawThreshold) {
TRC_NRM((TB, _T("Draw threshold reached")));
ordersDrawn = 0;
#ifdef SMART_SIZING
if (!_pOp->OP_CopyShadowToDC(_UH.hdcOutputWindow, 0, 0, desktopSize.width,
desktopSize.height, TRUE)) {
TRC_ERR((TB, _T("OP_CopyShadowToDC failed")));
}
#else // SMART_SIZING
SelectClipRgn(_UH.hdcOutputWindow, _UH.hrgnUpdate);
if (!BitBlt(_UH.hdcOutputWindow, 0, 0,
desktopSize.width, desktopSize.height,
UH.hdcShadowBitmap, 0, 0, SRCCOPY)) {
TRC_ERR((TB, _T("BitBlt failed")));
}
#endif // SMART_SIZING
// Reset the update region to be empty.
#ifdef SMART_SIZING
UHClearUpdateRegion();
#else // SMART_SIZING
SetRectRgn(_UH.hrgnUpdate, 0, 0, 0, 0);
#endif // SMART_SIZING
}
#endif // DRAW_GDIPLUS
// Alternate secondary order -- TS_SECONDARY without
// TS_STANDARD.
OrderType = (*pEncodedOrder & TS_ALTSEC_ORDER_TYPE_MASK) >>
TS_ALTSEC_ORDER_TYPE_SHIFT;
if (OrderType == TS_ALTSEC_SWITCH_SURFACE) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof(TS_SWITCH_SURFACE_ORDER), hr,
(TB, _T("Bad TS_SWITCH_SURFACE_ORDER")));
TRC_NRM((TB, _T("TS_SWITCH_SURFACE")));
hr = UHSwitchBitmapSurface((PTS_SWITCH_SURFACE_ORDER)
pEncodedOrder, pEnd - pEncodedOrder);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += sizeof(TS_SWITCH_SURFACE_ORDER);
}
else if (OrderType == TS_ALTSEC_CREATE_OFFSCR_BITMAP) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd,
FIELDOFFSET( TS_CREATE_OFFSCR_BITMAP_ORDER, variableBytes ),
hr, (TB, _T("Bad TS_CREATE_OFFSCR_BITMAP_ORDER ")));
TRC_NRM((TB, _T("TS_CREATE_OFFSCR_BITMAP")));
hr = UHCreateOffscrBitmap(
(PTS_CREATE_OFFSCR_BITMAP_ORDER)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
#ifdef DRAW_NINEGRID
else if (OrderType == TS_ALTSEC_STREAM_BITMAP_FIRST) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_STREAM_BITMAP_FIRST_PDU ), hr,
(TB, _T("Bad TS_STREAM_BITMAP_FIRST_PDU ")));
TRC_NRM((TB, _T("TS_STREAM_BITMAP_FIRST")));
hr = UHCacheStreamBitmapFirstPDU(
(PTS_STREAM_BITMAP_FIRST_PDU)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
else if (OrderType == TS_ALTSEC_STREAM_BITMAP_NEXT) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_STREAM_BITMAP_NEXT_PDU), hr,
(TB, _T("Bad TS_STREAM_BITMAP_NEXT_PDU ")));
TRC_NRM((TB, _T("TS_STREAM_BITMAP_NEXT")));
hr = UHCacheStreamBitmapNextPDU(
(PTS_STREAM_BITMAP_NEXT_PDU)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
else if (OrderType == TS_ALTSEC_CREATE_NINEGRID_BITMAP) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_CREATE_NINEGRID_BITMAP_ORDER ), hr,
(TB, _T("Bad TS_CREATE_NINEGRID_BITMAP_ORDER ")));
TRC_NRM((TB, _T("TS_CREATE_NINEGRID_BITMAP")));
hr = UHCreateNineGridBitmap(
(PTS_CREATE_NINEGRID_BITMAP_ORDER)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
#endif
#ifdef DRAW_GDIPLUS
else if (OrderType == TS_ALTSEC_GDIP_CACHE_FIRST) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_DRAW_GDIPLUS_CACHE_ORDER_FIRST ), hr,
(TB, _T("Bad TS_DRAW_GDIPLUS_CACHE_ORDER_FIRST ")));
TRC_NRM((TB, _T("TS_ALTSEC_GDIP_CACHE_FIRST")));
hr = UHDrawGdiplusCachePDUFirst(
(PTS_DRAW_GDIPLUS_CACHE_ORDER_FIRST)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
else if (OrderType == TS_ALTSEC_GDIP_CACHE_NEXT) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_DRAW_GDIPLUS_CACHE_ORDER_NEXT ), hr,
(TB, _T("Bad TS_DRAW_GDIPLUS_CACHE_ORDER_NEXT ")));
TRC_NRM((TB, _T("TS_ALTSEC_GDIP_CACHE_NEXT")));
hr = UHDrawGdiplusCachePDUNext(
(PTS_DRAW_GDIPLUS_CACHE_ORDER_NEXT)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
else if (OrderType == TS_ALTSEC_GDIP_CACHE_END) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_DRAW_GDIPLUS_CACHE_ORDER_END ), hr,
(TB, _T("Bad TS_DRAW_GDIPLUS_CACHE_ORDER_END ")));
TRC_NRM((TB, _T("TS_ALTSEC_GDIP_CACHE_END")));
hr = UHDrawGdiplusCachePDUEnd(
(PTS_DRAW_GDIPLUS_CACHE_ORDER_END)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
else if (OrderType == TS_ALTSEC_GDIP_FIRST) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_DRAW_GDIPLUS_ORDER_FIRST ), hr,
(TB, _T("Bad TS_DRAW_GDIPLUS_ORDER_FIRST ")));
TRC_NRM((TB, _T("TS_ALTSEC_GDIP_FIRST")));
hr = UHDrawGdiplusPDUFirst(
(PTS_DRAW_GDIPLUS_ORDER_FIRST)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
ordersDrawn++;
}
else if (OrderType == TS_ALTSEC_GDIP_NEXT) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_DRAW_GDIPLUS_ORDER_NEXT ), hr,
(TB, _T("Bad TS_DRAW_GDIPLUS_ORDER_NEXT ")));
TRC_NRM((TB, _T("TS_ALTSEC_GDIP_NEXT")));
hr = UHDrawGdiplusPDUNext(
(PTS_DRAW_GDIPLUS_ORDER_NEXT)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
}
else if (OrderType == TS_ALTSEC_GDIP_END) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof( TS_DRAW_GDIPLUS_ORDER_END ), hr,
(TB, _T("Bad TS_DRAW_GDIPLUS_ORDER_END ")));
TRC_NRM((TB, _T("TS_ALTSEC_GDIP_END")));
hr = UHDrawGdiplusPDUEnd(
(PTS_DRAW_GDIPLUS_ORDER_END)pEncodedOrder,
pEnd - pEncodedOrder, &orderSize);
DC_QUIT_ON_FAIL(hr);
pEncodedOrder += orderSize;
ordersDrawn++;
}
#endif // DRAW_GDIPLUS
else {
TRC_ASSERT((OrderType < TS_NUM_ALTSEC_ORDERS),
(TB,_T("Unsupported alt secondary order type %u"),
OrderType));
}
break;
case 3:
{
// Regular secondary order.
unsigned secondaryOrderLength;
TS_SECONDARY_ORDER_HEADER UNALIGNED FAR *pSecondaryOrderHeader;
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof(TS_SECONDARY_ORDER_HEADER), hr,
(TB, _T("Bad TS_SECONDARY_ORDER_HEADER")));
TRC_NRM((TB,_T("Secondary order pEncodedOrder(%p)"),
pEncodedOrder));
pSecondaryOrderHeader =
(TS_SECONDARY_ORDER_HEADER UNALIGNED FAR *)pOrderHeader;
OrderType = pSecondaryOrderHeader->orderType;
#ifdef DC_HICOLOR
//#ifdef DC_DEBUG
// For high color testing, we want to confirm that we've
// received each of the order types.
_pOd->_OD.orderHit[TS_FIRST_SECONDARY_ORDER + OrderType] += 1;
//#endif
#endif
if (OrderType == TS_CACHE_GLYPH) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pEncodedOrder, pEnd, sizeof(TS_CACHE_GLYPH_ORDER_REV2), hr,
(TB, _T("Bad TS_CACHE_GLYPH_ORDER_REV2")));
PTS_CACHE_GLYPH_ORDER_REV2 pOrderRev2 =
(PTS_CACHE_GLYPH_ORDER_REV2)pSecondaryOrderHeader;
TRC_NRM((TB, _T("TS_CACHE_GLYPH")));
if (pOrderRev2->header.extraFlags &
TS_CacheGlyphRev2_Mask) {
// Rev2 glyph order.
orderSize = TS_DECODE_SECONDARY_ORDER_ORDERLENGTH(
(INT16)pOrderRev2->header.orderLength) -
sizeof(TS_CACHE_GLYPH_ORDER_REV2) +
sizeof(pOrderRev2->glyphData);
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrderRev2->glyphData, pEnd, orderSize, hr,
(TB, _T("Bad TS_CACHE_GLYPH secondary order length")));
hr = UHProcessCacheGlyphOrderRev2(
(BYTE)(pOrderRev2->header.extraFlags &
TS_CacheGlyphRev2_CacheID_Mask),
(pOrderRev2->header.extraFlags &
TS_CacheGlyphRev2_cGlyphs_Mask) >> 8,
pOrderRev2->glyphData,
orderSize);
DC_QUIT_ON_FAIL(hr);
}
else {
// We get rev1 glyph order
// SECURITY: 552403
CHECK_READ_N_BYTES(pSecondaryOrderHeader, pEnd, FIELDOFFSET(TS_CACHE_GLYPH_ORDER, glyphData), hr,
(TB, _T("Bad TS_CACHE_GLYPH_ORDER")));
hr = UHProcessCacheGlyphOrder(
(PTS_CACHE_GLYPH_ORDER)pSecondaryOrderHeader, pEnd - (BYTE*)pSecondaryOrderHeader);
DC_QUIT_ON_FAIL(hr);
}
}
else if (OrderType == TS_CACHE_BRUSH) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pSecondaryOrderHeader, pEnd,
FIELDOFFSET(TS_CACHE_BRUSH_ORDER,brushData), hr,
(TB, _T("Bad TS_CACHE_BRUSH_ORDER")));
TRC_NRM((TB, _T("TS_CACHE_BRUSH")));
hr = UHProcessCacheBrushOrder(
(PTS_CACHE_BRUSH_ORDER)pSecondaryOrderHeader, pEnd - (BYTE*)pSecondaryOrderHeader);
DC_QUIT_ON_FAIL(hr);
}
else if (OrderType == TS_CACHE_COLOR_TABLE) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pSecondaryOrderHeader, pEnd,
FIELDOFFSET(TS_CACHE_COLOR_TABLE_ORDER, colorTable), hr,
(TB, _T("Bad TS_CACHE_COLOR_TABLE_ORDER")));
TRC_NRM((TB, _T("TS_CACHE_COLOR_TABLE")));
hr = UHProcessCacheColorTableOrder(
(PTS_CACHE_COLOR_TABLE_ORDER)pSecondaryOrderHeader, pEnd - (BYTE*)pSecondaryOrderHeader );
DC_QUIT_ON_FAIL(hr);
}
else {
TRC_ASSERT((OrderType == TS_CACHE_BITMAP_UNCOMPRESSED ||
OrderType == TS_CACHE_BITMAP_UNCOMPRESSED_REV2 ||
OrderType == TS_CACHE_BITMAP_COMPRESSED ||
OrderType == TS_CACHE_BITMAP_COMPRESSED_REV2),
(TB, _T("Unknown secondary order type (%u)"),
OrderType));
if (OrderType == TS_CACHE_BITMAP_UNCOMPRESSED ||
OrderType == TS_CACHE_BITMAP_UNCOMPRESSED_REV2 ||
OrderType == TS_CACHE_BITMAP_COMPRESSED ||
OrderType == TS_CACHE_BITMAP_COMPRESSED_REV2) {
TRC_NRM((TB, _T("TS_CACHE_BITMAP_XXX")));
hr = UHProcessCacheBitmapOrder(pSecondaryOrderHeader, pEnd - (BYTE*)pSecondaryOrderHeader);
DC_QUIT_ON_FAIL(hr);
}
}
// Need to cast the orderLength to INT16 because compressed
// bitmap data (w/o BC header) can be less than
// TS_SECONDARY_ORDER_LENGTH_FUDGE_FACTOR which makes
// orderLength negative.
secondaryOrderLength = TS_DECODE_SECONDARY_ORDER_ORDERLENGTH(
(short)pSecondaryOrderHeader->orderLength);
pEncodedOrder += secondaryOrderLength;
break;
}
}
}
TRC_DBG((TB, _T("End replaying orders ))")));
if (ordersDrawn != 0) {
ordersDrawn = 0;
#ifdef SMART_SIZING
// Get the OP to use the update region as the clip region.
if (!_pOp->OP_CopyShadowToDC(_UH.hdcOutputWindow, 0, 0, desktopSize.width,
desktopSize.height, TRUE)) {
TRC_ERR((TB, _T("OP_CopyShadowToDC failed")));
}
#else // SMART_SIZING
// Use the update region as the clip region.
SelectClipRgn(_UH.hdcOutputWindow, _UH.hrgnUpdate);
if (!BitBlt(_UH.hdcOutputWindow, 0, 0, desktopSize.width,
desktopSize.height, _UH.hdcShadowBitmap, 0, 0, SRCCOPY))
{
TRC_ERR((TB, _T("BitBlt failed")));
}
#endif // SMART_SIZING
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
/* Function to determine if the supplied color matches any of the VGA */
/* colors at the 'high' end of the supplied color table */
/****************************************************************************/
inline DCBOOL DCINTERNAL CUH::UHIsHighVGAColor(DCUINT8 red,
DCUINT8 green,
DCUINT8 blue)
{
DCBOOL rc = FALSE;
DC_BEGIN_FN("UHIsHighVGAColor");
switch (red)
{
case 255:
{
if ((green == 251) && (blue == 240))
{
rc = TRUE;
break;
}
}
/* NOTE DELIBERATE DROP THROUGH */
case 0:
{
if ((green == 0) || (green == 255))
{
if ((blue == 0) || (blue == 255))
{
rc = TRUE;
}
}
}
break;
case 160:
{
if ((green == 160) && (blue == 164))
{
rc = TRUE;
}
}
break;
case 128:
{
if ((green == 128) && (blue == 128))
{
rc = TRUE;
}
}
break;
default:
{
/* rc = FALSE; */
}
break;
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
/* Name: UHProcessPalettePDU */
/* */
/* Purpose: Processes a received Palette PDU. */
/* */
/* Operation: Creates a Windows palette containing the received colors */
/****************************************************************************/
HRESULT DCAPI CUH::UH_ProcessPalettePDU(
TS_UPDATE_PALETTE_PDU_DATA UNALIGNED FAR *pPalettePDU,
DCUINT dataLength)
{
HRESULT hr = S_OK;
/************************************************************************/
/* logPaletteBuffer is a large structure (~1K), but if we can get away */
/* with it on the stack, its better than having it statically */
/* allocated, or having to do a dynamic allocation. */
/************************************************************************/
DCUINT8 logPaletteBuffer[ sizeof(LOGPALETTE) +
(UH_NUM_8BPP_PAL_ENTRIES *
sizeof(PALETTEENTRY)) ];
PLOGPALETTE pLogPalette;
DCUINT i;
LPPALETTEENTRY pPaletteEntry;
TS_COLOR UNALIGNED FAR *pColor;
HPALETTE hpalNew;
DCINT cacheId;
BYTE * pDataEnd = (PBYTE)pPalettePDU + dataLength;
DC_BEGIN_FN("UHProcessPalettePDU");
#ifdef DC_HICOLOR
if (_UH.protocolBpp > 8)
{
TRC_ERR((TB, _T("Received palette PDU in Hi color mode!")));
DC_QUIT;
}
#endif
#if defined (OS_WINCE)
_UH.validBrushDC = NULL;
#endif
TIMERSTART;
/************************************************************************/
/* Increment our count of received palette PDUs. This is decremented */
/* inside OP_PaletteChanged, where we process the resulting */
/* WM_PALETTECHANGED message. */
/************************************************************************/
_pOp->OP_IncrementPalettePDUCount();
/************************************************************************/
/* Create a new palette from the received packet. */
/* */
/* We cannot just update the current palette colors (using */
/* SetPaletteEntries) because Windows does not handle the repainting */
/* of other local Palette Manager apps correctly (it does not */
/* broadcast the WM_PALETTE.. messages as the palette mapping does */
/* not change). */
/************************************************************************/
/************************************************************************/
/* We currently only support 8bpp protocol data. */
/************************************************************************/
if (UH_NUM_8BPP_PAL_ENTRIES != pPalettePDU->numberColors) {
TRC_ERR(( TB, _T("Invalid palette entries(%u)"),
pPalettePDU->numberColors));
hr = E_TSC_CORE_PALETTE;
DC_QUIT;
}
// SECURITY: 552403
CHECK_READ_N_BYTES(pPalettePDU, pDataEnd,
FIELDOFFSET(TS_UPDATE_PALETTE_PDU_DATA, palette) +
(pPalettePDU->numberColors * sizeof(TS_COLOR)),
hr, ( TB, _T("Invalid palette PDU; size %u"), dataLength ));
/************************************************************************/
/* Set up a logical palette structure containing the new colors. */
/************************************************************************/
pLogPalette = (LPLOGPALETTE)logPaletteBuffer;
pLogPalette->palVersion = UH_LOGPALETTE_VERSION;
pLogPalette->palNumEntries = (DCUINT16)UH_NUM_8BPP_PAL_ENTRIES;
/************************************************************************/
/* The palette PDU contains an array of TS_COLOR structures which each */
/* contain 3 fields (RGB). We have to convert each of these structures */
/* to a PALETTEENTRY structure which has the same 3 fields (RGB) plus */
/* some flags. */
/************************************************************************/
pPaletteEntry = &(pLogPalette->palPalEntry[0]);
pColor = &(pPalettePDU->palette[0]);
for (i = 0; i < UH_NUM_8BPP_PAL_ENTRIES; i++)
{
pPaletteEntry->peRed = pColor->red;
pPaletteEntry->peGreen = pColor->green;
pPaletteEntry->peBlue = pColor->blue;
/********************************************************************/
/* We want the created palette to have the given colors at the */
/* given indices, and for each color to draw with a pixel value */
/* identical to the palette index. This is because we want the */
/* client pixel values to be identical to the server values (if */
/* possible) so that awkward ROPs that rely on the destination */
/* pixel value (DSTBLT rops e.g. 0x55) come out correctly. In */
/* some cases this is simply not possible (e.g. if the client is */
/* not running 8bpp). */
/* */
/* There may be duplicated colors in the palette, so we must */
/* specify PC_NOCOLLAPSE for non-system colors to prevent these */
/* entries from being mapped to identical colors elsewhere in the */
/* palette. */
/********************************************************************/
#ifdef OS_WINCE
pPaletteEntry->peFlags = (BYTE)0;
#else // OS_WINCE
pPaletteEntry->peFlags = (BYTE)
(UH_IS_SYSTEM_COLOR_INDEX(i) ? 0 : PC_NOCOLLAPSE);
#endif
/********************************************************************/
/* We also have to avoid the problem of one of the system colors */
/* mapping onto another color in the palette. We do this by */
/* ensuring that no entries exactly match a system color */
/* Don't need to worry for 4bpp Client. */
/********************************************************************/
if (_pUi->UI_GetColorDepth() != 4)
{
if (!UH_IS_SYSTEM_COLOR_INDEX(i))
{
if (UHIsHighVGAColor(pColor->red,
pColor->green,
pColor->blue))
{
TRC_NRM((TB, _T("Tweaking entry %2x"), i));
UH_TWEAK_COLOR_COMPONENT(pPaletteEntry->peBlue);
}
}
TRC_DBG((TB, _T("%2x: r(%3u) g(%3u) b(%3u) flags(%#x)"),
i,
pPaletteEntry->peRed,
pPaletteEntry->peGreen,
pPaletteEntry->peBlue,
pPaletteEntry->peFlags));
}
_UH.rgbQuadTable[i].rgbRed = pPaletteEntry->peRed;
_UH.rgbQuadTable[i].rgbGreen = pPaletteEntry->peGreen;
_UH.rgbQuadTable[i].rgbBlue = pPaletteEntry->peBlue;
_UH.rgbQuadTable[i].rgbReserved = 0;
pPaletteEntry++;
pColor++;
}
#ifdef DRAW_GDIPLUS
pPaletteEntry = &(pLogPalette->palPalEntry[0]);
if (_UH.pfnGdipPlayTSClientRecord != NULL) {
_UH.pfnGdipPlayTSClientRecord(NULL, DrawTSClientPaletteChange, (BYTE *)pPaletteEntry,
sizeof(PALETTEENTRY) * UH_NUM_8BPP_PAL_ENTRIES, NULL);
}
#endif
// Now copy the RGBquad array into the color table used for brushes.
if (_UH.pColorBrushInfo != NULL) {
memcpy(_UH.pColorBrushInfo->bmi.bmiColors, _UH.rgbQuadTable,
sizeof(_UH.rgbQuadTable));
}
#ifdef USE_DIBSECTION
#ifndef OS_WINCE
/************************************************************************/
/* It is supposed to be legitimate to ignore this on WinCE. WinCE has */
/* simplified things such that when you create a DIB section and use */
/* specify a palette, it actually just uses the palette of the DC into */
/* which you select the DIB. That leaves the expectation that the Blt */
/* operations between those DCs can still be fast. So far that's not */
/* what we've seen. */
/************************************************************************/
if (_UH.usingDIBSection)
{
if (NULL != _UH.hdcShadowBitmap)
{
TRC_NRM((TB, _T("Update the shadow bitmap color table")));
SetDIBColorTable(_UH.hdcShadowBitmap,
0,
UH_NUM_8BPP_PAL_ENTRIES,
(RGBQUAD *)&_UH.rgbQuadTable);
}
if (NULL != _UH.hdcSaveScreenBitmap)
{
TRC_NRM((TB, _T("Update the save screen bitmap color table")));
SetDIBColorTable(_UH.hdcSaveScreenBitmap,
0,
UH_NUM_8BPP_PAL_ENTRIES,
(RGBQUAD *)&_UH.rgbQuadTable);
}
}
#endif
#endif /* USE_DIBSECTION */
// Create the palette.
hpalNew = CreatePalette(pLogPalette);
if (hpalNew == NULL)
{
TRC_ERR((TB, _T("Failed to create palette")));
}
TRC_NRM((TB, _T("Set new palette: %p"), hpalNew));
#ifdef OS_WINCE
// On a fixed palette device don't try to set and realize a palette.
// This only applies to Maxall, always do this on WBT
if (!_UH.paletteIsFixed || CE_CONFIG_WBT == g_CEConfig)
{
#endif
if (_UH.hdcShadowBitmap != NULL)
{
SelectPalette( _UH.hdcShadowBitmap,
hpalNew,
FALSE );
RealizePalette(_UH.hdcShadowBitmap);
}
if (_UH.hdcSaveScreenBitmap != NULL)
{
SelectPalette( _UH.hdcSaveScreenBitmap,
hpalNew,
FALSE );
RealizePalette(_UH.hdcSaveScreenBitmap);
}
if (_UH.hdcOutputWindow != NULL)
{
SelectPalette( _UH.hdcOutputWindow,
hpalNew,
FALSE );
RealizePalette(_UH.hdcOutputWindow);
}
if (_UH.hdcOffscreenBitmap != NULL)
{
SelectPalette( _UH.hdcOffscreenBitmap,
hpalNew,
FALSE );
RealizePalette(_UH.hdcOffscreenBitmap);
}
#ifdef OS_WINCE
}
#endif
if (_UH.hdcBrushBitmap != NULL)
{
SelectPalette( _UH.hdcBrushBitmap,
hpalNew,
FALSE );
RealizePalette(_UH.hdcBrushBitmap);
}
if ((_UH.hpalCurrent != NULL) && (_UH.hpalCurrent != _UH.hpalDefault))
{
TRC_DBG((TB, _T("Delete current palette %p"), _UH.hpalCurrent));
DeletePalette(_UH.hpalCurrent);
}
_UH.hpalCurrent = hpalNew;
// Recalculate the cached Color Table mappings.
for (cacheId = 0; cacheId <= _UH.maxColorTableId; cacheId++)
{
TRC_NRM((TB, _T("Recalculate mapping %u"), cacheId));
UHCalculateColorTableMapping(cacheId);
}
DC_EXIT_POINT:
TIMERSTOP;
UPDATECOUNTER(FC_UHPROCESSPALETTEPDU);
DC_END_FN();
return hr;
}
/****************************************************************************/
// UHUseBrush and UHUseSolidPaletteBrush create the correct brush to use.
// We rely on UHUseTextColor and UseBKColor being called before this routine
// to set up _UH.lastTextColor and _UH.lastBkColor correctly.
/****************************************************************************/
/****************************************************************************/
/* Name: UHUseBrush */
/* */
/* Purpose: Creates and selects a given brush into the current output */
/* DC. */
/* */
/* Params: IN: style - brush style */
/* IN: hatch - brush hatch */
/* IN: color - brush color */
/* IN: colorType - type of color */
/* IN: extra - array of bitmap bits for custom brushes */
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHUseBrush(
unsigned style,
unsigned hatch,
DCCOLOR color,
unsigned colorType,
BYTE extra[7] )
{
HRESULT hr = S_OK;
HBRUSH hBrushNew = NULL;
UINT32 iBitmapFormat;
BOOL bUsingPackedDib = FALSE;
#ifdef DC_HICOLOR
PVOID pDib = NULL;
#endif
DC_BEGIN_FN("UHUseBrush");
#if defined (OS_WINCE)
COLORREF colorref = UHGetColorRef(color, colorType, this);
if ((style != _UH.lastLogBrushStyle) ||
(hatch != _UH.lastLogBrushHatch) ||
(colorref != _UH.lastLogBrushColorRef) ||
(DC_MEMCMP(extra, _UH.lastLogBrushExtra, sizeof(_UH.lastLogBrushExtra))) ||
(_UH.validBrushDC != _UH.hdcDraw) ||
(((_UH.lastLogBrushStyle == BS_PATTERN) ||
(_UH.lastLogBrushStyle & TS_CACHED_BRUSH)) &&
((_UH.lastTextColor != _UH.lastBrushTextColor) ||
(_UH.lastBkColor != _UH.lastBrushBkColor) ||
(_UH.validTextColorDC != _UH.hdcDraw) ||
(_UH.validBkColorDC != _UH.hdcDraw))))
#endif
{
_UH.lastLogBrushStyle = style;
_UH.lastLogBrushHatch = hatch;
#if defined (OS_WINCE)
_UH.lastLogBrushColorRef = colorref;
#else
_UH.lastLogBrushColor = color;
#endif
memcpy(_UH.lastLogBrushExtra, extra, sizeof(_UH.lastLogBrushExtra));
#if defined (OS_WINCE)
_UH.validBrushDC = _UH.hdcDraw;
#endif
if ((style & TS_CACHED_BRUSH) || (style == BS_PATTERN))
{
BYTE patternData[64];
// Pull the brush from the cache if supplied.
if (style & TS_CACHED_BRUSH) {
iBitmapFormat = style & 0x0F;
switch (iBitmapFormat) {
// monochrome brush (BMF_1BPP)
case 1:
hr = UHIsValidMonoBrushCacheIndex(hatch);
DC_QUIT_ON_FAIL(hr);
#ifndef OS_WINCE
SetBitmapBits(_UH.bmpMonoPattern, 8*2,
_UH.pMonoBrush[hatch].data);
#else
DeleteObject(_UH.bmpMonoPattern);
_UH.bmpMonoPattern = CreateBitmap(8,8,1,1,
_UH.pMonoBrush[hatch].data);
#endif
_UH.bmpPattern = _UH.bmpMonoPattern;
break;
// 256 color brush (BMF_8BPP)
case 3:
hr = UHIsValidColorBrushCacheIndex(hatch);
DC_QUIT_ON_FAIL(hr);
// set up the packed DIB
memcpy(_UH.pColorBrushInfo->bytes,
_UH.pColorBrush[hatch].data,
UH_COLOR_BRUSH_SIZE);
_UH.pColorBrushInfo->bmi.bmiHeader.biBitCount = 8;
_UH.bmpPattern = NULL;
#ifdef DC_HICOLOR
pDib = _UH.pColorBrushInfo;
#endif
bUsingPackedDib = TRUE;
break;
#ifdef DC_HICOLOR
// 16bpp brush (BMF_16BPP)
case 4:
hr = UHIsValidColorBrushCacheIndex(hatch);
DC_QUIT_ON_FAIL(hr);
_UH.pHiColorBrushInfo->bmiHeader.biBitCount = 16;
if (_UH.protocolBpp == 16)
{
// set up the bmp format to use
_UH.pHiColorBrushInfo->bmiHeader.biClrUsed = 3;
_UH.pHiColorBrushInfo->bmiHeader.biCompression =
BI_BITFIELDS;
// set up the packed DIB
memcpy(_UH.pHiColorBrushInfo->bytes,
_UH.pColorBrush[hatch].data,
UH_COLOR_BRUSH_SIZE_16);
}
else
{
// set up the bmp format to use
_UH.pHiColorBrushInfo->bmiHeader.biClrUsed = 0;
_UH.pHiColorBrushInfo->bmiHeader.biCompression =
BI_RGB;
// set up the packed DIB, overwriting the unused color
// masks
memcpy(_UH.pHiColorBrushInfo->bmiColors,
_UH.pColorBrush[hatch].data,
UH_COLOR_BRUSH_SIZE_16);
}
_UH.bmpPattern = NULL;
pDib = _UH.pHiColorBrushInfo;
bUsingPackedDib = TRUE;
break;
// 24bpp brush (BMF_24BPP)
case 5:
hr = UHIsValidColorBrushCacheIndex(hatch);
DC_QUIT_ON_FAIL(hr);
// set up the packed DIB
memcpy(_UH.pHiColorBrushInfo->bytes,
_UH.pColorBrush[hatch].data,
UH_COLOR_BRUSH_SIZE_24);
_UH.pHiColorBrushInfo->bmiHeader.biBitCount = 24;
_UH.bmpPattern = NULL;
pDib = _UH.pHiColorBrushInfo;
bUsingPackedDib = TRUE;
break;
#endif
default:
_UH.bmpPattern = NULL;
TRC_ASSERT((iBitmapFormat == 1) ||
(iBitmapFormat == 3),
(TB, _T("Invalid cached brush depth: %ld cacheId: %u"),
iBitmapFormat, hatch));
}
}
/************************************************************/
/* Place the bitmap bits into an array of bytes in the */
/* correct form for SetBitmapBits which uses 16 bits per */
/* scanline. */
/************************************************************/
else {
patternData[14] = (DCUINT8)hatch;
patternData[12] = extra[0];
patternData[10] = extra[1];
patternData[8] = extra[2];
patternData[6] = extra[3];
patternData[4] = extra[4];
patternData[2] = extra[5];
patternData[0] = extra[6];
#ifndef OS_WINCE
SetBitmapBits(_UH.bmpMonoPattern, 8*2, patternData);
#else
DeleteObject(_UH.bmpMonoPattern);
_UH.bmpMonoPattern = CreateBitmap(8,8,1,1,patternData);
#endif
_UH.bmpPattern = _UH.bmpMonoPattern;
}
// Mono brush creation
if (_UH.bmpPattern)
{
hBrushNew = CreatePatternBrush(_UH.bmpPattern);
if (hBrushNew != NULL)
{
_UH.lastBrushTextColor = _UH.lastTextColor;
_UH.lastBrushBkColor = _UH.lastBkColor;
}
else
{
TRC_ERR((TB, _T("Failed to create pattern brush")));
}
}
// Color brush creation
else if (bUsingPackedDib) {
#ifdef DC_HICOLOR
hBrushNew = CreateDIBPatternBrushPt(pDib, DIB_RGB_COLORS);
#else
hBrushNew = CreateDIBPatternBrushPt(_UH.pColorBrushInfo,
DIB_RGB_COLORS);
#endif
if (hBrushNew != NULL)
{
_UH.lastBrushTextColor = _UH.lastTextColor;
_UH.lastBrushBkColor = _UH.lastBkColor;
}
else
{
TRC_ERR((TB, _T("CreateDIBPatternBrushPt Failed")));
}
}
}
else
{
#ifndef OS_WINCE
// Only allow through those operations we know will succeed. If we
// send any other style of brush, then the hatch will be interpretted
// as a pointer or a handle and can crash GDI32.
// Only allow through what we know is good.
if (BS_SOLID == _UH.lastLogBrushStyle ||
BS_HOLLOW == _UH.lastLogBrushStyle ||
BS_HATCHED == _UH.lastLogBrushStyle ) {
LOGBRUSH logBrush;
logBrush.lbStyle = _UH.lastLogBrushStyle;
logBrush.lbHatch = _UH.lastLogBrushHatch;
logBrush.lbColor = UHGetColorRef(_UH.lastLogBrushColor, colorType, this);
hBrushNew = CreateBrushIndirect(&logBrush);
}
else {
TRC_ABORT((TB,_T("Unsupported brush style: %d"), _UH.lastLogBrushStyle));
hBrushNew = NULL;
hr = E_TSC_CORE_DECODETYPE;
DC_QUIT;
}
#else // OS_WINCE
TRC_ASSERT((_UH.lastLogBrushStyle == BS_SOLID),
(TB,_T("Unsupported brush type %d"), _UH.lastLogBrushStyle));
hBrushNew = CECreateSolidBrush(colorref);
#endif // OS_WINCE
}
if (hBrushNew == NULL)
{
TRC_ERR((TB, _T("Failed to create brush")));
}
else
{
HBRUSH hbrOld;
TRC_DBG((TB, _T("Selecting new brush %p"), hBrushNew));
hbrOld = SelectBrush(_UH.hdcDraw, hBrushNew);
if(hbrOld)
{
#ifndef OS_WINCE
DeleteObject(hbrOld);
#else
CEDeleteBrush(hbrOld);
#endif
}
}
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// UHUseSolidPaletteBrush
//
// Used to switch the main DC to use the given solid color brush.
// We hard-code for 16- or 256-color palettes because that's all we support
// in this version, so why create extra branches?
// Differentiated from UHUseBrush() because solid color brushes are the most
// common (OpaqueRect).
/****************************************************************************/
void DCINTERNAL CUH::UHUseSolidPaletteBrush(DCCOLOR color)
{
HBRUSH hBrushNew;
DC_BEGIN_FN("UHUseSolidPaletteBrush");
#if defined (OS_WINCE)
COLORREF colorref = UHGetColorRef(color, UH_COLOR_PALETTE, this);
if ((_UH.lastLogBrushStyle != BS_SOLID) ||
(_UH.lastLogBrushHatch != 0) ||
(colorref != _UH.lastLogBrushColorRef) ||
(_UH.validBrushDC != _UH.hdcDraw))
#endif
{
_UH.lastLogBrushStyle = BS_SOLID;
_UH.lastLogBrushHatch = 0;
#if defined (OS_WINCE)
_UH.lastLogBrushColorRef = colorref;
#else
_UH.lastLogBrushColor = color;
#endif
memset(_UH.lastLogBrushExtra, 0, sizeof(_UH.lastLogBrushExtra));
#if defined (OS_WINCE)
_UH.validBrushDC = _UH.hdcDraw;
#endif
{
#ifndef OS_WINCE
LOGBRUSH logBrush;
logBrush.lbStyle = _UH.lastLogBrushStyle;
logBrush.lbHatch = _UH.lastLogBrushHatch;
logBrush.lbColor = UHGetColorRef(_UH.lastLogBrushColor,
UH_COLOR_PALETTE, this);
hBrushNew = CreateBrushIndirect(&logBrush);
#else // OS_WINCE
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
// When in multimon and two desktops have different color depths
// glyph color don't look right in 256 color connection
// Here is the temporary solution, need to investigate more later.
// SergeyS: This slows rdp down considerably, and the code is not
// relevant in CE case anyway
// if (_UH.protocolBpp <= 8)
// rgb = GetNearestColor(_UH.hdcDraw, rgb);
#endif //DISABLE_SHADOW_IN_FULLSCREEN
hBrushNew = CECreateSolidBrush(colorref);
#endif // OS_WINCE
}
if (hBrushNew != NULL) {
TRC_DBG((TB, _T("Selecting new brush %p"), hBrushNew));
#ifndef OS_WINCE
DeleteObject(SelectBrush(_UH.hdcDraw, hBrushNew));
#else
CEDeleteBrush(SelectBrush(_UH.hdcDraw, hBrushNew));
#endif
}
else {
TRC_ERR((TB, _T("Failed to create brush")));
}
}
DC_END_FN();
}
/****************************************************************************/
/* Name: UHUsePen */
/* */
/* Purpose: Creates and selects a given pen into the current output DC. */
/* */
/* Params: IN: style - pen style */
/* IN: width - pen width in pixels */
/* IN: color - pen color */
/* IN: colorType - type of color */
/****************************************************************************/
inline void DCINTERNAL CUH::UHUsePen(
unsigned style,
unsigned width,
DCCOLOR color,
unsigned colorType)
{
HPEN hPenNew;
HPEN hPenOld;
COLORREF rgb;
DC_BEGIN_FN("UHUsePen");
rgb = UHGetColorRef(color, colorType, this);
#if defined (OS_WINCE)
if ((style != _UH.lastPenStyle) ||
(rgb != _UH.lastPenColor) ||
(width != _UH.lastPenWidth) ||
(_UH.validPenDC != _UH.hdcDraw))
#endif
{
hPenNew = CreatePen(style, width, rgb);
hPenOld = SelectPen(_UH.hdcDraw, hPenNew);
if(hPenOld)
{
DeleteObject(hPenOld);
}
_UH.lastPenStyle = style;
_UH.lastPenColor = rgb;
_UH.lastPenWidth = width;
#if defined (OS_WINCE)
_UH.validPenDC = _UH.hdcDraw;
#endif
}
DC_END_FN();
}
/****************************************************************************/
/* Name: UHResetDCState */
/* */
/* Purpose: Ensures that the output DC's state matches the _UH.last... */
/* variables. */
/****************************************************************************/
void DCINTERNAL CUH::UHResetDCState()
{
DCCOLOR colorWhite = {0xFF,0xFF,0xFF};
BYTE brushExtra[7] = {0,0,0,0,0,0,0};
#if !defined(OS_WINCE) || defined(OS_WINCE_TEXTALIGN)
unsigned textAlign;
#endif // !defined(OS_WINCE) || defined(OS_WINCE_TEXTALIGN)
DC_BEGIN_FN("UHResetDCState");
/************************************************************************/
/* We ensure that the values within the output DC match our _UH.last... */
/* variables by setting a value into the _UH.last... variable directly, */
/* then setting a different value indirectly using the appropriate */
/* function. This forces the new value to be selected into the DC and */
/* the _UH.last... variable and the DC are guaranteed to be in sync. */
/************************************************************************/
/************************************************************************/
/* Background color. */
/************************************************************************/
_UH.lastBkColor = 0;
UHUseBkColor(colorWhite, UH_COLOR_RGB, this);
/************************************************************************/
/* Text color. */
/************************************************************************/
_UH.lastTextColor = 0;
UHUseTextColor(colorWhite, UH_COLOR_RGB, this);
/************************************************************************/
/* Background mode. */
/************************************************************************/
_UH.lastBkMode = TRANSPARENT;
UHUseBkMode(OPAQUE, this);
/************************************************************************/
/* ROP2. */
/************************************************************************/
_UH.lastROP2 = R2_BLACK;
UHUseROP2(R2_COPYPEN, this);
/************************************************************************/
/* Brush origin. */
/************************************************************************/
UHUseBrushOrg(0, 0, this);
/************************************************************************/
/* Pen. */
/************************************************************************/
_UH.lastPenStyle = PS_DASH;
_UH.lastPenWidth = 2;
_UH.lastPenColor = 0;
UHUsePen(PS_SOLID, 1, colorWhite, UH_COLOR_RGB);
/************************************************************************/
/* Brush. */
/************************************************************************/
_UH.lastLogBrushStyle = BS_NULL;
#if ! defined (OS_WINCE)
_UH.lastLogBrushHatch = HS_VERTICAL;
_UH.lastLogBrushColor.u.rgb.red = 0;
_UH.lastLogBrushColor.u.rgb.green = 0;
_UH.lastLogBrushColor.u.rgb.blue = 0;
#else
_UH.lastLogBrushHatch = 1; // This does not exist - we are just resetting the brush
_UH.lastLogBrushColorRef = 0;
#endif
_UH.lastBrushBkColor = 0;
_UH.lastBrushTextColor = 0;
// SECURITY: not checking return code, hatch value will be correct here
UHUseBrush(BS_SOLID,
#if ! defined (OS_WINCE)
HS_HORIZONTAL,
#else
0,
#endif
colorWhite, UH_COLOR_RGB, brushExtra);
/************************************************************************/
/* All fonts are sent with baseline alignment - so set this mode here. */
/************************************************************************/
#if !defined(OS_WINCE) || defined(OS_WINCE_TEXTALIGN)
textAlign = GetTextAlign(_UH.hdcDraw);
textAlign &= ~TA_TOP;
textAlign |= TA_BASELINE;
SetTextAlign(_UH.hdcDraw, textAlign);
#endif // !defined(OS_WINCE) || defined(OS_WINCE_TEXTALIGN)
/************************************************************************/
/* Clip region. */
/* */
/* Force it to be reset. */
/************************************************************************/
_UH.rectReset = FALSE;
UH_ResetClipRegion();
DC_END_FN();
}
/****************************************************************************/
/* Name: UHProcessCacheBitmapOrder */
/* */
/* Purpose: Processes a received CacheBitmap order by storing the */
/* bitmap data in the local cache. */
/****************************************************************************/
inline unsigned Decode2ByteField(PBYTE *ppDecode)
{
unsigned Val;
// The first bit of the first byte indicates if the field is 1 byte or 2
// bytes -- 0 if 1 byte.
if (!(**ppDecode & 0x80)) {
Val = **ppDecode;
(*ppDecode)++;
}
else {
Val = ((**ppDecode & 0x7F) << 8) + *(*ppDecode + 1);
(*ppDecode) += 2;
}
return Val;
}
inline long Decode4ByteField(PBYTE *ppDecode)
{
long Val;
unsigned FieldLength;
// The next 2 bits of the first byte indicate the field length --
// 00=1 byte, 01=2 bytes, 10=3 bytes, 11=4 bytes.
FieldLength = ((**ppDecode & 0xC0) >> 6) + 1;
switch (FieldLength) {
case 1:
Val = **ppDecode & 0x3F;
break;
case 2:
Val = ((**ppDecode & 0x3F) << 8) + *(*ppDecode + 1);
break;
case 3:
Val = ((**ppDecode & 0x3F) << 16) + (*(*ppDecode + 1) << 8) +
*(*ppDecode + 2);
break;
default:
Val = ((**ppDecode & 0x3F) << 24) + (*(*ppDecode + 1) << 16) +
(*(*ppDecode + 2) << 8) + *(*ppDecode + 3);
break;
}
*ppDecode += FieldLength;
return Val;
}
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/**************************************************************************/
// UHSendBitmapCacheErrorPDU
//
// Send an bitmap error pdu for the cache with cacheId
// request the server to clear the cache
/**************************************************************************/
BOOL DCINTERNAL CUH::UHSendBitmapCacheErrorPDU(ULONG_PTR cacheId)
{
unsigned short PktLen;
SL_BUFHND hBuffer;
PTS_BITMAPCACHE_ERROR_PDU pBitmapCacheErrorPDU;
BOOL rc = FALSE;
//
// CD passes params as PVOID
//
DC_BEGIN_FN("UHSendBitmapCacheErrorPDU");
PktLen = sizeof(TS_BITMAPCACHE_ERROR_PDU);
if (_pSl->SL_GetBuffer(PktLen, (PPDCUINT8)&pBitmapCacheErrorPDU, &hBuffer)) {
TRC_NRM((TB, _T("Successfully alloc'd bitmap cache error packet")));
pBitmapCacheErrorPDU->shareDataHeader.shareControlHeader.pduType =
TS_PDUTYPE_DATAPDU | TS_PROTOCOL_VERSION;
pBitmapCacheErrorPDU->shareDataHeader.shareControlHeader.totalLength = PktLen;
pBitmapCacheErrorPDU->shareDataHeader.shareControlHeader.pduSource =
_pUi->UI_GetClientMCSID();
pBitmapCacheErrorPDU->shareDataHeader.shareID = _pUi->UI_GetShareID();
pBitmapCacheErrorPDU->shareDataHeader.pad1 = 0;
pBitmapCacheErrorPDU->shareDataHeader.streamID = TS_STREAM_LOW;
pBitmapCacheErrorPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_BITMAPCACHE_ERROR_PDU;
pBitmapCacheErrorPDU->shareDataHeader.generalCompressedType = 0;
pBitmapCacheErrorPDU->shareDataHeader.generalCompressedLength = 0;
pBitmapCacheErrorPDU->NumInfoBlocks = 1;
pBitmapCacheErrorPDU->Pad1 = 0;
pBitmapCacheErrorPDU->Pad2 = 0;
pBitmapCacheErrorPDU->Info[0].CacheID = (TSUINT8) cacheId;
pBitmapCacheErrorPDU->Info[0].bFlushCache = 1;
pBitmapCacheErrorPDU->Info[0].bNewNumEntriesValid = 0;
pBitmapCacheErrorPDU->Info[0].Pad1 = 0;
pBitmapCacheErrorPDU->Info[0].Pad2 = 0;
pBitmapCacheErrorPDU->Info[0].NewNumEntries = 0;
TRC_NRM((TB, _T("Send bitmap cache error PDU")));
_pSl->SL_SendPacket((PDCUINT8)pBitmapCacheErrorPDU, PktLen, RNS_SEC_ENCRYPT,
hBuffer, _pUi->UI_GetClientMCSID(), _pUi->UI_GetChannelID(), TS_MEDPRIORITY);
rc = TRUE;
}
else {
TRC_ALT((TB, _T("Failed to alloc bitmap cache error packet")));
pBitmapCacheErrorPDU = NULL;
}
DC_END_FN();
return rc;
}
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/**************************************************************************/
// UHSendOffscrCacheErrorPDU
//
// Send an offscreen cache error pdu to request the server to disable
// offscreen rendering and refresh the screen
/**************************************************************************/
BOOL DCINTERNAL CUH::UHSendOffscrCacheErrorPDU(unsigned unused)
{
unsigned short PktLen;
SL_BUFHND hBuffer;
PTS_OFFSCRCACHE_ERROR_PDU pOffscrCacheErrorPDU;
BOOL rc = FALSE;
UNREFERENCED_PARAMETER(unused);
DC_BEGIN_FN("UHSendOffscrCacheErrorPDU");
if (!_UH.sendOffscrCacheErrorPDU) {
PktLen = sizeof(TS_OFFSCRCACHE_ERROR_PDU);
if (_pSl->SL_GetBuffer(PktLen, (PPDCUINT8)&pOffscrCacheErrorPDU, &hBuffer)) {
TRC_NRM((TB, _T("Successfully alloc'd offscreen cache error packet")));
pOffscrCacheErrorPDU->shareDataHeader.shareControlHeader.pduType =
TS_PDUTYPE_DATAPDU | TS_PROTOCOL_VERSION;
pOffscrCacheErrorPDU->shareDataHeader.shareControlHeader.totalLength = PktLen;
pOffscrCacheErrorPDU->shareDataHeader.shareControlHeader.pduSource =
_pUi->UI_GetClientMCSID();
pOffscrCacheErrorPDU->shareDataHeader.shareID = _pUi->UI_GetShareID();
pOffscrCacheErrorPDU->shareDataHeader.pad1 = 0;
pOffscrCacheErrorPDU->shareDataHeader.streamID = TS_STREAM_LOW;
pOffscrCacheErrorPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_OFFSCRCACHE_ERROR_PDU;
pOffscrCacheErrorPDU->shareDataHeader.generalCompressedType = 0;
pOffscrCacheErrorPDU->shareDataHeader.generalCompressedLength = 0;
pOffscrCacheErrorPDU->flags = 1;
TRC_NRM((TB, _T("Send offscreen cache error PDU")));
_pSl->SL_SendPacket((PDCUINT8)pOffscrCacheErrorPDU, PktLen, RNS_SEC_ENCRYPT,
hBuffer, _pUi->UI_GetClientMCSID(), _pUi->UI_GetChannelID(), TS_MEDPRIORITY);
_UH.sendOffscrCacheErrorPDU = TRUE;
rc = TRUE;
} else {
TRC_ALT((TB, _T("Failed to alloc offscreen cache error packet")));
pOffscrCacheErrorPDU = NULL;
}
}
DC_END_FN();
return rc;
}
#ifdef DRAW_NINEGRID
/**************************************************************************/
// UHSendDrawNineGridErrorPDU
//
// Send an drawninegrid cache error pdu to request the server to disable
// drawninegrid rendering and refresh the screen
/**************************************************************************/
BOOL DCINTERNAL CUH::UHSendDrawNineGridErrorPDU(unsigned unused)
{
unsigned short PktLen;
SL_BUFHND hBuffer;
PTS_DRAWNINEGRID_ERROR_PDU pDNGErrorPDU;
BOOL rc = FALSE;
UNREFERENCED_PARAMETER(unused);
DC_BEGIN_FN("UHSendDrawNineGridErrorPDU");
if (!_UH.sendDrawNineGridErrorPDU) {
PktLen = sizeof(TS_DRAWNINEGRID_ERROR_PDU);
if (_pSl->SL_GetBuffer(PktLen, (PPDCUINT8)&pDNGErrorPDU, &hBuffer)) {
TRC_NRM((TB, _T("Successfully alloc'd drawninegrid error packet")));
pDNGErrorPDU->shareDataHeader.shareControlHeader.pduType =
TS_PDUTYPE_DATAPDU | TS_PROTOCOL_VERSION;
pDNGErrorPDU->shareDataHeader.shareControlHeader.totalLength = PktLen;
pDNGErrorPDU->shareDataHeader.shareControlHeader.pduSource =
_pUi->UI_GetClientMCSID();
pDNGErrorPDU->shareDataHeader.shareID = _pUi->UI_GetShareID();
pDNGErrorPDU->shareDataHeader.pad1 = 0;
pDNGErrorPDU->shareDataHeader.streamID = TS_STREAM_LOW;
pDNGErrorPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_DRAWNINEGRID_ERROR_PDU;
pDNGErrorPDU->shareDataHeader.generalCompressedType = 0;
pDNGErrorPDU->shareDataHeader.generalCompressedLength = 0;
pDNGErrorPDU->flags = 1;
TRC_NRM((TB, _T("Send drawninegrid error PDU")));
_pSl->SL_SendPacket((PDCUINT8)pDNGErrorPDU, PktLen, RNS_SEC_ENCRYPT,
hBuffer, _pUi->UI_GetClientMCSID(), _pUi->UI_GetChannelID(), TS_MEDPRIORITY);
_UH.sendDrawNineGridErrorPDU = TRUE;
rc = TRUE;
} else {
TRC_ALT((TB, _T("Failed to alloc drawninegrid error packet")));
pDNGErrorPDU = NULL;
}
}
DC_END_FN();
return rc;
}
#endif
#ifdef DRAW_GDIPLUS
/**************************************************************************/
// UHSendDrawGdiplusErrorPDU
//
// Send an drawgdiplus cache error pdu to request the server to disable
// drawgdiplus rendering and refresh the screen
/**************************************************************************/
BOOL DCINTERNAL CUH::UHSendDrawGdiplusErrorPDU(unsigned unused)
{
unsigned short PktLen;
SL_BUFHND hBuffer;
PTS_DRAWGDIPLUS_ERROR_PDU pGdipErrorPDU;
BOOL rc = FALSE;
UNREFERENCED_PARAMETER(unused);
DC_BEGIN_FN("UHSendDrawGdiplusErrorPDU");
if (!_UH.fSendDrawGdiplusErrorPDU) {
PktLen = sizeof(TS_DRAWGDIPLUS_ERROR_PDU);
if (_pSl->SL_GetBuffer(PktLen, (PPDCUINT8)&pGdipErrorPDU, &hBuffer)) {
TRC_NRM((TB, _T("Successfully alloc'd drawgdiplus error packet")));
pGdipErrorPDU->shareDataHeader.shareControlHeader.pduType =
TS_PDUTYPE_DATAPDU | TS_PROTOCOL_VERSION;
pGdipErrorPDU->shareDataHeader.shareControlHeader.totalLength = PktLen;
pGdipErrorPDU->shareDataHeader.shareControlHeader.pduSource =
_pUi->UI_GetClientMCSID();
pGdipErrorPDU->shareDataHeader.shareID = _pUi->UI_GetShareID();
pGdipErrorPDU->shareDataHeader.pad1 = 0;
pGdipErrorPDU->shareDataHeader.streamID = TS_STREAM_LOW;
pGdipErrorPDU->shareDataHeader.pduType2 = TS_PDUTYPE2_DRAWGDIPLUS_ERROR_PDU;
pGdipErrorPDU->shareDataHeader.generalCompressedType = 0;
pGdipErrorPDU->shareDataHeader.generalCompressedLength = 0;
pGdipErrorPDU->flags = 1;
TRC_NRM((TB, _T("Send drawgdiplus error PDU")));
_pSl->SL_SendPacket((PDCUINT8)pGdipErrorPDU, PktLen, RNS_SEC_ENCRYPT,
hBuffer, _pUi->UI_GetClientMCSID(), _pUi->UI_GetChannelID(), TS_MEDPRIORITY);
_UH.fSendDrawGdiplusErrorPDU = TRUE;
rc = TRUE;
} else {
TRC_ALT((TB, _T("Failed to alloc drawgdiplus error packet")));
pGdipErrorPDU = NULL;
}
}
DC_END_FN();
return rc;
}
#endif
/**************************************************************************/
// UHCacheBitmap
//
// Depending on whether it is a rev1 or rev2 order, we cache the bitmap
// in memory and save it to disk if it is persistent
/**************************************************************************/
// SECURITY 550811: Caller must verify cacheId and cacheIndex
HRESULT DCINTERNAL CUH::UHCacheBitmap(
UINT cacheId,
UINT32 cacheIndex,
TS_SECONDARY_ORDER_HEADER *pHdr,
PUHBITMAPINFO pBitmapInfo,
PBYTE pBitmapData)
{
HRESULT hr = S_OK;
PUHBITMAPCACHEENTRYHDR pCacheEntryHdr;
BYTE FAR *pCacheEntryData;
DC_BEGIN_FN("UHCacheBitmap");
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// Check if this bitmap should be placed in the bitmap cache or not
// If the noCacheFlag is set, we use the last entry of the bitmapcache
// for this noncachable bitmap for temp storage.
if (pHdr->extraFlags & TS_CacheBitmapRev2_bNotCacheFlag &&
_UH.BitmapCacheVersion > TS_BITMAPCACHE_REV1 ) {
pCacheEntryHdr = &_UH.bitmapCache[cacheId].Header[
_UH.bitmapCache[cacheId].BCInfo.NumEntries];
pCacheEntryData = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(
_UH.bitmapCache[cacheId].BCInfo.NumEntries, cacheId);
goto ProcessBitmapData;
}
if (_UH.bitmapCache[cacheId].BCInfo.bSendBitmapKeys) {
ULONG memEntry;
PUHBITMAPCACHEPTE pPTE;
// The persistent key for this cache is set. So we need to update
// the page table as well as cache the bitmap into memory
pPTE = &(_UH.bitmapCache[cacheId].PageTable.PageEntries[cacheIndex]);
TRC_NRM((TB,_T("K1: 0x%x K2: 0x%x (w/h %d,%d)"),
pBitmapInfo->Key1,
pBitmapInfo->Key2,
pBitmapInfo->bitmapWidth,
pBitmapInfo->bitmapHeight ));
#ifdef DC_DEBUG
if (pPTE->bmpInfo.Key1 != 0 && pPTE->bmpInfo.Key2 != 0) {
// Server side eviction.
UHCacheEntryEvictedFromDisk((unsigned)cacheId, cacheIndex);
}
#endif
if (pPTE->iEntryToMem < _UH.bitmapCache[cacheId].BCInfo.NumEntries) {
// we are evicting an entry that are already in memory,
// so we can simply use the memory to cache our bitmap
memEntry = pPTE->iEntryToMem;
}
else {
// we need to find a free cache memory or evict an existing
// entry so that we can cache this entry in memory
TRC_ASSERT((pPTE->iEntryToMem == _UH.bitmapCache[cacheId].BCInfo.NumEntries),
(TB, _T("Page Table %d entry %d is broken"), cacheId, cacheIndex));
// see if we can find a free memory entry
memEntry = UHFindFreeCacheEntry(cacheId);
if (memEntry >= _UH.bitmapCache[cacheId].BCInfo.NumEntries) {
// all cache memory entries are full.
// We need to evict an entry from the cache memory
memEntry = UHEvictLRUCacheEntry(cacheId);
TRC_ASSERT((memEntry < _UH.bitmapCache[cacheId].BCInfo.NumEntries),
(TB, _T("MRU list is broken")));
}
}
// update the mru list
UHTouchMRUCacheEntry(cacheId, cacheIndex);
// update the page table entry
(pPTE->bmpInfo).Key1 = pBitmapInfo->Key1;
(pPTE->bmpInfo).Key2 = pBitmapInfo->Key2;
pPTE->iEntryToMem = memEntry;
// Since this bitmap cache is persistent, we need to save this bitmap
// to disk.
// try to save the bitmap on disk
#ifndef VM_BMPCACHE
if (UHSavePersistentBitmap(_UH.bitmapCache[cacheId].PageTable.CacheFileInfo.hCacheFile,
#else
if (UHSavePersistentBitmap(cacheId,
#endif
cacheIndex * (UH_CellSizeFromCacheID(cacheId) + sizeof(UHBITMAPFILEHDR)),
pBitmapData, pHdr->extraFlags & TS_EXTRA_NO_BITMAP_COMPRESSION_HDR, pBitmapInfo)) {
TRC_NRM((TB, _T("bitmap file %s is saved on disk"), _UH.PersistCacheFileName));
}
else {
TRC_ERR((TB, _T("failed to save the bitmap file on disk")));
// if this is the first time we failed to save the bitmap on disk,
// we should display a warning message to the user.
if (!_UH.bWarningDisplayed) {
_UH.bWarningDisplayed = TRUE;
_pCd->CD_DecoupleSimpleNotification(CD_UI_COMPONENT,
_pUi, CD_NOTIFICATION_FUNC(CUI,UI_DisplayBitmapCacheWarning), 0);
}
}
// set where bitmap bits should be located
pCacheEntryHdr = &_UH.bitmapCache[cacheId].Header[memEntry];
#ifdef DC_HICOLOR
pCacheEntryData = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(memEntry, cacheId);
#else
pCacheEntryData = _UH.bitmapCache[cacheId].Entries + memEntry *
UH_CellSizeFromCacheID(cacheId);
#endif
}
else {
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// set where bitmap bits should be locatedvalues
pCacheEntryHdr = &_UH.bitmapCache[cacheId].Header[cacheIndex];
#ifdef DC_HICOLOR
pCacheEntryData = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(cacheIndex, cacheId);
#else
pCacheEntryData = _UH.bitmapCache[cacheId].Entries + cacheIndex *
UH_CellSizeFromCacheID(cacheId);
#endif //DC_HICOLOR
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
}
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
ProcessBitmapData:
// Fill in the bitmap header info for this cache entry
pCacheEntryHdr->bitmapWidth = (DCUINT16)pBitmapInfo->bitmapWidth;
pCacheEntryHdr->bitmapHeight = (DCUINT16)pBitmapInfo->bitmapHeight;
pCacheEntryHdr->hasData = TRUE;
#ifdef DC_HICOLOR
// Calculate the decompressed bitmap length.
pCacheEntryHdr->bitmapLength = pBitmapInfo->bitmapWidth *
pBitmapInfo->bitmapHeight *
_UH.copyMultiplier;
#else
// Calculate the decompressed bitmap length. The bitmap is always at
// 8bpp.
pCacheEntryHdr->bitmapLength = pBitmapInfo->bitmapWidth *
pBitmapInfo->bitmapHeight;
#endif
// Store the bitmap bits in the target cache cell.
if (pHdr->orderType == TS_CACHE_BITMAP_COMPRESSED_REV2 ||
pHdr->orderType == TS_CACHE_BITMAP_COMPRESSED) {
// Decompress the bitmap into the target cache cell.
TRC_NRM((TB, _T("Decompress %u:%u (%u -> %u bytes) (%u x %u)"),
cacheId, cacheIndex, pBitmapInfo->bitmapLength,
pCacheEntryHdr->bitmapLength, pBitmapInfo->bitmapWidth,
pBitmapInfo->bitmapHeight));
if(pCacheEntryHdr->bitmapLength >
(unsigned)UH_CellSizeFromCacheID(cacheId)) {
TRC_ABORT((TB, _T("Bitmap bits too large for cell! (cacheid=%u, len=%u, ")
_T("cell size=%u)"), cacheId, pCacheEntryHdr->bitmapLength,
UH_CellSizeFromCacheID(cacheId)));
hr = E_TSC_CORE_CACHEVALUE;
DC_QUIT;
}
#ifdef DC_HICOLOR
hr = BD_DecompressBitmap(pBitmapData,
pCacheEntryData,
(UINT) pBitmapInfo->bitmapLength,
pCacheEntryHdr->bitmapLength,
pHdr->extraFlags & TS_EXTRA_NO_BITMAP_COMPRESSION_HDR,
(DCUINT8)_UH.protocolBpp,
(DCUINT16)pBitmapInfo->bitmapWidth,
(DCUINT16)pBitmapInfo->bitmapHeight);
#else
hr = BD_DecompressBitmap(pBitmapData, pCacheEntryData,
(UINT) pBitmapInfo->bitmapLength,
pCacheEntryHdr->bitmapLength,
pHdr->extraFlags & TS_EXTRA_NO_BITMAP_COMPRESSION_HDR,
8, pBitmapInfo->bitmapWidth, pBitmapInfo->bitmapHeight);
#endif
DC_QUIT_ON_FAIL(hr);
}
else {
// Copy the data.
TRC_NRM((TB, _T("Memcpy %u:%u (%u bytes) (%u x %u)"),
(unsigned)cacheId, (unsigned)cacheIndex,
(unsigned)pBitmapInfo->bitmapLength,
(unsigned)pBitmapInfo->bitmapWidth,
(unsigned)pBitmapInfo->bitmapHeight));
if(pBitmapInfo->bitmapLength >
(unsigned)UH_CellSizeFromCacheID(cacheId)) {
TRC_ABORT((TB, _T("Bitmap bits too large for cell! (cacheid=%u, len=%u, ")
_T("cell size=%u)"), cacheId, pBitmapInfo->bitmapLength,
UH_CellSizeFromCacheID(cacheId)));
hr = E_TSC_CORE_CACHEVALUE;
DC_QUIT;
}
memcpy(pCacheEntryData, pBitmapData, pBitmapInfo->bitmapLength);
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
inline HRESULT DCINTERNAL CUH::UHProcessCacheBitmapOrder(VOID *pOrder,
DCUINT orderLen)
{
HRESULT hr = S_OK;
UINT CacheID;
UINT32 CacheIndex;
PBYTE pBitmapData;
UHBITMAPINFO BitmapInfo;
TS_SECONDARY_ORDER_HEADER *pHdr;
BYTE * pEnd = (BYTE *)pOrder + orderLen;
DC_BEGIN_FN("UHProcessCacheBitmapOrder");
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, sizeof(TS_SECONDARY_ORDER_HEADER), hr,
(TB, _T("Bad UHProcessCacheBitmapOrder; orderLen %u"), orderLen));
// Decode the order based on whether it's revision 1 or 2. Unpack data
// into the local variables. Note that if we receive a rev2 order
// our global caps must have been set to rev2.
pHdr = (TS_SECONDARY_ORDER_HEADER *)pOrder;
if (pHdr->orderType == TS_CACHE_BITMAP_COMPRESSED_REV2 ||
pHdr->orderType == TS_CACHE_BITMAP_UNCOMPRESSED_REV2)
{
PBYTE pDecode;
TS_CACHE_BITMAP_ORDER_REV2_HEADER *pCacheOrderHdr;
CHECK_READ_N_BYTES(pOrder, pEnd, sizeof(TS_CACHE_BITMAP_ORDER_REV2_HEADER), hr,
(TB, _T("Bad UHProcessCacheBitmapOrder; orderLen %u"), orderLen));
pCacheOrderHdr = (TS_CACHE_BITMAP_ORDER_REV2_HEADER *)pOrder;
TRC_NRM((TB,_T("Rev2 cache bitmap order")));
CacheID = (UINT) (pCacheOrderHdr->header.extraFlags &
TS_CacheBitmapRev2_CacheID_Mask);
// Check that bits per pel is what we expect.
#ifdef DC_HICOLOR
#else
TRC_ASSERT(((pCacheOrderHdr->header.extraFlags &
TS_CacheBitmapRev2_BitsPerPixelID_Mask) ==
TS_CacheBitmapRev2_8BitsPerPel),
(TB,_T("Invalid BitsPerPelID %d"), (pCacheOrderHdr->header.
extraFlags & TS_CacheBitmapRev2_BitsPerPixelID_Mask)));
#endif
// Grab or skip the key depending on the cache settings.
if (pCacheOrderHdr->header.extraFlags &
TS_CacheBitmapRev2_bKeyPresent_Mask)
{
BitmapInfo.Key1 = pCacheOrderHdr->Key1;
BitmapInfo.Key2 = pCacheOrderHdr->Key2;
pDecode = (PDCUINT8)pOrder +
sizeof(TS_CACHE_BITMAP_ORDER_REV2_HEADER);
}
else
{
BitmapInfo.Key1 = BitmapInfo.Key2 = 0;
// Account for the lack of keys in the order sent.
pDecode = (PDCUINT8)pOrder +
sizeof(TS_CACHE_BITMAP_ORDER_REV2_HEADER) -
2 * sizeof(TSUINT32);
}
// Decode the variable-length Width field.
CHECK_READ_N_BYTES(pDecode, pEnd, sizeof(DCUINT16), hr,
( TB, _T("Decode off end of data") ));
BitmapInfo.bitmapWidth = (DCUINT16) Decode2ByteField(&pDecode);
// Height is present only if bHeightSameAsWidth is false.
if (pCacheOrderHdr->header.extraFlags &
TS_CacheBitmapRev2_bHeightSameAsWidth_Mask)
BitmapInfo.bitmapHeight = BitmapInfo.bitmapWidth;
else {
CHECK_READ_N_BYTES(pDecode, pEnd, sizeof(DCUINT16), hr,
( TB, _T("Decode off end of data") ));
BitmapInfo.bitmapHeight = (DCUINT16) Decode2ByteField(&pDecode);
}
// BitmapDataLength.
CHECK_READ_N_BYTES(pDecode, pEnd, 6, hr,
( TB, _T("Decode off end of data") ));
BitmapInfo.bitmapLength = Decode4ByteField(&pDecode);
//TODO: Not currently checking streaming flag or parsing the streaming extended info field.
// CacheIndex.
CacheIndex = Decode2ByteField(&pDecode);
// Calculate pBitmapData.
pBitmapData = pDecode;
}
else
{
TS_CACHE_BITMAP_ORDER *pCacheOrder;
CHECK_READ_N_BYTES(pOrder, pEnd, sizeof(TS_CACHE_BITMAP_ORDER), hr,
( TB, _T("Bad UHProcessCacheBitmapOrder; orderLen %u"), orderLen));
pCacheOrder = (TS_CACHE_BITMAP_ORDER *)pOrder;
TRC_NRM((TB,_T("Rev1 cache bitmap order")));
TRC_ASSERT((pCacheOrder->bitmapBitsPerPel == 8),
(TB, _T("Invalid bitmapBitsPerPel: %u"),
pCacheOrder->bitmapBitsPerPel));
CacheID = pCacheOrder->cacheId;
BitmapInfo.bitmapWidth = pCacheOrder->bitmapWidth;
BitmapInfo.bitmapHeight = pCacheOrder->bitmapHeight;
BitmapInfo.bitmapLength = pCacheOrder->bitmapLength;
CacheIndex = pCacheOrder->cacheIndex;
pBitmapData = pCacheOrder->bitmapData;
// No hash keys in rev 1 order.
BitmapInfo.Key1 = BitmapInfo.Key2 = 0;
}
TRC_DBG((TB, _T("Cache %u, entry %u, dataLength %u"), CacheID, CacheIndex,
BitmapInfo.bitmapLength));
// SECURITY 550811: Cache Index and ID must be verified
hr = UHIsValidBitmapCacheID(CacheID);
DC_QUIT_ON_FAIL(hr);
hr = UHIsValidBitmapCacheIndex(CacheID, CacheIndex);
DC_QUIT_ON_FAIL(hr);
CHECK_READ_N_BYTES(pBitmapData, pEnd, BitmapInfo.bitmapLength, hr,
(TB, _T("Bad UHProcessCacheBitmapOrder; orderLen %u"), orderLen));
// cache this bitmap in cache memory
hr = UHCacheBitmap(CacheID, CacheIndex, pHdr, &BitmapInfo, pBitmapData);
DC_QUIT_ON_FAIL(hr);
#ifdef DC_DEBUG
if (CacheIndex != BITMAPCACHE_WAITING_LIST_INDEX) {
UHCacheDataReceived(CacheID, CacheIndex);
}
#endif /* DC_DEBUG */
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// UHProcessCacheGlyphOrderRev2
//
// Handles new-format cache-glyph order containing tighter order packing.
/****************************************************************************/
inline int Decode2ByteSignedField(PDCUINT8 *ppDecode)
{
int Val;
// The first bit of the first byte indicates if the field is 1 byte or 2
// bytes -- 0 if 1 byte.
if (!(**ppDecode & 0x80)) {
if (!(**ppDecode & 0x40)) {
Val = **ppDecode;
}
else {
Val = - (**ppDecode & 0x3F);
}
(*ppDecode)++;
}
else {
Val = ((**ppDecode & 0x3F) << 8) | *(*ppDecode + 1);
if ((**ppDecode & 0x40)) {
Val = -Val;
}
(*ppDecode) += 2;
}
return Val;
}
HRESULT DCAPI CUH::UHIsValidGlyphCacheIDIndex(unsigned cacheId,
unsigned cacheIndex)
{
HRESULT hr = UHIsValidGlyphCacheID(cacheId);
if (SUCCEEDED(hr)) {
hr = cacheIndex < _pCc->_ccCombinedCapabilities.glyphCacheCapabilitySet.GlyphCache[cacheId].CacheEntries ?
S_OK : E_TSC_CORE_CACHEVALUE;
}
return hr;
}
HRESULT DCAPI CUH::UHIsValidOffsreenBitmapCacheIndex(unsigned cacheIndex)
{
return cacheIndex <
_pCc->_ccCombinedCapabilities.offscreenCapabilitySet.offscreenCacheEntries ?
S_OK : E_TSC_CORE_CACHEVALUE;
}
HRESULT DCINTERNAL CUH::UHProcessCacheGlyphOrderRev2(
BYTE cacheId,
unsigned cGlyphs,
BYTE FAR *pGlyphDataOrder,
unsigned length)
{
HRESULT hr = S_OK;
UINT16 i;
BYTE FAR *pGlyphData;
unsigned cbDataSize, cacheIndex;
HPDCUINT8 pCacheEntryData;
PUHGLYPHCACHEENTRYHDR pCacheEntryHdr;
HPUHGLYPHCACHE pCache;
UINT16 UNALIGNED FAR *pUnicode;
PBYTE pEnd = (BYTE*)pGlyphDataOrder + length;
DC_BEGIN_FN("UHProcessCacheGlyphOrderRev2");
// SECURITY 550811 - must validate cacheIndex
hr = UHIsValidGlyphCacheID(cacheId);
DC_QUIT_ON_FAIL(hr);
pCache = &(_UH.glyphCache[cacheId]);
pGlyphData = pGlyphDataOrder;
pUnicode = (UINT16 UNALIGNED FAR *)(pGlyphData + length - cGlyphs *
sizeof(UINT16));
for (i = 0; i < cGlyphs; i++) {
cacheIndex = *pGlyphData++;
hr = UHIsValidGlyphCacheIDIndex(cacheId, cacheIndex);
DC_QUIT_ON_FAIL(hr);
pCacheEntryHdr = &(pCache->pHdr[cacheIndex]);
pCacheEntryData = &(pCache->pData[cacheIndex * pCache->cbEntrySize]);
// Copy the data.
pCacheEntryHdr->unicode = 0;
CHECK_READ_N_BYTES(pGlyphData, pEnd, 8, hr,
(TB, _T("Read past end of data")));
pCacheEntryHdr->x = Decode2ByteSignedField(&pGlyphData);
pCacheEntryHdr->y = Decode2ByteSignedField(&pGlyphData);
pCacheEntryHdr->cx = Decode2ByteField(&pGlyphData);
pCacheEntryHdr->cy = Decode2ByteField(&pGlyphData);
cbDataSize = (unsigned)(((pCacheEntryHdr->cx + 7) / 8) *
pCacheEntryHdr->cy);
cbDataSize = (cbDataSize + 3) & ~3;
if (cbDataSize > pCache->cbEntrySize) {
TRC_ABORT((TB, _T("Invalid cache cbDataSize: %u, %u"), cbDataSize,
pCache->cbEntrySize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
CHECK_READ_N_BYTES(pGlyphData, pEnd, cbDataSize, hr,
(TB, _T("Read past end of glyph data")));
memcpy(pCacheEntryData, pGlyphData, cbDataSize);
pGlyphData += cbDataSize;
pCacheEntryHdr->unicode = *pUnicode;
pUnicode++;
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
/* Name: UHProcessCacheGlyphOrder */
/* */
/* Purpose: Processes a received CacheGlyphe order by storing the given */
/* glyphs in the requested cache */
/* */
/* Params: pOrder - pointer to the CacheGlyph order */
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHProcessCacheGlyphOrder(PTS_CACHE_GLYPH_ORDER pOrder,
DCUINT orderLen)
{
HRESULT hr = S_OK;
UINT16 i;
unsigned cbDataSize;
PUHGLYPHCACHEENTRYHDR pCacheEntryHdr;
HPDCUINT8 pCacheEntryData;
HPUHGLYPHCACHE pCache;
PTS_CACHE_GLYPH_DATA pGlyphData;
UINT16 UNALIGNED FAR *pUnicode;
BYTE * pEnd = (BYTE *)pOrder + orderLen;
DC_BEGIN_FN("UHProcessCacheGlyphOrder");
hr = UHIsValidGlyphCacheID(pOrder->cacheId);
DC_QUIT_ON_FAIL(hr);
pCache = &(_UH.glyphCache[pOrder->cacheId]);
pGlyphData = pOrder->glyphData;
for (i = 0; i < pOrder->cGlyphs; i++) {
CHECK_READ_N_BYTES(pGlyphData, pEnd, FIELDOFFSET(TS_CACHE_GLYPH_DATA, aj), hr,
( TB, _T("Bad glyph length")));
hr = UHIsValidGlyphCacheIDIndex(pOrder->cacheId, pGlyphData->cacheIndex);
DC_QUIT_ON_FAIL(hr);
cbDataSize = ((pGlyphData->cx + 7) / 8) * pGlyphData->cy;
cbDataSize = (cbDataSize + 3) & ~3;
// SECURITY: 552403
CHECK_READ_N_BYTES(pGlyphData, pEnd, FIELDOFFSET(TS_CACHE_GLYPH_DATA, aj) + cbDataSize, hr,
( TB, _T("Bad glyph length")));
// SECURITY: 552403
if(cbDataSize > pCache->cbEntrySize) {
TRC_ABORT((TB, _T("Invalid cache cbDataSize: %u, %u"), cbDataSize,
pCache->cbEntrySize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
pCacheEntryHdr = &(pCache->pHdr[pGlyphData->cacheIndex]);
pCacheEntryData = &(pCache->pData[pGlyphData->cacheIndex *
pCache->cbEntrySize]);
// Copy the data.
pCacheEntryHdr->unicode = 0;
pCacheEntryHdr->x = pGlyphData->x;
pCacheEntryHdr->y = pGlyphData->y;
pCacheEntryHdr->cx = pGlyphData->cx;
pCacheEntryHdr->cy = pGlyphData->cy;
memcpy(pCacheEntryData, pGlyphData->aj, cbDataSize);
pGlyphData = (PTS_CACHE_GLYPH_DATA)(&pGlyphData->aj[cbDataSize]);
}
pUnicode = (UINT16 UNALIGNED FAR *)pGlyphData;
if (pOrder->header.extraFlags & TS_EXTRA_GLYPH_UNICODE) {
// SECURITY: 552403
CHECK_READ_N_BYTES(pUnicode, pEnd, pOrder->cGlyphs * sizeof(UINT16), hr,
(TB, _T("Unicode data length larger than packet")));
pGlyphData = pOrder->glyphData;
for (i = 0; i < pOrder->cGlyphs; i++) {
pCacheEntryHdr = &(pCache->pHdr[pGlyphData->cacheIndex]);
pCacheEntryHdr->unicode = *pUnicode;
pUnicode++;
cbDataSize = ((pGlyphData->cx + 7) / 8) * pGlyphData->cy;
cbDataSize = (cbDataSize + 3) & ~3;
if (cbDataSize > pCache->cbEntrySize) {
TRC_ABORT((TB, _T("Invalid cache cbDataSize: %u, %u"), cbDataSize,
pCache->cbEntrySize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
pGlyphData = (PTS_CACHE_GLYPH_DATA)(&pGlyphData->aj[cbDataSize]);
}
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
/* Name: UHProcessCacheBrushOrder */
/* */
/* Purpose: Processes a received cached brush order by storing the given */
/* brush in the requested cache */
/* */
/* Params: pOrder - pointer to the CacheBrush order */
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHProcessCacheBrushOrder(
const TS_CACHE_BRUSH_ORDER *pOrder, DCUINT orderLen)
{
HRESULT hr = S_OK;
UINT32 entry;
PBYTE pData;
PBYTE pEnd = (BYTE*)pOrder + orderLen;
DC_BEGIN_FN("UHProcessCacheBrushOrder");
entry = pOrder->cacheEntry;
#if defined (OS_WINCE)
_UH.validBrushDC = NULL;
#endif
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder,pEnd,FIELDOFFSET(TS_CACHE_BRUSH_ORDER,brushData) +
pOrder->iBytes, hr,
(TB, _T("Invalid UHProcessCacheBrushOrder: OrderLen %u"), orderLen ));
switch (pOrder->iBitmapFormat) {
// monochrome brush (BMF_1BPP)
case 1:
hr = UHIsValidMonoBrushCacheIndex(pOrder->cacheEntry);
DC_QUIT_ON_FAIL(hr);
TRC_NRM((TB, _T("Mono Brush[%ld]: format(%ld), cx(%ld), cy(%ld), bytes(%ld)"),
entry, pOrder->iBitmapFormat, pOrder->cx, pOrder->cy, pOrder->iBytes));
_UH.pMonoBrush[entry].hdr.iBitmapFormat = pOrder->iBitmapFormat;
_UH.pMonoBrush[entry].hdr.cx = pOrder->cx;
_UH.pMonoBrush[entry].hdr.cy = pOrder->cy;
_UH.pMonoBrush[entry].hdr.iBytes = pOrder->iBytes;
// reverse the row order since we use SetBitmapBits / CreateBitmap later
memset(_UH.pMonoBrush[entry].data, 0, sizeof(_UH.pMonoBrush[entry].data));
pData = _UH.pMonoBrush[entry].data;
pData[14] = pOrder->brushData[0];
pData[12] = pOrder->brushData[1];
pData[10] = pOrder->brushData[2];
pData[8] = pOrder->brushData[3];
pData[6] = pOrder->brushData[4];
pData[4] = pOrder->brushData[5];
pData[2] = pOrder->brushData[6];
pData[0] = pOrder->brushData[7];
break;
// 256 color brush (BMF_8BPP)
case 3:
{
DCUINT32 i;
hr = UHIsValidColorBrushCacheIndex(pOrder->cacheEntry);
DC_QUIT_ON_FAIL(hr);
TRC_NRM((TB, _T("Color Brush[%ld]: format(%ld), cx(%ld), cy(%ld), bytes(%ld)"),
entry, pOrder->iBitmapFormat, pOrder->cx, pOrder->cy, pOrder->iBytes));
_UH.pColorBrush[entry].hdr.iBitmapFormat = pOrder->iBitmapFormat;
_UH.pColorBrush[entry].hdr.cx = pOrder->cx;
_UH.pColorBrush[entry].hdr.cy = pOrder->cy;
// Unpack the data if necessary
pData = _UH.pColorBrush[entry].data;
if (pOrder->iBytes == 20) {
DCUINT32 currIndex ;
DCUINT8 decode[4], color;
// get the decoding table from the end of the list
for (i = 0; i < 4; i++) {
decode[i] = pOrder->brushData[16 + i];
}
// unpack to 1 pixel per byte
for (i = 0; i < 16; i++) {
currIndex = i * 4;
color = pOrder->brushData[i];
pData[currIndex] = decode[(color & 0xC0) >> 6];
pData[currIndex + 1] = decode[(color & 0x30) >> 4];
pData[currIndex + 2] = decode[(color & 0x0C) >> 2] ;
pData[currIndex + 3] = decode[(color & 0x03)];
}
_UH.pColorBrush[entry].hdr.iBytes = 64;
}
// Else brush is non-encoded byte stream
else {
if (pOrder->iBytes > sizeof(_UH.pColorBrush[entry].data)) {
TRC_ABORT((TB, _T("Invalid color brush iBytes: %u"), pOrder->iBytes));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
_UH.pColorBrush[entry].hdr.iBytes = pOrder->iBytes;
memcpy(pData, pOrder->brushData, pOrder->iBytes);
}
}
break;
#ifdef DC_HICOLOR
// 16bpp brush (BMF_16BPP)
case 4:
{
DCUINT32 i;
hr = UHIsValidColorBrushCacheIndex(pOrder->cacheEntry);
DC_QUIT_ON_FAIL(hr);
TRC_NRM((TB, _T("Color Brush[%ld]: format(%ld), cx(%ld), cy(%ld), bytes(%ld)"),
entry, pOrder->iBitmapFormat, pOrder->cx, pOrder->cy, pOrder->iBytes));
_UH.pColorBrush[entry].hdr.iBitmapFormat = pOrder->iBitmapFormat;
_UH.pColorBrush[entry].hdr.cx = pOrder->cx;
_UH.pColorBrush[entry].hdr.cy = pOrder->cy;
// Unpack the data if necessary
pData = _UH.pColorBrush[entry].data;
if (pOrder->iBytes == 24)
{
DCUINT32 currIndex ;
DCUINT8 color;
PDCUINT16 pIntoData = (PDCUINT16)pData;
UINT16 UNALIGNED *pDecodeTable = (UINT16 UNALIGNED *)&(pOrder->brushData[16]);
// unpack to 2 bytes per pel
for (i = 0; i < 16; i++)
{
color = pOrder->brushData[i];
currIndex = i * 4; // we decode 4 bytes at a pass
pIntoData[currIndex] = pDecodeTable[(color & 0xC0) >> 6];
pIntoData[currIndex + 1] = pDecodeTable[(color & 0x30) >> 4];
pIntoData[currIndex + 2] = pDecodeTable[(color & 0x0C) >> 2] ;
pIntoData[currIndex + 3] = pDecodeTable[(color & 0x03)];
}
_UH.pColorBrush[entry].hdr.iBytes = 128;
}
// Else brush is non-encoded byte stream
else
{
if (pOrder->iBytes > sizeof(_UH.pColorBrush[entry].data)) {
TRC_ABORT((TB, _T("Invalid color brush iBytes: %u"), pOrder->iBytes));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
_UH.pColorBrush[entry].hdr.iBytes = pOrder->iBytes;
memcpy(pData, pOrder->brushData, pOrder->iBytes);
}
}
break;
// 24bpp brush (BMF_24BPP)
case 5:
{
DCUINT32 i;
hr = UHIsValidColorBrushCacheIndex(pOrder->cacheEntry);
DC_QUIT_ON_FAIL(hr);
TRC_NRM((TB, _T("Color Brush[%ld]: format(%ld), cx(%ld), cy(%ld), bytes(%ld)"),
entry, pOrder->iBitmapFormat, pOrder->cx, pOrder->cy, pOrder->iBytes));
_UH.pColorBrush[entry].hdr.iBitmapFormat = pOrder->iBitmapFormat;
_UH.pColorBrush[entry].hdr.cx = pOrder->cx;
_UH.pColorBrush[entry].hdr.cy = pOrder->cy;
// Unpack the data if necessary
pData = _UH.pColorBrush[entry].data;
if (pOrder->iBytes == 28)
{
DCUINT32 currIndex;
RGBTRIPLE * pIntoData = (RGBTRIPLE *)pData;
RGBTRIPLE * pDecodeTable = (RGBTRIPLE *)&(pOrder->brushData[16]);
DCUINT8 color;
// unpack to 3 bytes per pel
for (i = 0; i < 16; i++)
{
color = pOrder->brushData[i];
currIndex = i * 4; // we decode 4 bytes at a pass
pIntoData[currIndex] = pDecodeTable[(color & 0xC0) >> 6];
pIntoData[currIndex + 1] = pDecodeTable[(color & 0x30) >> 4];
pIntoData[currIndex + 2] = pDecodeTable[(color & 0x0C) >> 2];
pIntoData[currIndex + 3] = pDecodeTable[(color & 0x03)];
}
_UH.pColorBrush[entry].hdr.iBytes = 192;
}
// Else brush is non-encoded byte stream
else
{
if (pOrder->iBytes > sizeof(_UH.pColorBrush[entry].data)) {
TRC_ABORT((TB, _T("Invalid color brush iBytes: %u"), pOrder->iBytes));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
_UH.pColorBrush[entry].hdr.iBytes = pOrder->iBytes;
memcpy(pData, pOrder->brushData, pOrder->iBytes);
}
}
break;
#endif
default:
TRC_ASSERT((pOrder->iBitmapFormat == 1) ||
(pOrder->iBitmapFormat == 3),
(TB, _T("Invalid cached brush depth: %ld cacheId: %u"),
pOrder->iBitmapFormat, pOrder->cacheEntry));
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
/* Name: UHProcessCacheColorTableOrder */
/* */
/* Purpose: Processes a received CacheColorTable order by storing the */
/* color table in the local cache. */
/* */
/* Params: pOrder - pointer to the CacheColorTable order */
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHProcessCacheColorTableOrder(
PTS_CACHE_COLOR_TABLE_ORDER pOrder, DCUINT orderLen)
{
HRESULT hr = S_OK;
unsigned i;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
DC_BEGIN_FN("UHProcessCacheColorTableOrder");
// Check that the cache index is within range.
hr = UHIsValidColorTableCacheIndex(pOrder->cacheIndex);
DC_QUIT_ON_FAIL(hr);
// This PDU should only come down in an 8-bit connection.
if (pOrder->numberColors != 256) {
TRC_ABORT((TB, _T("Invalid numberColors: %u"), pOrder->numberColors));
hr = E_TSC_CORE_PALETTE;
DC_QUIT;
}
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, pOrder->numberColors*sizeof(TS_COLOR_QUAD) +
FIELDOFFSET(TS_CACHE_COLOR_TABLE_ORDER, colorTable),
hr, ( TB, _T("Invalid UHProcessCacheColorTableOrder; packet size %u"), orderLen));
// Copy the supplied color table data into the specified color table
// cache entry.
TRC_DBG((TB, _T("Updating color table cache %u"), pOrder->cacheIndex));
for (i = 0; i < UH_NUM_8BPP_PAL_ENTRIES; i++) {
// Definition of TS_RGB_QUAD in T.128 does not match what
// server sends (RGB, should be BGR), so the assignments below are
// swapped around to get the correct result.
_UH.pColorTableCache[pOrder->cacheIndex].rgb[i].rgbtRed =
pOrder->colorTable[i].blue;
_UH.pColorTableCache[pOrder->cacheIndex].rgb[i].rgbtGreen =
pOrder->colorTable[i].green;
_UH.pColorTableCache[pOrder->cacheIndex].rgb[i].rgbtBlue =
pOrder->colorTable[i].red;
// We also have to avoid the problem of one of the system colors
// mapping onto another color in the palette. We do this by
// ensuring that no entries exactly match a system color.
if (!UH_IS_SYSTEM_COLOR_INDEX(i)) {
if (UHIsHighVGAColor(
_UH.pColorTableCache[pOrder->cacheIndex].rgb[i].rgbtRed,
_UH.pColorTableCache[pOrder->cacheIndex].rgb[i].rgbtGreen,
_UH.pColorTableCache[pOrder->cacheIndex].rgb[i].rgbtBlue))
{
UH_TWEAK_COLOR_COMPONENT(
_UH.pColorTableCache[pOrder->cacheIndex].rgb[i].rgbtBlue);
}
}
}
// Track the maximum color table id.
_UH.maxColorTableId = DC_MAX(_UH.maxColorTableId, pOrder->cacheIndex);
// Calculate a mapping table from the received color table to the
// current palette.
UHCalculateColorTableMapping(pOrder->cacheIndex);
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHCreateOffscrBitmap
//
// Purpose: Processes a received CreateOffscrBitmap order by creating the
// offscreen bitmap in the local cache. Returns the size of the
// order to subtract from the encoding stream.
//
// Params: pOrder - pointer to the CreateOffscrBitmap order.
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHCreateOffscrBitmap(
PTS_CREATE_OFFSCR_BITMAP_ORDER pOrder,
DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned cacheId;
HBITMAP hBitmap = NULL;
HDC hdcDesktop = NULL;
DCSIZE desktopSize;
unsigned OrderSize;
PBYTE pEnd = (BYTE*)pOrder + orderLen;
DC_BEGIN_FN("UHCreateOffscrBitmap");
// Get the offscreen bitmap Id
cacheId = pOrder->Flags & 0x7FFF;
hr = UHIsValidOffsreenBitmapCacheIndex(cacheId);
DC_QUIT_ON_FAIL(hr);
// Check if bitmap delete list is appended, if so, delete the bitmaps
// first
if (!(pOrder->Flags & 0x8000)) {
OrderSize = sizeof(TS_CREATE_OFFSCR_BITMAP_ORDER) -
sizeof(pOrder->variableBytes);
}
else {
unsigned numBitmaps, i, bitmapId;
TSUINT16 UNALIGNED *pData;
CHECK_READ_N_BYTES(pOrder->variableBytes, pEnd, sizeof(TSUINT16), hr,
(TB,_T("Not enough data to read number of delete bitmaps")));
numBitmaps = pOrder->variableBytes[0];
pData = (TSUINT16 UNALIGNED *)(pOrder->variableBytes);
pData++;
// SECURITY: 552403
CHECK_READ_N_BYTES(pData, pEnd, sizeof(TSUINT16) * numBitmaps, hr,
( TB, _T("Bad bitmap count %u"), numBitmaps));
for (i = 0; i < numBitmaps; i++) {
bitmapId = *pData++;
hr = UHIsValidOffsreenBitmapCacheIndex(bitmapId);
DC_QUIT_ON_FAIL(hr);
if (_UH.offscrBitmapCache[bitmapId].offscrBitmap != NULL) {
SelectBitmap(_UH.hdcOffscreenBitmap, _UH.hUnusedOffscrBitmap);
DeleteObject(_UH.offscrBitmapCache[bitmapId].offscrBitmap);
_UH.offscrBitmapCache[bitmapId].offscrBitmap = NULL;
}
}
OrderSize = sizeof(TS_CREATE_OFFSCR_BITMAP_ORDER) + sizeof(UINT16) *
numBitmaps;
}
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
(TB, _T("offscreen size invalid: size %u; orderLen %u"),
OrderSize, orderLen));
// Get the current desktop size
_pUi->UI_GetDesktopSize(&desktopSize);
TRC_ASSERT((pOrder->cx <= desktopSize.width) &&
(pOrder->cy <= desktopSize.height),
(TB, _T("invalid offscreen dimensions [cx %u cy %u]")
_T("[width %u height %u]"), pOrder->cx, pOrder->cy,
desktopSize.width, desktopSize.height));
TRC_NRM((TB, _T("Create an offscreen bitmap of size (%d, %d)"), pOrder->cx,
pOrder->cy));
// Delete the bitmap if there is one already exists.
if (_UH.offscrBitmapCache[cacheId].offscrBitmap != NULL) {
// JOYC: TODO: reuse bitmap
//if (UH.offscrBitmapCache[cacheId].cx >= pOrder->cx &&
// UH.offscrBitmapCache[cacheId].cy >= pOrder->cy) {
// return;
//}
SelectBitmap(_UH.hdcOffscreenBitmap, _UH.hUnusedOffscrBitmap);
DeleteObject(_UH.offscrBitmapCache[cacheId].offscrBitmap);
_UH.offscrBitmapCache[cacheId].offscrBitmap = NULL;
}
// Create an offscreen bitmap
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
if (!_UH.DontUseShadowBitmap && (_UH.hdcShadowBitmap != NULL)) {
#else // DISABLE_SHADOW_IN_FULLSCREEN
if (_UH.hdcShadowBitmap != NULL) {
#endif // DISABLE_SHADOW_IN_FULLSCREEN
hBitmap = CreateCompatibleBitmap(_UH.hdcShadowBitmap, pOrder->cx, pOrder->cy);
}
else {
hBitmap = CreateCompatibleBitmap(_UH.hdcOutputWindow, pOrder->cx, pOrder->cy);
}
if (hBitmap != NULL) {
DCCOLOR colorWhite;
// set the unused bitmap
if (_UH.hUnusedOffscrBitmap == NULL)
_UH.hUnusedOffscrBitmap = SelectBitmap(_UH.hdcOffscreenBitmap,
hBitmap);
SelectBitmap(_UH.hdcOffscreenBitmap, hBitmap);
//SetDIBColorTable(UH.hdcOffscreenBitmap,
// 0,
// UH_NUM_8BPP_PAL_ENTRIES,
// (RGBQUAD *)&UH.rgbQuadTable);
if (_UH.protocolBpp <= 8) {
SelectPalette(_UH.hdcOffscreenBitmap, _UH.hpalCurrent, FALSE);
}
colorWhite.u.rgb.blue = 255;
colorWhite.u.rgb.green = 255;
colorWhite.u.rgb.red = 255;
UHUseBkColor(colorWhite, UH_COLOR_RGB, this);
UHUseTextColor(colorWhite, UH_COLOR_RGB, this);
_UH.offscrBitmapCache[cacheId].offscrBitmap = hBitmap;
_UH.offscrBitmapCache[cacheId].cx = pOrder->cx;
_UH.offscrBitmapCache[cacheId].cy = pOrder->cy;
} else {
// Unable to create the bitmap, send error pdu to the server
// to disable offscreen rendering
_UH.offscrBitmapCache[cacheId].offscrBitmap = NULL;
_UH.offscrBitmapCache[cacheId].cx = 0;
_UH.offscrBitmapCache[cacheId].cy = 0;
if (!_UH.sendOffscrCacheErrorPDU)
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendOffscrCacheErrorPDU),
0);
}
*pOrderSize = OrderSize;
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHSwitchBitmapSurface
//
// Purpose: Processes a received SwitchBitmapSurface order by switching the
// drawing surface (hdcDraw) to the right surface.
//
// Params: pOrder - pointer to the SwitchBitmapSurface order
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHSwitchBitmapSurface(PTS_SWITCH_SURFACE_ORDER pOrder,
DCUINT orderLen)
{
HRESULT hr = S_OK;
unsigned cacheId;
HBITMAP hBitmap;
// SECURITY: 552403
DC_IGNORE_PARAMETER(orderLen);
DC_BEGIN_FN("UHSwitchBitmapSurface");
cacheId = pOrder->BitmapID;
if (cacheId != SCREEN_BITMAP_SURFACE) {
hr = UHIsValidOffsreenBitmapCacheIndex(cacheId);
DC_QUIT_ON_FAIL(hr);
}
_UH.lastHDC = _UH.hdcDraw;
if (cacheId != SCREEN_BITMAP_SURFACE) {
hBitmap = _UH.offscrBitmapCache[cacheId].offscrBitmap;
if (hBitmap) {
// Select the bitmap into the offscreen DC
SelectObject(_UH.hdcOffscreenBitmap, hBitmap);
}
else {
// the bitmap is NULL, we use the unused bitmap in the
// mean time
SelectObject(_UH.hdcOffscreenBitmap, _UH.hUnusedOffscrBitmap);
}
_UH.hdcDraw = _UH.hdcOffscreenBitmap;
}
else {
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
if (!_UH.DontUseShadowBitmap && _UH.hdcShadowBitmap) {
#else
if (_UH.hdcShadowBitmap) {
#endif // DISABLE_SHADOW_IN_FULLSCREEN
_UH.hdcDraw = _UH.hdcShadowBitmap;
}
else {
_UH.hdcDraw = _UH.hdcOutputWindow;
}
}
#if defined (OS_WINCE)
_UH.validClipDC = NULL;
_UH.validBkColorDC = NULL;
_UH.validBkModeDC = NULL;
_UH.validROPDC = NULL;
_UH.validTextColorDC = NULL;
_UH.validPenDC = NULL;
_UH.validBrushDC = NULL;
#endif
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
#ifdef DRAW_GDIPLUS
/****************************************************************************/
// Name: UHDrawGdiplusCachePDUFirst
//
// Handle the First PDU of Gdiplus Cache Order
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawGdiplusCachePDUFirst(
PTS_DRAW_GDIPLUS_CACHE_ORDER_FIRST pOrder,
DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PTS_DRAW_GDIPLUS_CACHE_ORDER_FIRST pTSDrawGdiplusCache;
ULONG cbSize, cbTotalSize;
PTSEmfPlusRecord pTSEmfRecord;
BYTE *pCacheData;
TSUINT16 CacheID, CacheType;
TSUINT16 i, RemoveCacheNum = 0, *pRemoveCacheList;
PBYTE pEnd = (BYTE*)pOrder + orderLen;
DC_BEGIN_FN("UHDrawGdiplusCachePDUFirst");
OrderSize = sizeof(TS_DRAW_GDIPLUS_CACHE_ORDER_FIRST) + pOrder->cbSize;
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
(TB, _T("Bad UHDrawGdiplusCachePDUFirst, size %u"), OrderSize));
// Set the return once we know we have enough data. If the alloc fails below, still return
// the packet size so decode continues
*pOrderSize = OrderSize;
if (TS_DRAW_GDIPLUS_SUPPORTED != _pCc->_ccCombinedCapabilities.
drawGdiplusCapabilitySet.drawGdiplusCacheLevel) {
TRC_ERR((TB, _T("Gdip order when gdip not supported")));
DC_QUIT;
}
pTSDrawGdiplusCache = (PTS_DRAW_GDIPLUS_CACHE_ORDER_FIRST)pOrder;
TRC_NRM((TB, _T("Get GdiplusCachePDU, Type: %d, ID: %d"),
pTSDrawGdiplusCache->CacheType, pTSDrawGdiplusCache->CacheID));
cbSize = pTSDrawGdiplusCache->cbSize;
cbTotalSize = pTSDrawGdiplusCache->cbTotalSize;
CacheType = pTSDrawGdiplusCache->CacheType;
if (FAILED(UHIsValidGdipCacheType(CacheType)))
{
// Ignore all failures for invalid cache type
DC_QUIT;
}
CacheID = pTSDrawGdiplusCache->CacheID;
hr = UHIsValidGdipCacheTypeID(CacheType, CacheID);
DC_QUIT_ON_FAIL(hr);
_UH.drawGdipCacheBuffer = (BYTE *)UT_Malloc(_pUt, cbTotalSize);
if (NULL == _UH.drawGdipCacheBuffer) {
TRC_ERR((TB, _T("LocalAlloc failes in UHDrawGdiplusCachePDUFirst")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawGdiplusErrorPDU), 0);
DC_QUIT;
}
_UH.drawGdipCacheBufferOffset = _UH.drawGdipCacheBuffer;
_UH.drawGdipCacheBufferSize = (NULL == _UH.drawGdipCacheBuffer) ? 0 : cbTotalSize;
pCacheData = (BYTE *)(pTSDrawGdiplusCache + 1);
if (pTSDrawGdiplusCache->Flags & TS_GDIPLUS_CACHE_ORDER_REMOVE_CACHEENTRY) {
// This order contain the RemoveCacheList
CHECK_READ_N_BYTES(pCacheData, pEnd, sizeof(TSUINT16), hr,
( TB, _T("not enough data for remove cache entry orders")));
RemoveCacheNum = *(TSUINT16 *)pCacheData;
CHECK_READ_N_BYTES(pCacheData, pEnd, ((RemoveCacheNum + 1) * sizeof(TSUINT16)), hr,
( TB, _T("remove cache entry orders too large")));
pRemoveCacheList = (TSUINT16 *)(pTSDrawGdiplusCache + 1) + 1;
for (i=0; i<RemoveCacheNum; i++) {
hr = UHIsValidGdipCacheTypeID(GDIP_CACHE_OBJECT_IMAGE,
*pRemoveCacheList);
DC_QUIT_ON_FAIL(hr);
UHDrawGdipRemoveImageCacheEntry(*pRemoveCacheList);
TRC_NRM((TB, _T("Remove chche ID %d"), *pRemoveCacheList));
pRemoveCacheList++;
}
pCacheData = (BYTE *)pRemoveCacheList;
if (cbSize <= (sizeof(TSUINT16) * (RemoveCacheNum + 1))) {
TRC_ERR(( TB, _T("DrawDGIPlusCachePDUFirst invalid sizes")
_T("[cbSize %u cbTotalSize %u]"), cbSize, cbTotalSize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
cbSize -= sizeof(TSUINT16) * (RemoveCacheNum + 1);
}
// SECURITY - other size checks above should permit this assert to exist
TRC_ASSERT(_UH.drawGdipCacheBufferSize - (_UH.drawGdipCacheBufferOffset -
_UH.drawGdipCacheBuffer) >= cbSize, (TB, _T("DrawDGIPlusCachePDUFirst size invalid")));
memcpy(_UH.drawGdipCacheBufferOffset, pCacheData, cbSize);
_UH.drawGdipCacheBufferOffset += cbSize;
if (cbSize > cbTotalSize) {
TRC_ERR(( TB, _T("DrawDGIPlusCachePDUFirst invalid sizes")
_T("[cbSize %u cbTotalSize %u]"), cbSize, cbTotalSize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
if (cbSize == cbTotalSize) {
// The cache order only has one block
hr = UHDrawGdiplusCacheData(CacheType, CacheID, cbTotalSize);
DC_QUIT_ON_FAIL(hr);
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHDrawGdiplusCachePDUNext
//
// Handle the subsequent PDU of Gdiplus Cache Order
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawGdiplusCachePDUNext(
PTS_DRAW_GDIPLUS_CACHE_ORDER_NEXT pOrder, DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PTS_DRAW_GDIPLUS_CACHE_ORDER_NEXT pTSDrawGdiplusCache;
ULONG cbSize;
RECT rect;
DrawTSClientEnum drawGdiplusType = DrawTSClientRecord;
PBYTE pEnd = (BYTE*)pOrder + orderLen;
DC_BEGIN_FN("UHDrawGdiplusCachePDUNext");
OrderSize = sizeof(TS_DRAW_GDIPLUS_CACHE_ORDER_NEXT) + pOrder->cbSize;
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
( TB, _T("Bad UHDrawGdiplusCachePDUNext; size %u"), OrderSize));
*pOrderSize = OrderSize;
if (TS_DRAW_GDIPLUS_SUPPORTED != _pCc->_ccCombinedCapabilities.
drawGdiplusCapabilitySet.drawGdiplusCacheLevel) {
TRC_ERR((TB, _T("Gdip order when gdip not supported")));
DC_QUIT;
}
if (NULL == _UH.drawGdipCacheBuffer) {
DC_QUIT;
}
pTSDrawGdiplusCache = (PTS_DRAW_GDIPLUS_CACHE_ORDER_NEXT)pOrder;
cbSize = pTSDrawGdiplusCache->cbSize;
CHECK_WRITE_N_BYTES(_UH.drawGdipCacheBufferOffset, _UH.drawGdipCacheBuffer + _UH.drawGdipCacheBufferSize,
cbSize, hr, (TB, _T("UHDrawGdiplusCachePDUNext size invalid")));
memcpy(_UH.drawGdipCacheBufferOffset, pTSDrawGdiplusCache + 1, cbSize);
_UH.drawGdipCacheBufferOffset += cbSize;
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHDrawGdiplusCachePDUEnd
//
// Handle the last PDU of Gdiplus Cache Order
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawGdiplusCachePDUEnd(
PTS_DRAW_GDIPLUS_CACHE_ORDER_END pOrder, DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PTS_DRAW_GDIPLUS_CACHE_ORDER_END pTSDrawGdiplusCache;
ULONG cbSize, cbTotalSize;
TSUINT16 CacheID, CacheType;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
DC_BEGIN_FN("UHDrawGdiplusCachePDUEnd");
OrderSize = sizeof(TS_DRAW_GDIPLUS_CACHE_ORDER_END) + pOrder->cbSize;
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
( TB, _T("Bad UHDrawGdiplusCachePDUEnd, size %u"), OrderSize));
*pOrderSize = OrderSize;
if (TS_DRAW_GDIPLUS_SUPPORTED != _pCc->_ccCombinedCapabilities.
drawGdiplusCapabilitySet.drawGdiplusCacheLevel) {
TRC_ERR((TB, _T("Gdip order when gdip not supported")));
DC_QUIT;
}
if (NULL == _UH.drawGdipCacheBuffer) {
DC_QUIT;
}
pTSDrawGdiplusCache = (PTS_DRAW_GDIPLUS_CACHE_ORDER_END)pOrder;
cbSize = pTSDrawGdiplusCache->cbSize;
cbTotalSize = pTSDrawGdiplusCache->cbTotalSize;
CacheType = pTSDrawGdiplusCache->CacheType;
if (FAILED(UHIsValidGdipCacheType(CacheType)))
{
// Ignore all failures for invalid cache type
DC_QUIT;
}
CacheID = pTSDrawGdiplusCache->CacheID;
hr = UHIsValidGdipCacheTypeID(CacheType, CacheID);
DC_QUIT_ON_FAIL(hr);
if (_UH.drawGdipCacheBufferOffset + cbSize != _UH.drawGdipCacheBuffer + _UH.drawGdipCacheBufferSize ||
cbTotalSize != _UH.drawGdipCacheBufferSize ) {
TRC_ABORT((TB, _T("Sizes are off") ));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
memcpy(_UH.drawGdipCacheBufferOffset, pTSDrawGdiplusCache + 1, cbSize);
hr = UHDrawGdiplusCacheData(CacheType, CacheID, cbTotalSize);
DC_QUIT_ON_FAIL(hr);
*pOrderSize = OrderSize;
DC_EXIT_POINT:
if (_UH.drawGdipCacheBuffer != NULL) {
UT_Free(_pUt, _UH.drawGdipCacheBuffer);
_UH.drawGdipCacheBuffer = NULL;
_UH.drawGdipCacheBufferOffset = NULL;
_UH.drawGdipCacheBufferSize = 0;
}
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHDrawGdiplusCacheData
//
// Put the received gdiplus cache data into free chunks
/****************************************************************************/
// SECURITY - caller should verify CacheType, CacheID
HRESULT DCINTERNAL CUH::UHDrawGdiplusCacheData(TSUINT16 CacheType,
TSUINT16 CacheID, unsigned cbTotalSize)
{
HRESULT hr = S_OK;
PUHGDIPLUSOBJECTCACHE pGdipObjectCache = NULL;
PUHGDIPLUSIMAGECACHE pGdipImageCache;
BOOL IsImageCache = FALSE;
BYTE *pCacheDataOffset, *pCacheSrcDataOffset;
INT16 NextIndex, CurrentIndex;
TSUINT16 ChunkNum, i;
unsigned SizeRemain, ChunkSize;
DC_BEGIN_FN("UHAssembleGdipEmfRecord");
switch (CacheType) {
case GDIP_CACHE_GRAPHICS_DATA:
pGdipObjectCache = &_UH.GdiplusGraphicsCache[CacheID];
break;
case GDIP_CACHE_OBJECT_BRUSH:
pGdipObjectCache = &_UH.GdiplusObjectBrushCache[CacheID];
break;
case GDIP_CACHE_OBJECT_PEN:
pGdipObjectCache = &_UH.GdiplusObjectPenCache[CacheID];
break;
case GDIP_CACHE_OBJECT_IMAGE:
pGdipImageCache = &_UH.GdiplusObjectImageCache[CacheID];
IsImageCache = TRUE;
break;
case GDIP_CACHE_OBJECT_IMAGEATTRIBUTES:
pGdipObjectCache = &_UH.GdiplusObjectImageAttributesCache[CacheID];
break;
default:
// Can't get here
break;
}
ChunkSize = UHGdipCacheChunkSize(CacheType);
TRC_ASSERT( ChunkSize != 0, (TB, _T("Invalid ChunkSize")));
if (IsImageCache) {
TRC_NRM((TB, _T("Image Cache ID %d"), CacheID));
// Remove previous cache to free the used chunks
UHDrawGdipRemoveImageCacheEntry(CacheID);
SizeRemain = cbTotalSize;
ChunkNum = (TSUINT16)ActualSizeToChunkSize(cbTotalSize, _UH.GdiplusObjectImageCacheChunkSize);
pGdipImageCache->CacheSize = cbTotalSize;
pGdipImageCache->ChunkNum = ChunkNum;
pCacheSrcDataOffset = _UH.drawGdipCacheBuffer;
CurrentIndex = _UH.GdipImageCacheFreeListHead;
pCacheDataOffset = _UH.GdipImageCacheData + CurrentIndex * _UH.GdiplusObjectImageCacheChunkSize;
for (i=0; i<ChunkNum - 1; i++) {
hr = UHIsValidGdipCacheTypeID(CacheType, CacheID);
DC_QUIT_ON_FAIL(hr);
memcpy(pCacheDataOffset, pCacheSrcDataOffset, _UH.GdiplusObjectImageCacheChunkSize);
pGdipImageCache->CacheDataIndex[i] = CurrentIndex;
_UH.GdipImageCacheFreeListHead = _UH.GdipImageCacheFreeList[CurrentIndex];
_UH.GdipImageCacheFreeList[CurrentIndex] = GDIP_CACHE_INDEX_DEFAULT;
CurrentIndex = _UH.GdipImageCacheFreeListHead;
pCacheDataOffset = _UH.GdipImageCacheData + CurrentIndex * _UH.GdiplusObjectImageCacheChunkSize;
pCacheSrcDataOffset += _UH.GdiplusObjectImageCacheChunkSize;
SizeRemain -= _UH.GdiplusObjectImageCacheChunkSize;
}
hr = UHIsValidGdipCacheTypeID(CacheType, CacheID);
DC_QUIT_ON_FAIL(hr);
memcpy(pCacheDataOffset, pCacheSrcDataOffset, SizeRemain);
pGdipImageCache->CacheDataIndex[ChunkNum - 1] = CurrentIndex;
_UH.GdipImageCacheFreeListHead = _UH.GdipImageCacheFreeList[CurrentIndex];
_UH.GdipImageCacheFreeList[CurrentIndex] = GDIP_CACHE_INDEX_DEFAULT;
}
else {
if (cbTotalSize > ChunkSize) {
TRC_ABORT(( TB, _T("TotalSize too large [totalSize %u ChunkSize %u]"),
cbTotalSize, ChunkSize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
if (pGdipObjectCache) {
pGdipObjectCache->CacheSize = cbTotalSize;
memcpy(pGdipObjectCache->CacheData, _UH.drawGdipCacheBuffer, cbTotalSize);
}
}
DC_EXIT_POINT:
if (_UH.drawGdipCacheBuffer != NULL) {
UT_Free(_pUt, _UH.drawGdipCacheBuffer);
_UH.drawGdipCacheBuffer = NULL;
_UH.drawGdipCacheBufferOffset = NULL;
_UH.drawGdipCacheBufferSize = 0;
}
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHAssembleGdipEmfRecord
//
// When receiving whole EMF+ record, assemble it, i.e. convert cachID to real cache data
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHAssembleGdipEmfRecord(unsigned cbEmfSize,
unsigned cbTotalSize)
{
HRESULT hr = S_OK;
ULONG cbSize;
RECT rect;
DrawTSClientEnum drawGdiplusType = DrawTSClientRecord;
PTSEmfPlusRecord pTSEmfRecord;
ULONG Size, CopyDataSize, SizeRemain;
BYTE * pData;
TSUINT16 CacheID;
unsigned int CacheSize;
PUHGDIPLUSOBJECTCACHE pGdipObjectCache;
PUHGDIPLUSIMAGECACHE pGdipImageCache;
BOOL IsCache;
BOOL IsImageCache = FALSE;
BYTE *pCacheSrcDataOffset;
INT16 NextIndex, CurrentIndex;
TSUINT16 ChunkNum;
TSUINT16 i;
TSUINT16 CacheType;
DC_BEGIN_FN("UHAssembleGdipEmfRecord");
_UH.drawGdipEmfBuffer = (BYTE *)UT_Malloc(_pUt, cbEmfSize);
if (_UH.drawGdipEmfBuffer == NULL) {
TRC_ERR((TB, _T("LocalAlloc failes in UHAssembleGdipEmfRecord")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawGdiplusErrorPDU), 0);
DC_QUIT;
}
_UH.drawGdipEmfBufferOffset = _UH.drawGdipEmfBuffer;
cbSize = cbTotalSize;
CHECK_READ_N_BYTES(_UH.drawGdipBuffer,
_UH.drawGdipBuffer + _UH.drawGdipBufferSize,
sizeof(TSEmfPlusRecord), hr,
(TB, _T("Not enough data for emfplusrecord")));
pTSEmfRecord = (PTSEmfPlusRecord)_UH.drawGdipBuffer;
pData = _UH.drawGdipBuffer;
Size = cbTotalSize;
while (Size > 0) {
CHECK_READ_N_BYTES(pData, _UH.drawGdipBuffer + _UH.drawGdipBufferSize,
sizeof(TSEmfPlusRecord), hr,
(TB, _T("Not enough data for emfplusrecord")));
pTSEmfRecord = (PTSEmfPlusRecord)pData;
IsCache = FALSE;
IsImageCache = FALSE;
// Fix for bug #660993. If this size is 0 we will be stuck
// in this loop.
if (pTSEmfRecord->Size != 0) {
if (pTSEmfRecord->Type == (enum EmfPlusRecordType)EmfPlusRecordTypeSetTSGraphics) {
pGdipObjectCache = _UH.GdiplusGraphicsCache;
CacheType = GDIP_CACHE_GRAPHICS_DATA;
IsCache = TRUE;
}
else if (pTSEmfRecord->Type == EmfPlusRecordTypeObject) {
switch ((enum ObjectType)(pTSEmfRecord->Flags >> 8)) {
case ObjectTypeBrush:
pGdipObjectCache = _UH.GdiplusObjectBrushCache;
CacheType = GDIP_CACHE_OBJECT_BRUSH;
IsCache = TRUE;
break;
case ObjectTypePen:
pGdipObjectCache = _UH.GdiplusObjectPenCache;
CacheType = GDIP_CACHE_OBJECT_PEN;
IsCache = TRUE;
break;
case ObjectTypeImage:
pGdipImageCache = _UH.GdiplusObjectImageCache;
CacheType = GDIP_CACHE_OBJECT_IMAGE;
IsCache = TRUE;
IsImageCache = TRUE;
break;
case ObjectTypeImageAttributes:
pGdipObjectCache = _UH.GdiplusObjectImageAttributesCache;
CacheType = GDIP_CACHE_OBJECT_IMAGEATTRIBUTES;
IsCache = TRUE;
break;
default:
IsCache = FALSE;
break;
}
}
if (!IsCache) {
// This record is not cached
CHECK_READ_N_BYTES(pData, _UH.drawGdipBuffer + _UH.drawGdipBufferSize,
pTSEmfRecord->Size, hr, ( TB, _T("Reading from data past end")));
CHECK_WRITE_N_BYTES(_UH.drawGdipEmfBufferOffset, _UH.drawGdipEmfBuffer + cbEmfSize,
pTSEmfRecord->Size, hr, ( TB, _T("Writing past data end")));
memcpy(_UH.drawGdipEmfBufferOffset, pData, pTSEmfRecord->Size);
_UH.drawGdipEmfBufferOffset += pTSEmfRecord->Size;
Size -= pTSEmfRecord->Size;
pData += pTSEmfRecord->Size;
}
else {
CacheSize = pTSEmfRecord->Size;
// Ensure that we have enough to read the following UINT16...
CHECK_READ_N_BYTES(pData, _UH.drawGdipBuffer + _UH.drawGdipBufferSize,
sizeof(TSEmfPlusRecord) + sizeof(TSUINT16), hr,
(TB, _T("Not enough data for cache ID")));
CacheID = *(TSUINT16 *)(pTSEmfRecord + 1);
if (CacheSize & 0x80000000) {
// This is Cached record
if (IsImageCache) {
// Image cache
hr = UHIsValidGdipCacheTypeID(CacheType, CacheID);
DC_QUIT_ON_FAIL(hr);
pGdipImageCache += CacheID;
pTSEmfRecord->Size = sizeof(TSEmfPlusRecord) +
pGdipImageCache->CacheSize;
CHECK_READ_N_BYTES(pData,
_UH.drawGdipBuffer + _UH.drawGdipBufferSize,
sizeof(TSEmfPlusRecord), hr,
( TB, _T("Reading from data past end")));
CHECK_WRITE_N_BYTES(_UH.drawGdipEmfBufferOffset,
_UH.drawGdipEmfBuffer + cbEmfSize,
sizeof(TSEmfPlusRecord), hr,
( TB, _T("Writing past data end")));
memcpy(_UH.drawGdipEmfBufferOffset, pData, sizeof(TSEmfPlusRecord));
Size -= sizeof(TSEmfPlusRecord);
pData += sizeof(TSEmfPlusRecord);
_UH.drawGdipEmfBufferOffset += sizeof(TSEmfPlusRecord);
SizeRemain = pGdipImageCache->CacheSize;
CHECK_WRITE_N_BYTES(_UH.drawGdipEmfBufferOffset,
_UH.drawGdipEmfBuffer + cbEmfSize,
SizeRemain, hr, ( TB, _T("Writing past data end")));
for (i=0; i<pGdipImageCache->ChunkNum-1; i++) {
CurrentIndex = pGdipImageCache->CacheDataIndex[i];
pCacheSrcDataOffset = _UH.GdipImageCacheData + _UH.GdiplusObjectImageCacheChunkSize * CurrentIndex;
memcpy(_UH.drawGdipEmfBufferOffset, pCacheSrcDataOffset, _UH.GdiplusObjectImageCacheChunkSize);
SizeRemain -= _UH.GdiplusObjectImageCacheChunkSize;
_UH.drawGdipEmfBufferOffset += _UH.GdiplusObjectImageCacheChunkSize;
}
CurrentIndex = pGdipImageCache->CacheDataIndex[pGdipImageCache->ChunkNum - 1];
pCacheSrcDataOffset = _UH.GdipImageCacheData + _UH.GdiplusObjectImageCacheChunkSize * CurrentIndex;
memcpy(_UH.drawGdipEmfBufferOffset, pCacheSrcDataOffset, SizeRemain);
_UH.drawGdipEmfBufferOffset += SizeRemain;
// We already checked above that we had enough data to read for this UINT16
Size -= sizeof(TSUINT16);
pData += sizeof(TSUINT16);
}
else {
// Other caches
pGdipObjectCache += CacheID;
hr = UHIsValidGdipCacheTypeID(CacheType, CacheID);
DC_QUIT_ON_FAIL(hr);
pTSEmfRecord->Size = sizeof(TSEmfPlusRecord) + pGdipObjectCache->CacheSize;
CHECK_READ_N_BYTES(pData,
_UH.drawGdipBuffer + _UH.drawGdipBufferSize,
sizeof(TSEmfPlusRecord), hr,
( TB, _T("Reading from data past end")));
CHECK_WRITE_N_BYTES(_UH.drawGdipEmfBufferOffset,
_UH.drawGdipEmfBuffer + cbEmfSize,
sizeof(TSEmfPlusRecord) + pGdipObjectCache->CacheSize,
hr, ( TB, _T("Writing past data end")));
memcpy(_UH.drawGdipEmfBufferOffset, pData, sizeof(TSEmfPlusRecord));
Size -= sizeof(TSEmfPlusRecord);
pData += sizeof(TSEmfPlusRecord);
_UH.drawGdipEmfBufferOffset += sizeof(TSEmfPlusRecord);
memcpy(_UH.drawGdipEmfBufferOffset, pGdipObjectCache->CacheData, pGdipObjectCache->CacheSize);
_UH.drawGdipEmfBufferOffset += pGdipObjectCache->CacheSize;
// We already checked above that we had enough data to read for this UINT16
Size -= sizeof(TSUINT16);
pData += sizeof(TSUINT16);
}
}
else {
// Not cached record, so copy it
CHECK_READ_N_BYTES(pData,
_UH.drawGdipBuffer + _UH.drawGdipBufferSize,
pTSEmfRecord->Size, hr,
( TB, _T("Reading from data past end")));
CHECK_WRITE_N_BYTES(_UH.drawGdipEmfBufferOffset,
_UH.drawGdipEmfBuffer + cbEmfSize,
pTSEmfRecord->Size, hr, ( TB, _T("Writing past data end")));
memcpy(_UH.drawGdipEmfBufferOffset, pData, pTSEmfRecord->Size);
_UH.drawGdipEmfBufferOffset += pTSEmfRecord->Size;
Size -= pTSEmfRecord->Size;
pData += pTSEmfRecord->Size;
}
}
} else {
TRC_ABORT((TB, _T("Invalid TSEmfRecord size")));
hr = E_TSC_CORE_GDIPLUS;
DC_QUIT;
}
}
if (_UH.drawGdipEmfBufferOffset !=
(_UH.drawGdipEmfBuffer+cbEmfSize)) {
TRC_ABORT((TB, _T("Error unpacking the EMF record.")));
hr = E_TSC_CORE_GDIPLUS;
DC_QUIT;
}
TRC_ASSERT((Size == 0), (TB, _T("Invalid EMF+ Record Size")));
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
HRESULT DCINTERNAL CUH::UHDrawGdiplusPDUComplete( ULONG cbEmfSize,
ULONG cbTotalSize)
{
HRESULT hr = S_OK;
RECT rect;
DrawTSClientEnum drawGdiplusType = DrawTSClientRecord;
UH_ORDER UHOrder;
DC_BEGIN_FN("UHDrawGdiplusPDUComplete");
hr = UHAssembleGdipEmfRecord(cbEmfSize, cbTotalSize);
DC_QUIT_ON_FAIL(hr);
if (_UH.pfnGdipPlayTSClientRecord != NULL) {
if (_UH.pfnGdipPlayTSClientRecord(_UH.hdcDraw, drawGdiplusType,
_UH.drawGdipEmfBuffer, cbEmfSize, &rect) == 0) {
// success
_UH.DrawGdiplusFailureCount = 0;
}
else {
TRC_ERR((TB, _T("GdiPlay:DrawTSClientRecord failed")));
_UH.DrawGdiplusFailureCount++;
if (_UH.DrawGdiplusFailureCount >= DRAWGDIPLUSFAILURELIMIT) {
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawGdiplusErrorPDU), 0);
_UH.DrawGdiplusFailureCount = 0;
hr = E_TSC_CORE_GDIPLUS;
DC_QUIT;
}
}
// $TODO - IVAN - If pfnGdipPlayTSClientRecord failed, rect is probably not initialized
// _UH.DrawGdiplusFailureCount < DRAWGDIPLUSFAILURELIMIT
if (_UH.hdcDraw == _UH.hdcShadowBitmap) {
UHOrder.dstRect.left = rect.left;
UHOrder.dstRect.bottom = rect.bottom;
UHOrder.dstRect.right = rect.right;
UHOrder.dstRect.top = rect.top;
UHAddUpdateRegion(&UHOrder, _UH.hrgnUpdate);
}
}
DC_EXIT_POINT:
if (_UH.drawGdipBuffer != NULL) {
UT_Free(_pUt, _UH.drawGdipBuffer);
_UH.drawGdipBuffer = NULL;
_UH.drawGdipBufferOffset = NULL;
_UH.drawGdipBufferSize = 0;
}
if (_UH.drawGdipEmfBuffer != NULL) {
UT_Free(_pUt, _UH.drawGdipEmfBuffer);
_UH.drawGdipEmfBuffer = NULL;
_UH.drawGdipEmfBufferOffset = NULL;
}
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHDrawGdiplusPDUFirst
//
// Handle the first PDU of Gdiplus Order
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawGdiplusPDUFirst(
PTS_DRAW_GDIPLUS_ORDER_FIRST pOrder, DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PTS_DRAW_GDIPLUS_ORDER_FIRST pTSDrawGdiplus;
ULONG cbSize, cbTotalSize, cbEmfSize;
RECT rect;
DrawTSClientEnum drawGdiplusType = DrawTSClientRecord;
PTSEmfPlusRecord pTSEmfRecord;
ULONG Size;
BYTE * pData;
UH_ORDER UHOrder;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
DC_BEGIN_FN("UHDrawGdiplusPDUFirst");
TRC_NRM((TB, _T("UHDrawGdiplusPDUFirst")));
OrderSize = sizeof(TS_DRAW_GDIPLUS_ORDER_FIRST) + pOrder->cbSize;
//SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
( TB, _T("Bad UHDrawGdiplusPDUFirst; Size %u"), OrderSize));
*pOrderSize = OrderSize;
if (TS_DRAW_GDIPLUS_SUPPORTED != _pCc->_ccCombinedCapabilities.
drawGdiplusCapabilitySet.drawGdiplusCacheLevel) {
TRC_ERR((TB, _T("Gdip order when gdip not supported")));
DC_QUIT;
}
pTSDrawGdiplus = (PTS_DRAW_GDIPLUS_ORDER_FIRST)pOrder;
cbSize = pTSDrawGdiplus->cbSize;
cbTotalSize = pTSDrawGdiplus->cbTotalSize;
if (cbSize > cbTotalSize) {
TRC_ERR(( TB, _T("invalid sizes [cbSize %u cbTotalSize %u]"),
cbSize, cbTotalSize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
cbEmfSize = pTSDrawGdiplus->cbTotalEmfSize;
_UH.drawGdipBuffer = (BYTE *)UT_Malloc(_pUt, cbTotalSize);
if (_UH.drawGdipBuffer == NULL) {
TRC_ERR((TB, _T("LocalAlloc failes in UHDrawGdiplusPDUFirst")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawGdiplusErrorPDU), 0);
DC_QUIT;
}
_UH.drawGdipBufferOffset = _UH.drawGdipBuffer;
_UH.drawGdipBufferSize = cbTotalSize;
// SECURITY: we can copy cbSize bytes since it is <= cbTotalSize,
// which is the buffer length
memcpy(_UH.drawGdipBufferOffset, (BYTE *)(pTSDrawGdiplus + 1), cbSize);
_UH.drawGdipBufferOffset += cbSize;
if (cbSize == cbTotalSize) {
hr = UHDrawGdiplusPDUComplete(cbEmfSize, cbTotalSize);
DC_QUIT_ON_FAIL(hr);
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHDrawGdiplusPDUFirst
//
// Handle the subsequent PDU of Gdiplus Order
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawGdiplusPDUNext(
PTS_DRAW_GDIPLUS_ORDER_NEXT pOrder, DCUINT orderLen, unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PTS_DRAW_GDIPLUS_ORDER_NEXT pTSDrawGdiplus;
ULONG cbSize;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
DC_BEGIN_FN("UHDrawGdiplusPDUNext");
OrderSize = sizeof(TS_DRAW_GDIPLUS_ORDER_NEXT) + pOrder->cbSize;
//SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
( TB, _T("Bad UHDrawGdiplusPDUNext; Size %u"), OrderSize));
*pOrderSize = OrderSize;
if (TS_DRAW_GDIPLUS_SUPPORTED != _pCc->_ccCombinedCapabilities.
drawGdiplusCapabilitySet.drawGdiplusCacheLevel) {
TRC_ERR((TB, _T("Gdip order when gdip not supported")));
DC_QUIT;
}
if (NULL == _UH.drawGdipBufferOffset) {
DC_QUIT;
}
pTSDrawGdiplus = (PTS_DRAW_GDIPLUS_ORDER_NEXT)pOrder;
cbSize = pTSDrawGdiplus->cbSize;
CHECK_WRITE_N_BYTES(_UH.drawGdipBufferOffset, _UH.drawGdipBuffer + _UH.drawGdipBufferSize,
cbSize, hr, (TB, _T("UHDrawGdiplusPDUNext size invalid")));
memcpy(_UH.drawGdipBufferOffset, (BYTE *)(pTSDrawGdiplus + 1), cbSize);
_UH.drawGdipBufferOffset += cbSize;
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHDrawGdiplusPDUFirst
//
// Handle the last PDU of Gdiplus Order
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawGdiplusPDUEnd(
PTS_DRAW_GDIPLUS_ORDER_END pOrder, DCUINT orderLen, unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PTS_DRAW_GDIPLUS_ORDER_END pTSDrawGdiplus;
ULONG cbSize, cbTotalSize, cbEmfSize;
RECT rect;
DrawTSClientEnum drawGdiplusType = DrawTSClientRecord;
UH_ORDER UHOrder;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
DC_BEGIN_FN("UHDrawGdiplusPDUEnd");
OrderSize = sizeof(TS_DRAW_GDIPLUS_ORDER_END) + pOrder->cbSize;
//SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
( TB, _T("Bad UHDrawGdiplusPDUEnd; Size %u"), OrderSize));
*pOrderSize = OrderSize;
if (TS_DRAW_GDIPLUS_SUPPORTED != _pCc->_ccCombinedCapabilities.
drawGdiplusCapabilitySet.drawGdiplusCacheLevel) {
TRC_ERR((TB, _T("Gdip order when gdip not supported")));
DC_QUIT;
}
if (NULL == _UH.drawGdipBufferOffset) {
DC_QUIT;
}
pTSDrawGdiplus = (PTS_DRAW_GDIPLUS_ORDER_END)pOrder;
cbSize = pTSDrawGdiplus->cbSize;
cbTotalSize = pTSDrawGdiplus->cbTotalSize;
if (cbSize > cbTotalSize) {
TRC_ERR(( TB, _T("invalid sizes [cbSize %u cbTotalSize %u]"),
cbSize, cbTotalSize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
if (cbTotalSize != _UH.drawGdipBufferSize) {
TRC_ERR(( TB, _T("cbTotalSize has changed [original %u, now %u]"),
_UH.drawGdipBufferSize, cbTotalSize));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
cbEmfSize = pTSDrawGdiplus->cbTotalEmfSize;
CHECK_WRITE_N_BYTES(_UH.drawGdipBufferOffset, _UH.drawGdipBuffer + _UH.drawGdipBufferSize,
cbSize, hr, (TB, _T("UHDrawGdiplusPDUEnd size invalid")));
memcpy(_UH.drawGdipBufferOffset, (BYTE *)(pTSDrawGdiplus + 1), cbSize);
_UH.drawGdipBufferOffset += cbSize;
hr = UHDrawGdiplusPDUComplete(cbEmfSize, cbTotalSize);
DC_QUIT_ON_FAIL(hr);
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
// Remove a gdiplus image cache entry and add the free memory to the free list
// SECURITY - callers must verify the CacheID
BOOL DCINTERNAL CUH::UHDrawGdipRemoveImageCacheEntry(TSUINT16 CacheID)
{
unsigned i;
BOOL rc = FALSE;
PUHGDIPLUSIMAGECACHE pGdipImageCache;
INT16 CurrentIndex;
DC_BEGIN_FN("UHDrawGdipRemoveImageCacheEntry");
pGdipImageCache = _UH.GdiplusObjectImageCache + CacheID;
for (i=0; i<pGdipImageCache->ChunkNum; i++) {
CurrentIndex = pGdipImageCache->CacheDataIndex[i];
_UH.GdipImageCacheFreeList[CurrentIndex] = _UH.GdipImageCacheFreeListHead;
_UH.GdipImageCacheFreeListHead = CurrentIndex;
}
pGdipImageCache->ChunkNum = 0;
DC_END_FN();
return rc;
}
#endif // DRAW_GDIPLUS
#ifdef DRAW_NINEGRID
/****************************************************************************/
// Name: UHCacheStreamBitmapFirstPDU
//
// Cache streamed bitmap, this is the first block
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHCacheStreamBitmapFirstPDU(
PTS_STREAM_BITMAP_FIRST_PDU pOrder, DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
TS_STREAM_BITMAP_FIRST_PDU_REV2 OrderRev2;
PTS_STREAM_BITMAP_FIRST_PDU_REV2 pOrderRev2;
BYTE *pOrderData;
DC_BEGIN_FN("UHCacheStreamBitmapFirstPDU");
pOrderRev2 = &OrderRev2;
if (pOrder->BitmapFlags & TS_STREAM_BITMAP_REV2) {
// TS_STREAM_BITMAP_FIRST_PDU_REV2
CHECK_READ_N_BYTES(pOrder, pEnd, sizeof( TS_STREAM_BITMAP_FIRST_PDU_REV2 ), hr,
(TB, _T("Bad TS_STREAM_BITMAP_FIRST_PDU ")));
OrderSize = sizeof(TS_STREAM_BITMAP_FIRST_PDU_REV2) + ((PTS_STREAM_BITMAP_FIRST_PDU_REV2)pOrder)->BitmapBlockLength;
pOrderData = (BYTE *)((PTS_STREAM_BITMAP_FIRST_PDU_REV2)pOrder + 1);
memcpy(pOrderRev2, pOrder, sizeof(TS_STREAM_BITMAP_FIRST_PDU_REV2));
}
else {
OrderSize = sizeof(TS_STREAM_BITMAP_FIRST_PDU) + pOrder->BitmapBlockLength;
pOrderData = (BYTE *)(pOrder + 1);
pOrderRev2->ControlFlags = pOrder->ControlFlags;
pOrderRev2->BitmapFlags = pOrder->BitmapFlags;
pOrderRev2->BitmapLength = pOrder->BitmapLength;
pOrderRev2->BitmapId = pOrder->BitmapId;
pOrderRev2->BitmapBpp = pOrder->BitmapBpp;
pOrderRev2->BitmapWidth = pOrder->BitmapWidth;
pOrderRev2->BitmapHeight = pOrder->BitmapHeight;
pOrderRev2->BitmapBlockLength = pOrder->BitmapBlockLength;
}
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
( TB, _T("Bad UHCacheStreamBitmapFirstPDU; Size %u"), OrderSize));
*pOrderSize = OrderSize;
if (pOrderRev2->BitmapId == TS_DRAW_NINEGRID_BITMAP_CACHE) {
_UH.drawNineGridAssembleBuffer =
(PDCUINT8)UT_Malloc(_pUt, pOrderRev2->BitmapLength);
_UH.drawNineGridDecompressionBufferSize = pOrderRev2->BitmapWidth * pOrderRev2->BitmapHeight *
pOrderRev2->BitmapBpp / 8;
_UH.drawNineGridDecompressionBuffer =
(PDCUINT8)UT_Malloc(_pUt, _UH.drawNineGridDecompressionBufferSize);
if (_UH.drawNineGridAssembleBuffer != NULL &&
_UH.drawNineGridDecompressionBuffer != NULL &&
pOrderRev2->BitmapBlockLength <= pOrderRev2->BitmapLength &&
pOrderRev2->BitmapLength <= (TSUINT32)(pOrderRev2->BitmapWidth * pOrderRev2->BitmapHeight *
pOrderRev2->BitmapBpp / 8)) {
_UH.drawNineGridAssembleBufferWidth = pOrderRev2->BitmapWidth;
_UH.drawNineGridAssembleBufferHeight = pOrderRev2->BitmapHeight;
_UH.drawNineGridAssembleBufferBpp = pOrderRev2->BitmapBpp;
_UH.drawNineGridAssembleBufferSize = pOrderRev2->BitmapLength;
_UH.drawNineGridAssembleCompressed = pOrderRev2->BitmapFlags & TS_STREAM_BITMAP_COMPRESSED;
_UH.drawNineGridAssembleBufferOffset = pOrderRev2->BitmapBlockLength;
if (pOrderRev2->BitmapFlags & TS_STREAM_BITMAP_END) {
if (_UH.drawNineGridAssembleCompressed) {
hr = BD_DecompressBitmap((PDCUINT8)pOrderData, _UH.drawNineGridDecompressionBuffer,
pOrderRev2->BitmapBlockLength,
_UH.drawNineGridDecompressionBufferSize,
TRUE, pOrderRev2->BitmapBpp, pOrderRev2->BitmapWidth,
pOrderRev2->BitmapHeight);
DC_QUIT_ON_FAIL(hr);
}
else {
// Save to the assemble buffer uncompressed bitmap
memcpy(_UH.drawNineGridAssembleBuffer, pOrderData, pOrderRev2->BitmapBlockLength);
}
}
else {
// Save to the assemble buffer for decompression when full bitmap stream received
memcpy(_UH.drawNineGridAssembleBuffer, pOrderData, pOrderRev2->BitmapBlockLength);
}
}
else {
if (_UH.drawNineGridAssembleBuffer != NULL) {
UT_Free(_pUt, _UH.drawNineGridAssembleBuffer);
_UH.drawNineGridAssembleBuffer = NULL;
}
if (_UH.drawNineGridDecompressionBuffer != NULL) {
UT_Free(_pUt, _UH.drawNineGridDecompressionBuffer);
_UH.drawNineGridDecompressionBuffer = NULL;
_UH.drawNineGridDecompressionBufferSize = 0;
}
// Send error PDU
if (!_UH.sendDrawNineGridErrorPDU)
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawNineGridErrorPDU), 0);
}
}
else {
TRC_ASSERT((FALSE), (TB, _T("Invalid bitmapId for stream bitmap first pdu")));
// ignore
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHCacheStreamBitmapNextPDU
//
// Cache streamed bitmap, this is the subsequent block
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHCacheStreamBitmapNextPDU(
PTS_STREAM_BITMAP_NEXT_PDU pOrder, DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned OrderSize;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
DC_BEGIN_FN("UHCacheStreamBitmapNextPDU");
OrderSize = sizeof(TS_STREAM_BITMAP_NEXT_PDU) +
pOrder->BitmapBlockLength;
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, OrderSize, hr,
( TB, _T("Bad UHCacheStreamBitmapNextPDU; Size %u"), OrderSize));
*pOrderSize = OrderSize;
if (pOrder->BitmapId == TS_DRAW_NINEGRID_BITMAP_CACHE) {
if ((_UH.drawNineGridAssembleBufferOffset + pOrder->BitmapBlockLength <=
_UH.drawNineGridAssembleBufferSize) &&
(_UH.drawNineGridAssembleBuffer != NULL)) {
// Save to assemble buffer
memcpy(_UH.drawNineGridAssembleBuffer + _UH.drawNineGridAssembleBufferOffset,
pOrder + 1, pOrder->BitmapBlockLength);
_UH.drawNineGridAssembleBufferOffset += pOrder->BitmapBlockLength;
if (pOrder->BitmapFlags & TS_STREAM_BITMAP_END) {
if (_UH.drawNineGridAssembleCompressed) {
hr = BD_DecompressBitmap(_UH.drawNineGridAssembleBuffer, _UH.drawNineGridDecompressionBuffer,
_UH.drawNineGridAssembleBufferOffset, _UH.drawNineGridDecompressionBufferSize,
TRUE,
(BYTE)_UH.drawNineGridAssembleBufferBpp,
(TSUINT16)_UH.drawNineGridAssembleBufferWidth,
(TSUINT16)_UH.drawNineGridAssembleBufferHeight);
DC_QUIT_ON_FAIL(hr);
}
}
}
else {
if (_UH.drawNineGridAssembleBuffer != NULL) {
UT_Free(_pUt, _UH.drawNineGridAssembleBuffer);
_UH.drawNineGridAssembleBuffer = NULL;
}
if (_UH.drawNineGridDecompressionBuffer != NULL) {
UT_Free(_pUt, _UH.drawNineGridDecompressionBuffer);
_UH.drawNineGridDecompressionBuffer = NULL;
_UH.drawNineGridDecompressionBufferSize = 0;
}
// Send error PDU
if (!_UH.sendDrawNineGridErrorPDU)
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawNineGridErrorPDU), 0);
}
}
else {
TRC_ASSERT((FALSE), (TB, _T("Invalid bitmapId for stream bitmap first pdu")));
// ignore
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UHCreateNineGridBitmap
//
// Create DrawNineGrid bitmap
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHCreateNineGridBitmap(
PTS_CREATE_NINEGRID_BITMAP_ORDER pOrder, DCUINT orderLen,
unsigned *pOrderSize)
{
HRESULT hr = S_OK;
unsigned orderSize;
unsigned cacheId;
HBITMAP hBitmap = NULL;
HDC hdc;
BITMAPINFO bi = { 0 };
void * pvBits = NULL;
struct {
BITMAPINFOHEADER bmih;
ULONG masks[3];
} bmi;
PBYTE pEnd = (PBYTE)pOrder + orderLen;
DC_BEGIN_FN("UHCreateNineGridBitmap");
orderSize = sizeof(TS_CREATE_NINEGRID_BITMAP_ORDER);
// SECURITY: 552403
CHECK_READ_N_BYTES(pOrder, pEnd, orderSize, hr,
( TB, _T("Bad UHCreateNineGridBitmap")));
TRC_NRM((TB, _T("Create a drawninegrid bitmap of size (%d, %d)"), pOrder->cx,
pOrder->cy));
// Get the DrawNineGrid bitmap Id
cacheId = pOrder->BitmapID;
hr = UHIsValidNineGridCacheIndex(cacheId);
DC_QUIT_ON_FAIL(hr);
if (_UH.drawNineGridDecompressionBuffer != NULL &&
_UH.drawNineGridAssembleBuffer != NULL) {
TRC_ASSERT((pOrder->BitmapBpp == 32), (TB, _T("Invalid bitmap bpp")));
// Create a drawninegrid bitmap
#ifdef DISABLE_SHADOW_IN_FULLSCREEN
if (!_UH.DontUseShadowBitmap && (_UH.hdcShadowBitmap != NULL)) {
#else // DISABLE_SHADOW_IN_FULLSCREEN
if (_UH.hdcShadowBitmap != NULL) {
#endif // DISABLE_SHADOW_IN_FULLSCREEN
hdc = _UH.hdcShadowBitmap;
}
else {
hdc = _UH.hdcOutputWindow;
}
// Delete the bitmap if there is one already exists.
if (_UH.drawNineGridBitmapCache[cacheId].drawNineGridBitmap != NULL) {
SelectBitmap(_UH.hdcDrawNineGridBitmap, _UH.hUnusedDrawNineGridBitmap);
DeleteObject(_UH.drawNineGridBitmapCache[cacheId].drawNineGridBitmap);
_UH.drawNineGridBitmapCache[cacheId].drawNineGridBitmap = NULL;
}
#if 0
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = _UH.drawNineGridAssembleBufferWidth;
bi.bmiHeader.biHeight = 0 - _UH.drawNineGridAssembleBufferHeight;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = pOrder->BitmapBpp;
bi.bmiHeader.biCompression = BI_RGB;
hBitmap = CreateDIBSection(hdc, &bi, DIB_RGB_COLORS,
(VOID**)&pvBits, NULL, 0);
if (_UH.drawNineGridAssembleCompressed) {
memcpy(pvBits, _UH.drawNineGridDecompressionBuffer, _UH.drawNineGridAssembleBufferWidth *
_UH.drawNineGridAssembleBufferHeight * pOrder->BitmapBpp / 8);
}
else {
memcpy(pvBits, _UH.drawNineGridAssembleBuffer, _UH.drawNineGridAssembleBufferWidth *
_UH.drawNineGridAssembleBufferHeight * pOrder->BitmapBpp / 8);
}
#else
bmi.bmih.biSize = sizeof(bmi.bmih);
bmi.bmih.biWidth = _UH.drawNineGridAssembleBufferWidth;
bmi.bmih.biHeight = _UH.drawNineGridAssembleBufferHeight;
bmi.bmih.biPlanes = 1;
bmi.bmih.biBitCount = 32;
bmi.bmih.biCompression = BI_BITFIELDS;
bmi.bmih.biSizeImage = 0;
bmi.bmih.biXPelsPerMeter = 0;
bmi.bmih.biYPelsPerMeter = 0;
bmi.bmih.biClrUsed = 3;
bmi.bmih.biClrImportant = 0;
bmi.masks[0] = 0xff0000; // red
bmi.masks[1] = 0x00ff00; // green
bmi.masks[2] = 0x0000ff; // blue
if (_UH.drawNineGridAssembleCompressed) {
hBitmap = CreateDIBitmap(hdc, &bmi.bmih, CBM_INIT | 0x2,
_UH.drawNineGridDecompressionBuffer, (BITMAPINFO*)&bmi.bmih, DIB_RGB_COLORS);
}
else {
hBitmap = CreateDIBitmap(hdc, &bmi.bmih, CBM_INIT | 0x2,
_UH.drawNineGridAssembleBuffer, (BITMAPINFO*)&bmi.bmih, DIB_RGB_COLORS);
}
#endif
if (_UH.drawNineGridAssembleBuffer != NULL) {
UT_Free(_pUt, _UH.drawNineGridAssembleBuffer);
_UH.drawNineGridAssembleBuffer = NULL;
}
if (_UH.drawNineGridDecompressionBuffer != NULL) {
UT_Free(_pUt, _UH.drawNineGridDecompressionBuffer);
_UH.drawNineGridDecompressionBuffer = NULL;
_UH.drawNineGridDecompressionBufferSize = 0;
}
if (hBitmap != NULL) {
// set the unused bitmap
if (_UH.hUnusedDrawNineGridBitmap == NULL)
_UH.hUnusedDrawNineGridBitmap = SelectBitmap(_UH.hdcDrawNineGridBitmap,
hBitmap);
#if 0
SelectBitmap(_UH.hdcDrawNineGridBitmap, hBitmap);
SelectPalette(_UH.hdcDrawNineGridBitmap, _UH.hpalCurrent, FALSE);
#endif
_UH.drawNineGridBitmapCache[cacheId].drawNineGridBitmap = hBitmap;
_UH.drawNineGridBitmapCache[cacheId].cx = pOrder->cx;
_UH.drawNineGridBitmapCache[cacheId].cy = pOrder->cy;
_UH.drawNineGridBitmapCache[cacheId].dngInfo.crTransparent = pOrder->nineGridInfo.crTransparent;
_UH.drawNineGridBitmapCache[cacheId].dngInfo.flFlags = pOrder->nineGridInfo.flFlags;
_UH.drawNineGridBitmapCache[cacheId].dngInfo.ulBottomHeight = pOrder->nineGridInfo.ulBottomHeight;
_UH.drawNineGridBitmapCache[cacheId].dngInfo.ulLeftWidth = pOrder->nineGridInfo.ulLeftWidth;
_UH.drawNineGridBitmapCache[cacheId].dngInfo.ulRightWidth = pOrder->nineGridInfo.ulRightWidth;
_UH.drawNineGridBitmapCache[cacheId].dngInfo.ulTopHeight = pOrder->nineGridInfo.ulTopHeight;
_UH.drawNineGridBitmapCache[cacheId].bitmapBpp = pOrder->BitmapBpp;
} else {
TRC_ERR((TB, _T("CreateDIBitmap failed\n")));
// Unable to create the bitmap, send error pdu to the server
// to disable drawninegrid rendering
_UH.drawNineGridBitmapCache[cacheId].drawNineGridBitmap = NULL;
_UH.drawNineGridBitmapCache[cacheId].cx = 0;
_UH.drawNineGridBitmapCache[cacheId].cy = 0;
_UH.drawNineGridBitmapCache[cacheId].bitmapBpp = 0;
if (!_UH.sendDrawNineGridErrorPDU)
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawNineGridErrorPDU), 0);
}
}
else {
_UH.drawNineGridBitmapCache[cacheId].drawNineGridBitmap = NULL;
_UH.drawNineGridBitmapCache[cacheId].cx = 0;
_UH.drawNineGridBitmapCache[cacheId].cy = 0;
_UH.drawNineGridBitmapCache[cacheId].bitmapBpp = 0;
}
*pOrderSize = orderSize;
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/****************************************************************************/
// Name: UH_DrawNineGrid
//
// DrawNineGrid
/****************************************************************************/
HRESULT DCAPI CUH::UH_DrawNineGrid(PUH_ORDER pOrder, unsigned bitmapId, RECT* psrcRect)
{
HRESULT hr = S_OK;
HBITMAP hBitmap;
TS_DRAW_NINEGRID stream;
DS_NINEGRIDINFO ngInfo;
TSCOLORREF colorRef;
TS_BITMAPOBJ srcBmpObj;
DC_BEGIN_FN("UH_DrawNineGrid");
if (_pCc->_ccCombinedCapabilities.drawNineGridCapabilitySet.drawNineGridSupportLevel < TS_DRAW_NINEGRID_SUPPORTED) {
TRC_ERR((TB, _T("Recieved draw nine grid order when not expected")));
DC_QUIT;
}
hr = UHIsValidNineGridCacheIndex(bitmapId);
DC_QUIT_ON_FAIL(hr);
// Get the drawninegrid bitmap from bitmapid
hBitmap = _UH.drawNineGridBitmapCache[bitmapId].drawNineGridBitmap;
#if 0
SelectObject(_UH.hdcDrawNineGridBitmap, hBitmap);
#endif
// setup the ninegrid info
ngInfo.flFlags = _UH.drawNineGridBitmapCache[bitmapId].dngInfo.flFlags;
ngInfo.ulLeftWidth = _UH.drawNineGridBitmapCache[bitmapId].dngInfo.ulLeftWidth;
ngInfo.ulRightWidth = _UH.drawNineGridBitmapCache[bitmapId].dngInfo.ulRightWidth;
ngInfo.ulTopHeight = _UH.drawNineGridBitmapCache[bitmapId].dngInfo.ulTopHeight;
ngInfo.ulBottomHeight = _UH.drawNineGridBitmapCache[bitmapId].dngInfo.ulBottomHeight;
// the color ref from server needs to be switched to BGR format
colorRef = _UH.drawNineGridBitmapCache[bitmapId].dngInfo.crTransparent;
ngInfo.crTransparent = (colorRef & 0xFF00FF00) | ((colorRef & 0xFF) << 0x10) |
((colorRef & 0xFF0000) >> 0x10);
// render
stream.hdr.magic = DS_MAGIC;
stream.cmdSetTarget.ulCmdID = DS_SETTARGETID;
stream.cmdSetTarget.hdc = (ULONG)((ULONG_PTR)(_UH.hdcDraw));
stream.cmdSetTarget.rclDstClip.left = pOrder->dstRect.left;
stream.cmdSetTarget.rclDstClip.top = pOrder->dstRect.top;
stream.cmdSetTarget.rclDstClip.right = pOrder->dstRect.right;
stream.cmdSetTarget.rclDstClip.bottom = pOrder->dstRect.bottom;
stream.cmdSetSource.ulCmdID = DS_SETSOURCEID;
#if 0
stream.cmdSetSource.hbm = (ULONG)_UH.hdcDrawNineGridBitmap;
#else
stream.cmdSetSource.hbm = (ULONG)((ULONG_PTR)hBitmap);
#endif
stream.cmdNineGrid.ulCmdID = DS_NINEGRIDID;
if (ngInfo.flFlags & DSDNG_MUSTFLIP) {
stream.cmdNineGrid.rclDst.left = pOrder->dstRect.right;
stream.cmdNineGrid.rclDst.right = pOrder->dstRect.left;
}
else {
stream.cmdNineGrid.rclDst.left = pOrder->dstRect.left;
stream.cmdNineGrid.rclDst.right = pOrder->dstRect.right;
}
stream.cmdNineGrid.rclDst.top = pOrder->dstRect.top;
stream.cmdNineGrid.rclDst.bottom = pOrder->dstRect.bottom;
stream.cmdNineGrid.rclSrc.left = psrcRect->left;
stream.cmdNineGrid.rclSrc.top = psrcRect->top;
stream.cmdNineGrid.rclSrc.right = psrcRect->right;
stream.cmdNineGrid.rclSrc.bottom = psrcRect->bottom;
stream.cmdNineGrid.ngi = ngInfo;
if (_UH.pfnGdiDrawStream != NULL) {
if (!_UH.pfnGdiDrawStream(_UH.hdcDraw, sizeof(stream), &stream)) {
TRC_ASSERT((FALSE), (TB, _T("GdiDrawStream call failed")));
}
}
else {
TS_DS_NINEGRID drawNineGridInfo;
drawNineGridInfo.dng = stream.cmdNineGrid;
drawNineGridInfo.pfnAlphaBlend = _UH.pfnGdiAlphaBlend;
drawNineGridInfo.pfnTransparentBlt = _UH.pfnGdiTransparentBlt;
TRC_ASSERT((_UH.pfnGdiAlphaBlend != NULL && _UH.pfnGdiTransparentBlt != NULL),
(TB, _T("Can't find AlphaBlend or TransparentBlt funcs")));
srcBmpObj.hdc = _UH.hdcDrawNineGridBitmap;
// The bitmap sent to us is always dword aligned width
srcBmpObj.sizlBitmap.cx = (_UH.drawNineGridBitmapCache[bitmapId].cx + 3) & ~3;
srcBmpObj.sizlBitmap.cy = _UH.drawNineGridBitmapCache[bitmapId].cy;
// We would get 32bpp always for now
TRC_ASSERT((_UH.drawNineGridBitmapCache[bitmapId].bitmapBpp == 32),
(TB, _T("Get non 32bpp source bitmap for drawninegrid")));
srcBmpObj.cjBits = srcBmpObj.sizlBitmap.cx * _UH.drawNineGridBitmapCache[bitmapId].cy *
_UH.drawNineGridBitmapCache[bitmapId].bitmapBpp / 8;
srcBmpObj.lDelta = srcBmpObj.sizlBitmap.cx * sizeof(ULONG);
srcBmpObj.iBitmapFormat = _UH.drawNineGridBitmapCache[bitmapId].bitmapBpp;
srcBmpObj.pvBits = (PDCUINT8)UT_Malloc(_pUt, srcBmpObj.cjBits);
if (srcBmpObj.pvBits != NULL) {
GetBitmapBits(hBitmap, srcBmpObj.cjBits, srcBmpObj.pvBits);
DrawNineGrid(_UH.hdcDraw, &srcBmpObj, &drawNineGridInfo);
UT_Free(_pUt, srcBmpObj.pvBits);
}
else {
// send an error pdu for redraw
if (!_UH.sendDrawNineGridErrorPDU) {
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH, UHSendDrawNineGridErrorPDU), 0);
DC_QUIT;
}
}
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
#if 0
void DCINTERNAL CUH::UHCreateDrawStreamBitmap(
PTS_CREATE_DRAW_STREAM_ORDER pOrder)
{
unsigned cacheId;
HBITMAP hBitmap = NULL;
HDC hdcDesktop = NULL;
DC_BEGIN_FN("UHCreateDrawStreamBitmap");
// Get the DrawStream bitmap Id
cacheId = pOrder->BitmapID;
//TRC_ASSERT((cacheId < _UH.offscrCacheEntries), (TB, _T("Invalid offscreen ")
// _T("cache ID")));
TRC_NRM((TB, _T("Create a drawstream bitmap of size (%d, %d)"), pOrder->cx,
pOrder->cy));
// Delete the bitmap if there is one already exists.
if (_UH.drawStreamBitmapCache[cacheId].drawStreamBitmap != NULL) {
// JOYC: TODO: reuse bitmap
//if (UH.offscrBitmapCache[cacheId].cx >= pOrder->cx &&
// UH.offscrBitmapCache[cacheId].cy >= pOrder->cy) {
// return;
//}
SelectBitmap(_UH.hdcDrawStreamBitmap, _UH.hUnusedDrawStreamBitmap);
DeleteObject(_UH.drawStreamBitmapCache[cacheId].drawStreamBitmap);
_UH.drawStreamBitmapCache[cacheId].drawStreamBitmap = NULL;
}
// Create an offscreen bitmap
if (_UH.hdcShadowBitmap != NULL) {
BITMAPINFO bi = { 0 };
void * pvBits = NULL;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = pOrder->cx;
bi.bmiHeader.biHeight = -pOrder->cy;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = pOrder->bitmapBpp;
bi.bmiHeader.biCompression = BI_RGB;
hBitmap = CreateDIBSection(_UH.hdcShadowBitmap, &bi, DIB_RGB_COLORS,
(VOID**)&pvBits, NULL, 0);
if (_UH.drawStreamAssembleBufferWidth == pOrder->cx) {
if (_UH.drawStreamAssembleCompressed) {
memcpy(pvBits, _UH.drawStreamDecompressionBuffer, pOrder->cx * pOrder->cy *
pOrder->bitmapBpp / 8);
}
else {
memcpy(pvBits, _UH.drawStreamAssembleBuffer, pOrder->cx * pOrder->cy *
pOrder->bitmapBpp / 8);
}
}
}
else {
BITMAPINFO bi = { 0 };
void * pvBits = NULL;
bi.bmiHeader.biSize = sizeof(bi.bmiHeader);
bi.bmiHeader.biWidth = pOrder->cx;
bi.bmiHeader.biHeight = -pOrder->cy;
bi.bmiHeader.biPlanes = 1;
bi.bmiHeader.biBitCount = pOrder->bitmapBpp;
bi.bmiHeader.biCompression = BI_RGB;
hBitmap = CreateDIBSection(_UH.hdcOutputWindow, &bi, DIB_RGB_COLORS,
(VOID**)&pvBits, NULL, 0);
if (_UH.drawStreamAssembleCompressed) {
memcpy(pvBits, _UH.drawStreamDecompressionBuffer, pOrder->cx * pOrder->cy *
pOrder->bitmapBpp / 8);
}
else {
memcpy(pvBits, _UH.drawStreamAssembleBuffer, pOrder->cx * pOrder->cy *
pOrder->bitmapBpp / 8);
}
}
if (hBitmap != NULL) {
// set the unused bitmap
if (_UH.hUnusedDrawStreamBitmap == NULL)
_UH.hUnusedDrawStreamBitmap = SelectBitmap(_UH.hdcDrawStreamBitmap,
hBitmap);
SelectBitmap(_UH.hdcDrawStreamBitmap, hBitmap);
SelectPalette(_UH.hdcDrawStreamBitmap, _UH.hpalCurrent, FALSE);
_UH.drawStreamBitmapCache[cacheId].drawStreamBitmap = hBitmap;
_UH.drawStreamBitmapCache[cacheId].cx = pOrder->cx;
_UH.drawStreamBitmapCache[cacheId].cy = pOrder->cy;
} else {
// Unable to create the bitmap, send error pdu to the server
// to disable offscreen rendering
_UH.drawStreamBitmapCache[cacheId].drawStreamBitmap = NULL;
_UH.drawStreamBitmapCache[cacheId].cx = 0;
_UH.drawStreamBitmapCache[cacheId].cy = 0;
//if (!_UH.sendOffscrCacheErrorPDU)
// _pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
// CD_NOTIFICATION_FUNC(CUH, UHSendOffscrCacheErrorPDU),
// 0);
}
if (TRUE) {
UHBITMAPINFOPALINDEX bmpInfo = { 0 };
if (_UH.drawStreamAssembleBufferBpp != 32) {
memcpy(&bmpInfo, &_UH.pMappedColorTableCache[0], sizeof(UHBITMAPINFOPALINDEX));
bmpInfo.hdr.biWidth = _UH.drawStreamAssembleBufferWidth;
bmpInfo.hdr.biHeight = _UH.drawStreamAssembleBufferHeight;
bmpInfo.hdr.biBitCount = (TSUINT16)_UH.drawStreamAssembleBufferBpp;
}
else {
bmpInfo.hdr.biSize = sizeof(bmpInfo.hdr);
bmpInfo.hdr.biWidth = _UH.drawStreamAssembleBufferWidth;
bmpInfo.hdr.biHeight = _UH.drawStreamAssembleBufferHeight;
bmpInfo.hdr.biPlanes = 1;
bmpInfo.hdr.biBitCount = (TSUINT16)_UH.drawStreamAssembleBufferBpp;
bmpInfo.hdr.biCompression = BI_RGB;
}
if (_UH.drawStreamAssembleCompressed) {
StretchDIBits(
_UH.hdcDrawStreamBitmap,
0,
0,
(int)pOrder->cx,
(int)pOrder->cy,
0,
0,
_UH.drawStreamAssembleBufferWidth,
_UH.drawStreamAssembleBufferHeight,
_UH.drawStreamDecompressionBuffer,
(PBITMAPINFO)&bmpInfo.hdr,
DIB_RGB_COLORS,
SRCCOPY);
}
else {
StretchDIBits(
_UH.hdcDrawStreamBitmap,
0,
0,
(int)pOrder->cx,
(int)pOrder->cy,
0,
0,
_UH.drawStreamAssembleBufferWidth,
_UH.drawStreamAssembleBufferHeight,
_UH.drawStreamAssembleBuffer,
(PBITMAPINFO)&bmpInfo.hdr,
DIB_RGB_COLORS,
SRCCOPY);
}
}
DC_END_FN();
}
unsigned drawStreamSize = 0;
unsigned drawStreamPktSize = 0;
unsigned drawStreamClipSize = 0;
unsigned numDrawStreams = 0;
void DCINTERNAL CUH::UHDecodeDrawStream(PBYTE streamIn, unsigned streamSize, PBYTE streamOut,
unsigned *streamSizeOut)
{
PBYTE pul = (PBYTE) streamIn;
ULONG cjIn = streamSize;
DC_BEGIN_FN("UHDecodeDrawStream");
*streamSizeOut = 0;
while(cjIn > 0)
{
BYTE command = *pul;
unsigned commandSize;
switch(command)
{
case DS_COPYTILEID:
{
RDP_DS_COPYTILE * rdpcmd = (RDP_DS_COPYTILE *) pul;
DS_COPYTILE * cmd = (DS_COPYTILE *) streamOut;
commandSize = sizeof(*rdpcmd);
if (cjIn < commandSize) {
DC_QUIT;
}
cmd->ulCmdID = rdpcmd->ulCmdID;
TSRECT16_TO_RECTL(cmd->rclDst, rdpcmd->rclDst);
TSRECT16_TO_RECTL(cmd->rclSrc, rdpcmd->rclSrc);
TSPOINT16_TO_POINTL(cmd->ptlOrigin, rdpcmd->ptlOrigin);
*streamSizeOut += sizeof(DS_COPYTILE);
streamOut += sizeof(DS_COPYTILE);
}
break;
case DS_SOLIDFILLID:
{
RDP_DS_SOLIDFILL * rdpcmd = (RDP_DS_SOLIDFILL *) pul;
DS_SOLIDFILL * cmd = (DS_SOLIDFILL *) streamOut;
commandSize = sizeof(*rdpcmd);
if (cjIn < commandSize) {
DC_QUIT;
}
cmd->ulCmdID = rdpcmd->ulCmdID;
cmd->crSolidColor = rdpcmd->crSolidColor;
TSRECT16_TO_RECTL(cmd->rclDst, rdpcmd->rclDst);
*streamSizeOut += sizeof(DS_SOLIDFILL);
streamOut += sizeof(DS_SOLIDFILL);
}
break;
case DS_TRANSPARENTTILEID:
{
RDP_DS_TRANSPARENTTILE * rdpcmd = (RDP_DS_TRANSPARENTTILE *) pul;
DS_TRANSPARENTTILE * cmd = (DS_TRANSPARENTTILE *) streamOut;
commandSize = sizeof(*rdpcmd);
if (cjIn < commandSize) {
DC_QUIT;
}
cmd->ulCmdID = rdpcmd->ulCmdID;
cmd->crTransparentColor = rdpcmd->crTransparentColor;
TSRECT16_TO_RECTL(cmd->rclDst, rdpcmd->rclDst);
TSRECT16_TO_RECTL(cmd->rclSrc, rdpcmd->rclSrc);
TSPOINT16_TO_POINTL(cmd->ptlOrigin, rdpcmd->ptlOrigin);
*streamSizeOut += sizeof(DS_TRANSPARENTTILE);
streamOut += sizeof(DS_TRANSPARENTTILE);
}
break;
case DS_ALPHATILEID:
{
RDP_DS_ALPHATILE * rdpcmd = (RDP_DS_ALPHATILE *) pul;
DS_ALPHATILE * cmd = (DS_ALPHATILE *) streamOut;
commandSize = sizeof(*rdpcmd);
if (cjIn < commandSize) {
DC_QUIT;
}
cmd->ulCmdID = rdpcmd->ulCmdID;
cmd->blendFunction.AlphaFormat = rdpcmd->blendFunction.AlphaFormat;
cmd->blendFunction.BlendFlags = rdpcmd->blendFunction.BlendFlags;
cmd->blendFunction.BlendOp = rdpcmd->blendFunction.BlendOp;
cmd->blendFunction.SourceConstantAlpha = rdpcmd->blendFunction.SourceConstantAlpha;
TSRECT16_TO_RECTL(cmd->rclDst, rdpcmd->rclDst);
TSRECT16_TO_RECTL(cmd->rclSrc, rdpcmd->rclSrc);
TSPOINT16_TO_POINTL(cmd->ptlOrigin, rdpcmd->ptlOrigin);
*streamSizeOut += sizeof(DS_ALPHATILE);
streamOut += sizeof(DS_ALPHATILE);
}
break;
case DS_STRETCHID:
{
RDP_DS_STRETCH * rdpcmd = (RDP_DS_STRETCH *) pul;
DS_STRETCH * cmd = (DS_STRETCH *) streamOut;
commandSize = sizeof(*rdpcmd);
if (cjIn < commandSize) {
DC_QUIT;
}
cmd->ulCmdID = rdpcmd->ulCmdID;
TSRECT16_TO_RECTL(cmd->rclDst, rdpcmd->rclDst);
TSRECT16_TO_RECTL(cmd->rclSrc, rdpcmd->rclSrc);
*streamSizeOut += sizeof(DS_STRETCH);
streamOut += sizeof(DS_STRETCH);
}
break;
case DS_TRANSPARENTSTRETCHID:
{
RDP_DS_TRANSPARENTSTRETCH * rdpcmd = (RDP_DS_TRANSPARENTSTRETCH *) pul;
DS_TRANSPARENTSTRETCH * cmd = (DS_TRANSPARENTSTRETCH *) streamOut;
commandSize = sizeof(*rdpcmd);
if (cjIn < commandSize) {
DC_QUIT;
}
cmd->ulCmdID = rdpcmd->ulCmdID;
cmd->crTransparentColor = rdpcmd->crTransparentColor;
TSRECT16_TO_RECTL(cmd->rclDst, rdpcmd->rclDst);
TSRECT16_TO_RECTL(cmd->rclSrc, rdpcmd->rclSrc);
*streamSizeOut += sizeof(DS_TRANSPARENTSTRETCH);
streamOut += sizeof(DS_TRANSPARENTSTRETCH);
}
break;
case DS_ALPHASTRETCHID:
{
RDP_DS_ALPHASTRETCH * rdpcmd = (RDP_DS_ALPHASTRETCH *) pul;
DS_ALPHASTRETCH * cmd = (DS_ALPHASTRETCH *) streamOut;
commandSize = sizeof(*rdpcmd);
if (cjIn < commandSize) {
DC_QUIT;
}
cmd->ulCmdID = rdpcmd->ulCmdID;
cmd->blendFunction.AlphaFormat = rdpcmd->blendFunction.AlphaFormat;
cmd->blendFunction.BlendFlags = rdpcmd->blendFunction.BlendFlags;
cmd->blendFunction.BlendOp = rdpcmd->blendFunction.BlendOp;
cmd->blendFunction.SourceConstantAlpha = rdpcmd->blendFunction.SourceConstantAlpha;
TSRECT16_TO_RECTL(cmd->rclDst, rdpcmd->rclDst);
TSRECT16_TO_RECTL(cmd->rclSrc, rdpcmd->rclSrc);
*streamSizeOut += sizeof(DS_ALPHASTRETCH);
streamOut += sizeof(DS_ALPHASTRETCH);
}
break;
default:
{
DC_QUIT;
}
}
cjIn -= commandSize;
pul += commandSize;
}
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
// Name: UHDrawStream
/****************************************************************************/
unsigned DCINTERNAL CUH::UHDrawStream(PTS_DRAW_STREAM_ORDER pOrder)
{
typedef struct _DSSTREAM
{
DS_HEADER hdr;
DS_SETTARGET cmdSetTarget;
DS_SETSOURCE cmdSetSource;
} DSSTREAM;
unsigned bitmapId;
unsigned orderSize, streamSize;
HBITMAP hBitmap;
DSSTREAM *stream;
ULONG magic = 'DrwQ';
PBYTE streamData;
TS_RECTANGLE16 *clipRects;
DC_BEGIN_FN("UHDrawStream");
bitmapId = pOrder->BitmapID;
hBitmap = _UH.drawStreamBitmapCache[bitmapId].drawStreamBitmap;
SelectObject(_UH.hdcDrawStreamBitmap, hBitmap);
orderSize = sizeof(TS_DRAW_STREAM_ORDER) + pOrder->StreamLen +
sizeof(TS_RECTANGLE16) * pOrder->nClipRects;
drawStreamPktSize += orderSize;
drawStreamSize += pOrder->StreamLen;
drawStreamClipSize += sizeof(TS_RECTANGLE16) * pOrder->nClipRects;
numDrawStreams += 1;
// JOYC: todo need to lookinto how much to allocate.
stream = (DSSTREAM *) UT_Malloc(_pUt, sizeof(DSSTREAM) + pOrder->StreamLen * 2);
if (stream) {
HRGN hrgnUpdate;
// render
stream->hdr.magic = DS_MAGIC;
stream->cmdSetTarget.ulCmdID = DS_SETTARGETID;
stream->cmdSetTarget.hdc = _UH.hdcDraw;
stream->cmdSetTarget.rclDstClip.left = pOrder->Bounds.left;
stream->cmdSetTarget.rclDstClip.top = pOrder->Bounds.top;
stream->cmdSetTarget.rclDstClip.right = pOrder->Bounds.right;
stream->cmdSetTarget.rclDstClip.bottom = pOrder->Bounds.bottom;
stream->cmdSetSource.ulCmdID = DS_SETSOURCEID;
stream->cmdSetSource.hdc = _UH.hdcDrawStreamBitmap;
// Need to setup the clip region
clipRects = (TS_RECTANGLE16 *)(pOrder + 1);
streamData = (PBYTE)clipRects + sizeof(TS_RECTANGLE16) * pOrder->nClipRects;
UHDecodeDrawStream(streamData, pOrder->StreamLen, (PBYTE)(stream + 1), &streamSize);
streamSize += sizeof(DSSTREAM);
hrgnUpdate = CreateRectRgn(0, 0, 0, 0);
SetRectRgn(hrgnUpdate, 0, 0, 0, 0);
for (int i = 0; i < pOrder->nClipRects; i++) {
UH_ORDER OrderRect;
OrderRect.dstRect.left = clipRects[i].left;
OrderRect.dstRect.top = clipRects[i].top;
OrderRect.dstRect.right = clipRects[i].right;
OrderRect.dstRect.bottom = clipRects[i].bottom;
UHAddUpdateRegion(&OrderRect, hrgnUpdate);
#if 0
UH_HatchRectDC(_UH.hdcOutputWindow, OrderRect.dstRect.left,
OrderRect.dstRect.top,
OrderRect.dstRect.right,
OrderRect.dstRect.bottom,
UH_RGB_GREEN,
UH_BRUSHTYPE_FDIAGONAL );
#endif
}
UH_ResetClipRegion();
if (pOrder->nClipRects) {
#if defined (OS_WINCE)
_UH.validClipDC = NULL;
#endif
SelectClipRgn(_UH.hdcDraw, hrgnUpdate);
}
if (ExtEscape(_UH.hdcDraw, 201, sizeof(magic), (char *) &magic, 0, NULL))
{
ExtEscape(NULL, 200, streamSize, (char *) stream, 0, NULL);
}
else
{
// Emulate
DrawStream(streamSize, stream);
}
if (_UH.hdcDraw == _UH.hdcShadowBitmap) {
SelectClipRgn(_UH.hdcOutputWindow, NULL);
if (pOrder->nClipRects) {
SelectClipRgn(_UH.hdcOutputWindow, hrgnUpdate);
DeleteRgn(hrgnUpdate);
}
//#ifdef SMART_SIZING
// if (!_pOp->OP_CopyShadowToDC(_UH.hdcOutputWindow, pRectangle->destLeft,
// pRectangle->destTop, bltSize.width, bltSize.height)) {
// TRC_ERR((TB, _T("OP_CopyShadowToDC failed")));
// }
//#else // SMART_SIZING
if (!BitBlt( _UH.hdcOutputWindow,
pOrder->Bounds.left,
pOrder->Bounds.top,
pOrder->Bounds.right - pOrder->Bounds.left,
pOrder->Bounds.bottom - pOrder->Bounds.top,
_UH.hdcShadowBitmap,
pOrder->Bounds.left,
pOrder->Bounds.top,
SRCCOPY ))
{
TRC_ERR((TB, _T("BitBlt failed")));
}
}
else {
DeleteRgn(hrgnUpdate);
}
// cleanup
}
return orderSize;
}
unsigned DCINTERNAL CUH::UHDrawNineGrid(PTS_DRAW_NINEGRID_ORDER pOrder)
{
typedef struct _DSSTREAM
{
DS_HEADER hdr;
DS_SETTARGET cmdSetTarget;
DS_SETSOURCE cmdSetSource;
DS_NINEGRID cmdNineGrid;
} DSSTREAM;
unsigned bitmapId;
unsigned orderSize;
HBITMAP hBitmap;
DSSTREAM stream;
ULONG magic = 'DrwQ';
TS_RECTANGLE16 *clipRects;
DS_NINEGRIDINFO ngInfo;
BYTE BitmapBits[32 * 1024];
DC_BEGIN_FN("UHDrawStream");
bitmapId = pOrder->BitmapID;
hBitmap = _UH.drawStreamBitmapCache[bitmapId].drawStreamBitmap;
ngInfo.flFlags = _UH.drawStreamBitmapCache[bitmapId].dngInfo.flFlags;
ngInfo.ulLeftWidth = _UH.drawStreamBitmapCache[bitmapId].dngInfo.ulLeftWidth;
ngInfo.ulRightWidth = _UH.drawStreamBitmapCache[bitmapId].dngInfo.ulRightWidth;
ngInfo.ulTopHeight = _UH.drawStreamBitmapCache[bitmapId].dngInfo.ulTopHeight;
ngInfo.ulBottomHeight = _UH.drawStreamBitmapCache[bitmapId].dngInfo.ulBottomHeight;
ngInfo.crTransparent = _UH.drawStreamBitmapCache[bitmapId].dngInfo.crTransparent;
SelectObject(_UH.hdcDrawStreamBitmap, hBitmap);
orderSize = sizeof(TS_DRAW_NINEGRID_ORDER) + pOrder->nClipRects *
sizeof(TS_RECTANGLE16);
drawStreamPktSize += orderSize;
drawStreamClipSize += sizeof(TS_RECTANGLE16) * pOrder->nClipRects;
numDrawStreams += 1;
HRGN hrgnUpdate;
// render
stream.hdr.magic = DS_MAGIC;
stream.cmdSetTarget.ulCmdID = DS_SETTARGETID;
stream.cmdSetTarget.hdc = _UH.hdcDraw;
stream.cmdSetTarget.rclDstClip.left = pOrder->Bounds.left;
stream.cmdSetTarget.rclDstClip.top = pOrder->Bounds.top;
stream.cmdSetTarget.rclDstClip.right = pOrder->Bounds.right;
stream.cmdSetTarget.rclDstClip.bottom = pOrder->Bounds.bottom;
stream.cmdSetSource.ulCmdID = DS_SETSOURCEID;
stream.cmdSetSource.hdc = (HDC)hBitmap;
stream.cmdNineGrid.ulCmdID = DS_NINEGRIDID;
stream.cmdNineGrid.rclDst.left = pOrder->Bounds.left;
stream.cmdNineGrid.rclDst.top = pOrder->Bounds.top;
stream.cmdNineGrid.rclDst.right = pOrder->Bounds.right;
stream.cmdNineGrid.rclDst.bottom = pOrder->Bounds.bottom;
stream.cmdNineGrid.rclSrc.left = pOrder->srcBounds.left;
stream.cmdNineGrid.rclSrc.top = pOrder->srcBounds.top;
stream.cmdNineGrid.rclSrc.right = pOrder->srcBounds.right;
stream.cmdNineGrid.rclSrc.bottom = pOrder->srcBounds.bottom;
stream.cmdNineGrid.ngi = ngInfo;
// Need to setup the clip region
clipRects = (TS_RECTANGLE16 *)(pOrder + 1);
hrgnUpdate = CreateRectRgn(0, 0, 0, 0);
SetRectRgn(hrgnUpdate, 0, 0, 0, 0);
for (int i = 0; i < pOrder->nClipRects; i++) {
UH_ORDER OrderRect;
OrderRect.dstRect.left = clipRects[i].left;
OrderRect.dstRect.top = clipRects[i].top;
OrderRect.dstRect.right = clipRects[i].right;
OrderRect.dstRect.bottom = clipRects[i].bottom;
UHAddUpdateRegion(&OrderRect, hrgnUpdate);
}
UH_ResetClipRegion();
if (pOrder->nClipRects) {
#if defined (OS_WINCE)
_UH.validClipDC = NULL;
#endif
SelectClipRgn(_UH.hdcDraw, hrgnUpdate);
}
ExtEscape(_UH.hdcDraw, 200, sizeof(stream), (char*) &stream, 0, NULL);
if (_UH.hdcDraw == _UH.hdcShadowBitmap) {
SelectClipRgn(_UH.hdcOutputWindow, NULL);
if (pOrder->nClipRects) {
SelectClipRgn(_UH.hdcOutputWindow, hrgnUpdate);
DeleteRgn(hrgnUpdate);
}
//#ifdef SMART_SIZING
// if (!_pOp->OP_CopyShadowToDC(_UH.hdcOutputWindow, pRectangle->destLeft,
// pRectangle->destTop, bltSize.width, bltSize.height)) {
// TRC_ERR((TB, _T("OP_CopyShadowToDC failed")));
// }
//#else // SMART_SIZING
if (!BitBlt( _UH.hdcOutputWindow,
pOrder->Bounds.left,
pOrder->Bounds.top,
pOrder->Bounds.right - pOrder->Bounds.left,
pOrder->Bounds.bottom - pOrder->Bounds.top,
_UH.hdcShadowBitmap,
pOrder->Bounds.left,
pOrder->Bounds.top,
SRCCOPY ))
{
TRC_ERR((TB, _T("BitBlt failed")));
}
}
else {
DeleteRgn(hrgnUpdate);
}
// cleanup
return orderSize;
}
#endif
#endif //DRAW_NINEGRID
/****************************************************************************/
/* Name: UHCalculateColorTableMapping */
/* */
/* Purpose: Calculates a Mapped Color Table from a given Color Table */
/* Cache entry to the current palette. The mapping is stored */
/* in _UH.pMappedColorTableCache[cachId]. */
/****************************************************************************/
// SECURITY: Caller must verify the cacheId
void DCINTERNAL CUH::UHCalculateColorTableMapping(unsigned cacheId)
{
BOOL bIdentityPalette;
unsigned i;
DC_BEGIN_FN("UHCalculateColorTableMapping");
bIdentityPalette = TRUE;
for (i = 0; i < 256; i++) {
_UH.pMappedColorTableCache[cacheId].paletteIndexTable[i] = (UINT16)
GetNearestPaletteIndex(_UH.hpalCurrent,
RGB(_UH.pColorTableCache[cacheId].rgb[i].rgbtRed,
_UH.pColorTableCache[cacheId].rgb[i].rgbtGreen,
_UH.pColorTableCache[cacheId].rgb[i].rgbtBlue));
TRC_DBG((TB, _T("Mapping %#2x->%#2x"), i,
_UH.pMappedColorTableCache[cacheId].paletteIndexTable[i]));
// An identity palette has palette indices that match the index number
// (i.e. the array contents look like [0, 1, 2, 3, ..., 255]).
if (_UH.pMappedColorTableCache[cacheId].paletteIndexTable[i] != i)
bIdentityPalette = FALSE;
}
// Cache the identity palette flag for use during UHDIBCopyBits().
_UH.pMappedColorTableCache[cacheId].bIdentityPalette = bIdentityPalette;
DC_END_FN();
}
/****************************************************************************/
// Name: UHDrawOffscrBitmapBits
//
// Draw the offscreen bitmap onto the screen or another offscreen bitmap
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawOffscrBitmapBits(HDC hdc, MEMBLT_COMMON FAR *pMB)
{
HRESULT hr = S_OK;
UINT32 windowsROP = UHConvertToWindowsROP((unsigned)pMB->bRop);
unsigned cacheId;
HBITMAP hBitmap, hbmOld;
DC_BEGIN_FN("UHDrawOffscrBitmapBits");
cacheId = pMB->cacheIndex;
hr = UHIsValidOffsreenBitmapCacheIndex(cacheId);
DC_QUIT_ON_FAIL(hr);
hBitmap = _UH.offscrBitmapCache[cacheId].offscrBitmap;
if (hBitmap != NULL) {
#if defined (OS_WINCE)
_UH.validClipDC = NULL;
#endif
hbmOld = (HBITMAP)SelectObject(_UH.hdcOffscreenBitmap, hBitmap);
if (_UH.protocolBpp <= 8) {
SelectPalette(_UH.hdcOffscreenBitmap, _UH.hpalCurrent, FALSE);
}
if (!BitBlt(hdc, (int)pMB->nLeftRect, (int)pMB->nTopRect,
(int)pMB->nWidth, (int)pMB->nHeight, _UH.hdcOffscreenBitmap,
(int)pMB->nXSrc,
(int)pMB->nYSrc,
windowsROP))
{
TRC_ERR((TB, _T("BitBlt failed")));
}
else {
_pClx->CLX_ClxOffscrOut(_UH.hdcOffscreenBitmap,
(int)pMB->nLeftRect, (int)pMB->nTopRect);
}
}
#if 0
UH_HatchRect((int)pMB->nLeftRect, (int)pMB->nTopRect,
(int)(pMB->nLeftRect + pMB->nWidth),
(int)(pMB->nTopRect + pMB->nHeight),
UH_RGB_YELLOW,
UH_BRUSHTYPE_FDIAGONAL );
#endif
//hbmOld = SelectObject(UH.hdcOffscreenBitmap,
// hbmOld);
//hpalOld = SelectPalette(UH.hdcOffscreenBitmap,
// hpalOld, FALSE);
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
/**********************************************************************/
// UHLoadBitmapBits
//
// Find the memory entry where the cached bitmap is stored
// In the persistent caching case, the bitmap may not be in memory
// at this time. So we need to load it into the memory
/**********************************************************************/
// SECURITY - caller must verify cacheId and cacheIndex
inline void DCINTERNAL CUH::UHLoadBitmapBits(
UINT cacheId,
UINT32 cacheIndex,
PUHBITMAPCACHEENTRYHDR *ppCacheEntryHdr,
PBYTE *ppBitmapBits)
{
DC_BEGIN_FN("UHLoadBitmapBits");
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// If the bitmap is noncachable, i.e. in the waiting list, we
// retrieve the bitmap bits from the last cache entry
if (cacheIndex == BITMAPCACHE_WAITING_LIST_INDEX) {
*ppCacheEntryHdr = &(_UH.bitmapCache[cacheId].Header[
_UH.bitmapCache[cacheId].BCInfo.NumEntries]);
*ppBitmapBits = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(
_UH.bitmapCache[cacheId].BCInfo.NumEntries, cacheId);
DC_QUIT;
}
if (_UH.bitmapCache[cacheId].BCInfo.bSendBitmapKeys) {
ULONG memEntry;
PUHBITMAPCACHEPTE pPTE;
// this cache is marked persistent. So we need to check if the bitmap
// is in memory or not
pPTE = &(_UH.bitmapCache[cacheId].PageTable.PageEntries[cacheIndex]);
if (pPTE->iEntryToMem < _UH.bitmapCache[cacheId].BCInfo.NumEntries) {
// the bitmap is in memory, so we can just reference it, done
*ppCacheEntryHdr = &_UH.bitmapCache[cacheId].Header[pPTE->iEntryToMem];
#ifdef DC_HICOLOR
*ppBitmapBits = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(pPTE->iEntryToMem, cacheId);
#else
*ppBitmapBits = _UH.bitmapCache[cacheId].Entries +
pPTE->iEntryToMem * UH_CellSizeFromCacheID(cacheId);
#endif
}
else {
// the entry is not in memory. We have to load it to memory
// try to find a free memory entry if it is possible
memEntry = UHFindFreeCacheEntry(cacheId);
if (memEntry >= _UH.bitmapCache[cacheId].BCInfo.NumEntries) {
// All cache memory entries are full.
// We need to evict an entry from the cache memory
memEntry = UHEvictLRUCacheEntry(cacheId);
TRC_ASSERT((memEntry < _UH.bitmapCache[cacheId].BCInfo.NumEntries),
(TB, _T("Broken MRU list")));
}
// now we are ready to load the bitmap to memory
pPTE->iEntryToMem = memEntry;
*ppCacheEntryHdr = &_UH.bitmapCache[cacheId].Header[memEntry];
#ifdef DC_HICOLOR
*ppBitmapBits = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(memEntry, cacheId);
#else
*ppBitmapBits = _UH.bitmapCache[cacheId].Entries + memEntry *
UH_CellSizeFromCacheID(cacheId);
#endif
// try to load the bitmap file into memory
if (SUCCEEDED(UHLoadPersistentBitmap(
_UH.bitmapCache[cacheId].PageTable.CacheFileInfo.hCacheFile,
cacheIndex * (UH_CellSizeFromCacheID(cacheId) + sizeof(UHBITMAPFILEHDR)),
cacheId, memEntry, pPTE))) {
TRC_NRM((TB, _T("Load the bitmap file %s to memory"),
_UH.PersistCacheFileName));
#ifdef DC_DEBUG
// Update the bitmap cache monitor display
UHCacheEntryLoadedFromDisk(cacheId, cacheIndex);
#endif
}
else {
UINT32 currentTickCount;
// invalidate the pte entry by setting the bitmap data length on disk to 0
pPTE->bmpInfo.Key1 = 0;
pPTE->bmpInfo.Key2 = 0;
// since we failed to load the bitmap in memory,
// we need to create a replacement bitmap
(*ppCacheEntryHdr)->bitmapWidth =
(*ppCacheEntryHdr)->bitmapHeight =
(DCUINT16) (UH_CACHE_0_DIMENSION << cacheId);
#ifdef DC_HICOLOR
(*ppCacheEntryHdr)->bitmapLength = (*ppCacheEntryHdr)->bitmapWidth
* (*ppCacheEntryHdr)->bitmapHeight
* _UH.copyMultiplier;
#else
(*ppCacheEntryHdr)->bitmapLength = (*ppCacheEntryHdr)->bitmapWidth *
(*ppCacheEntryHdr)->bitmapHeight;
#endif
(*ppCacheEntryHdr)->hasData = TRUE;
// we just use a black bitmap to replace the missing one
DC_MEMSET(*ppBitmapBits, 0, (*ppCacheEntryHdr)->bitmapLength);
TRC_ALT((TB, _T("Unable to load the specified bitmap, use a replacement ")
_T("bitmap instead")));
// for the duration of a session, we can only send maximum
// MAX_NUM_ERROR_PDU_SEND numbers of error pdus to the server
// this is to avoid client flooding the server with error pdus
if (_UH.totalNumErrorPDUs < MAX_NUM_ERROR_PDU_SEND) {
// get the current tick count
currentTickCount = GetTickCount();
// if the last time we sent an error pdu is over a minute
// (60000 milli seconds) ago or if the system tick count gets
// rolled over after the last sent error pdu (so current tick
// count is less than last time error pdu sent), we will allow
// a new error pdu to be sent. otherwise, we will not allow
// a new error pdu to be sent
if (currentTickCount < _UH.lastTimeErrorPDU[cacheId]
|| currentTickCount - _UH.lastTimeErrorPDU[cacheId] > 60000) {
// update counters and flags
_UH.totalNumErrorPDUs++;
_UH.lastTimeErrorPDU[cacheId] = currentTickCount;
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH,UHSendBitmapCacheErrorPDU), cacheId);
}
}
else {
// we can't send anymore error pdus, so we have to inform
// the user at this point
if (!_UH.bWarningDisplayed) {
// we should display a warning message to the user
// if we haven't already done so.
_UH.bWarningDisplayed = TRUE;
_pCd->CD_DecoupleSimpleNotification(CD_UI_COMPONENT,
_pUi, CD_NOTIFICATION_FUNC(CUI,UI_DisplayBitmapCacheWarning), 0);
}
}
}
}
// update the mru list
UHTouchMRUCacheEntry(cacheId, cacheIndex);
}
else {
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// without persistent caching, the bitmap is definitely in memory
// so we can simply reference to the cache memory
*ppCacheEntryHdr = &(_UH.bitmapCache[cacheId].Header[cacheIndex]);
#ifdef DC_HICOLOR
*ppBitmapBits = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(cacheIndex, cacheId);
#else
*ppBitmapBits = _UH.bitmapCache[cacheId].Entries +
cacheIndex * UH_CellSizeFromCacheID(cacheId);
#endif
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
}
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
/* Name: UHGetMemBltBits */
/* */
/* Purpose: Get the bits to draw for a MemBlt order */
/* */
/* Returns: pointer to the bitmap bits */
/* */
/* Params: */
/* IN */
/* hdc : destination Device Context */
/* cacheId : the color table and bitmap cache ids to use */
/* bitmapCacheEntry : the bitmap cache entry to use */
/* */
/* OUT */
/* colorTablecacheEntry : the col table cache entry to use */
/* pCacheEntryHeader : the cacheentry */
/****************************************************************************/
PBYTE DCINTERNAL CUH::UHGetMemBltBits(
HDC hdc,
unsigned cacheId,
unsigned bitmapCacheEntry,
unsigned *pColorTableCacheEntry,
PUHBITMAPCACHEENTRYHDR *ppCacheEntryHdr)
{
unsigned bitmapCacheId;
PBYTE pBitmapBits;
DC_BEGIN_FN("UHGetMemBltBits");
DC_IGNORE_PARAMETER(hdc);
*pColorTableCacheEntry = DCHI8(cacheId);
bitmapCacheId = DCLO8(cacheId);
TRC_DBG((TB,
_T("colorTableCacheEntry(%u) bitmapCacheId(%u) bitmapCacheEntry(%u)"),
*pColorTableCacheEntry, bitmapCacheId, bitmapCacheEntry));
if (SUCCEEDED(UHIsValidBitmapCacheID(bitmapCacheId)) &&
SUCCEEDED(UHIsValidBitmapCacheIndex(bitmapCacheId, bitmapCacheEntry)))
{
#ifdef DC_DEBUG
if (_UH.MonitorEntries[0] != NULL &&
bitmapCacheEntry != BITMAPCACHE_WAITING_LIST_INDEX) {
UHCacheEntryUsed(bitmapCacheId, bitmapCacheEntry, *pColorTableCacheEntry);
if (hdc == _UH.hdcDraw)
{
/********************************************************************/
/* Increment the usage count. The Bitmap Cache Monitor calls this */
/* function - and we don't want to update the usage count for its */
/* calls, only orders that arrived in PDUs. */
/********************************************************************/
_UH.MonitorEntries[bitmapCacheId][bitmapCacheEntry].UsageCount++;
}
}
#endif
// find the memory entry where the cached bitmap is stored
UHLoadBitmapBits(bitmapCacheId, bitmapCacheEntry, ppCacheEntryHdr,
&pBitmapBits);
}
else
{
pBitmapBits = NULL;
DC_QUIT;
}
if ((*ppCacheEntryHdr)->hasData)
{
_UH.pMappedColorTableCache[*pColorTableCacheEntry].hdr.biWidth =
(*ppCacheEntryHdr)->bitmapWidth;
_UH.pMappedColorTableCache[*pColorTableCacheEntry].hdr.biHeight =
(*ppCacheEntryHdr)->bitmapHeight;
TRC_ASSERT(((*ppCacheEntryHdr)->bitmapHeight < 65536),
(TB, _T("cache entry bitmap height unexpectedly exceeds 16-bits")));
#ifdef DC_HICOLOR
TRC_ASSERT(!IsBadReadPtr(pBitmapBits,
(DCUINT)((*ppCacheEntryHdr)->bitmapWidth *
(*ppCacheEntryHdr)->bitmapHeight *
_UH.copyMultiplier)),
(TB, _T("Decompressed %ux%u bitmap: not %u bytes readable"),
(DCUINT)(*ppCacheEntryHdr)->bitmapWidth,
(DCUINT)(*ppCacheEntryHdr)->bitmapHeight,
(DCUINT)((*ppCacheEntryHdr)->bitmapWidth *
(*ppCacheEntryHdr)->bitmapHeight *
_UH.copyMultiplier)));
#else
TRC_ASSERT(!IsBadReadPtr(pBitmapBits,
(DCUINT)((*ppCacheEntryHdr)->bitmapWidth *
(*ppCacheEntryHdr)->bitmapHeight)),
(TB, _T("Decompressed %ux%u bitmap: not %u bytes readable"),
(DCUINT)(*ppCacheEntryHdr)->bitmapWidth,
(DCUINT)(*ppCacheEntryHdr)->bitmapHeight,
(DCUINT)((*ppCacheEntryHdr)->bitmapWidth *
(*ppCacheEntryHdr)->bitmapHeight)));
#endif
}
else {
TRC_ERR((TB, _T("Cache entry %u:%u referenced before being filled"),
bitmapCacheId, bitmapCacheEntry));
pBitmapBits = NULL;
}
DC_EXIT_POINT:
DC_END_FN();
return pBitmapBits;
}
/****************************************************************************/
/* Name: UHDrawMemBltOrder */
/* */
/* Purpose: Draws a MemBlt order into _UH.hdcDraw */
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHDrawMemBltOrder(HDC hdc, MEMBLT_COMMON FAR *pMB)
{
HRESULT hr = S_OK;
unsigned colorTableCacheEntry;
unsigned bitmapCacheId;
UINT cbBitmapBits;
PUHBITMAPCACHEENTRYHDR pCacheEntryHdr;
PDCUINT8 pBitmapBits;
UINT32 windowsROP = UHConvertToWindowsROP((unsigned)pMB->bRop);
#ifdef OS_WINCE
DCUINT row;
PDCUINT8 pSrc;
PDCUINT8 pDst;
HBITMAP hbmOld;
HPALETTE hpalOld;
#endif
DC_BEGIN_FN("UHDrawMemBltOrder");
bitmapCacheId = DCLO8(pMB->cacheId);
/************************************************************************/
/* get the actual bits to draw */
/************************************************************************/
// SECURITY - the cacheId and cacheIndex will be verified by UHGetMemBltBits
pBitmapBits = UHGetMemBltBits(hdc, pMB->cacheId, pMB->cacheIndex,
&colorTableCacheEntry, &pCacheEntryHdr);
if (pBitmapBits != NULL)
{
TRC_NRM((TB,
_T("dstLeft(%d) dstTop(%d) srcLeft(%d) srcTop(%d) ")
_T("bltWidth(%d) bltHeight(%d), rop(%#x/%#x)"),
(int)pMB->nLeftRect,
(int)pMB->nTopRect,
(int)pMB->nXSrc,
(int)pCacheEntryHdr->bitmapHeight - (int)pMB->nYSrc - (int)pMB->nHeight,
(int)pMB->nWidth, (int)pMB->nHeight,
pMB->bRop, windowsROP));
#ifdef DC_HICOLOR
cbBitmapBits = pCacheEntryHdr->bitmapWidth *
pCacheEntryHdr->bitmapHeight * _UH.copyMultiplier;
#else
cbBitmapBits = pCacheEntryHdr->bitmapWidth * pCacheEntryHdr->bitmapHeight;
#endif // DC_HICOLOR
// Draw!
TIMERSTART;
#ifdef USE_DIBSECTION
// We can only use UHDIBCopyBits if this is a simple copy and the shadow
// bitmap is enabled.
if ((_UH.usingDIBSection) && (windowsROP == SRCCOPY) &&
#ifdef USE_GDIPLUS
(_UH.shadowBitmapBpp == _UH.protocolBpp) &&
#endif // USE_GDIPLUS
(hdc == _UH.hdcShadowBitmap))
{
TRC_DBG((TB, _T("Using UH DI blt...")));
if (!UHDIBCopyBits(hdc, (int)pMB->nLeftRect, (int)pMB->nTopRect,
(int)pMB->nWidth, (int)pMB->nHeight, (int)pMB->nXSrc,
(int)pCacheEntryHdr->bitmapHeight - (int)pMB->nYSrc - (int)pMB->nHeight,
pBitmapBits, cbBitmapBits,
(PBITMAPINFO)&(_UH.pMappedColorTableCache[colorTableCacheEntry].hdr),
_UH.pMappedColorTableCache[colorTableCacheEntry].
bIdentityPalette))
{
TRC_ERR((TB, _T("UHDIBCopyBits failed")));
}
}
else
#endif /* USE_DIBSECTION */
#ifndef OS_WINCE
{
#ifdef DC_HICOLOR
TRC_DBG((TB, _T("Stretch blt size %d x %d"), pMB->nWidth, pMB->nHeight));
if (StretchDIBits(
hdc,
(int)pMB->nLeftRect,
(int)pMB->nTopRect,
(int)pMB->nWidth,
(int)pMB->nHeight,
(int)pMB->nXSrc,
(int)pCacheEntryHdr->bitmapHeight - (int)pMB->nYSrc - (int)pMB->nHeight,
(int)pMB->nWidth,
(int)pMB->nHeight,
pBitmapBits,
(PBITMAPINFO)&(_UH.pMappedColorTableCache[colorTableCacheEntry].hdr),
_UH.DIBFormat,
windowsROP) == 0)
#else
if (StretchDIBits(hdc,
(int)pMB->nLeftRect,
(int)pMB->nTopRect,
(int)pMB->nWidth,
(int)pMB->nHeight,
(int)pMB->nXSrc,
(int)pCacheEntryHdr->bitmapHeight - (int)pMB->nYSrc - (int)pMB->nHeight,
(int)pMB->nWidth,
(int)pMB->nHeight,
pBitmapBits,
(PBITMAPINFO)&(_UH.pMappedColorTableCache[
colorTableCacheEntry].hdr),
DIB_PAL_COLORS,
windowsROP) == 0)
#endif
{
TRC_ERR((TB, _T("StretchDIBits failed")));
}
}
#else // OS_WINCE
{
// Workaround for missing StretchDIBits in WinCE. Copy bits into a
// cached DIB Section and Blt to the target.
#ifdef DC_HICOLOR
if (_UH.protocolBpp <= 8)
{
#endif
hpalOld = SelectPalette(_UH.hdcMemCached, _UH.hpalCurrent, FALSE);
#ifdef DC_HICOLOR
}
#endif
// Copy into the cached DIB Section.
pSrc = pBitmapBits;
pDst = _UH.hBitmapCacheDIBits;
TRC_DBG((TB, _T("cache size (%d %d)"), pCacheEntryHdr->bitmapWidth,
pCacheEntryHdr->bitmapHeight));
if (pCacheEntryHdr->bitmapWidth >
(UH_CACHE_0_DIMENSION << (_UH.NumBitmapCaches - 1))) {
TRC_ABORT((TB, _T("Cache tile is too big")));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
if (pCacheEntryHdr->bitmapHeight >
(UH_CACHE_0_DIMENSION << (_UH.NumBitmapCaches - 1))) {
TRC_ABORT((TB, _T("Cache tile is too big")));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
#ifdef DC_HICOLOR
DWORD dwDstInc = (UH_CACHE_0_DIMENSION << (_UH.NumBitmapCaches - 1)) * _UH.copyMultiplier;
DWORD dwSrcInc = pCacheEntryHdr->bitmapWidth * _UH.copyMultiplier;
DWORD dwLineWidth = pCacheEntryHdr->bitmapWidth * _UH.copyMultiplier;
for (row = 0; row < pCacheEntryHdr->bitmapHeight; row++) {
DC_MEMCPY(pDst, pSrc, dwLineWidth);
pDst += dwDstInc;
pSrc += dwSrcInc;
}
#else
for (row = 0; row < pCacheEntryHdr->bitmapHeight; row++) {
DC_MEMCPY(pDst, pSrc, pCacheEntryHdr->bitmapWidth);
pDst += (UH_CACHE_0_DIMENSION << (_UH.NumBitmapCaches - 1));
pSrc += pCacheEntryHdr->bitmapWidth;
}
#endif
// Copy to the screen / shadow.
hbmOld = (HBITMAP)SelectObject(_UH.hdcMemCached, _UH.hBitmapCacheDIB);
if (!BitBlt(hdc, (int)pMB->nLeftRect, (int)pMB->nTopRect,
(int)pMB->nWidth, (int)pMB->nHeight, _UH.hdcMemCached,
(int)pMB->nXSrc,
(UH_CACHE_0_DIMENSION << (_UH.NumBitmapCaches - 1)) -
pCacheEntryHdr->bitmapHeight + (int)pMB->nYSrc,
windowsROP))
{
TRC_ERR((TB, _T("BitBlt failed")));
}
SelectBitmap(_UH.hdcMemCached, hbmOld);
#ifdef DC_HICOLOR
if (_UH.protocolBpp <= 8)
{
#endif
hpalOld = SelectPalette(_UH.hdcMemCached, hpalOld, FALSE);
#ifdef DC_HICOLOR
}
#endif
}
#endif // OS_WINCE
TIMERSTOP;
UPDATECOUNTER(FC_MEMBLT_TYPE);
#ifdef VLADIMIS // future CLX extension
_pClx->CLX_ClxBitmap((UINT)pCacheEntryHdr->bitmapWidth,
(UINT)pCacheEntryHdr->bitmapHeight,
pBitmapBits,
(UINT)sizeof(_UH.pMappedColorTableCache[colorTableCacheEntry]),
&_UH.pMappedColorTableCache[colorTableCacheEntry].hdr);
#endif
}
else if (bitmapCacheId > _UH.NumBitmapCaches){
hr = UHDrawOffscrBitmapBits(hdc, pMB);
DC_QUIT_ON_FAIL(hr);
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
#ifdef USE_DIBSECTION
/****************************************************************************/
// UHDIBCopyBits
//
// Fast Blt from bitmap cache to DIB section shadow bitmap. Work-around for
// the fact that StretchDIBits is over 6x slower when drawing to a DIB than
// when drawing to a normal bitmap. This routine runs between 5x and 25x
// faster, but is limited in that it assumes a bottom-up source (bitmap cache)
// and a top-down dest (shadow bitmap), both 8bpp. Returns nonzero on success.
/****************************************************************************/
BOOL DCINTERNAL CUH::UHDIBCopyBits(
HDC hdc,
int xDst,
int yDst,
int bltWidth,
int bltHeight,
int xSrc,
int ySrc,
PBYTE pSrcBits,
UINT cbSrcBits, // This length may be longer than what needs to be read
PBITMAPINFO pSrcInfo,
BOOL bIdentityPalette)
{
BOOL rc = FALSE;
HBITMAP dstBitmap;
DIBSECTION dibSection;
PBYTE pDstBits;
PBYTE pDstBitsEnd;
PBYTE pSrcBitsEnd;
PBYTE pSrcRow;
PBYTE pDstRow;
PBYTE pSrcPel;
PBYTE pDstPel;
int rowsCopied;
UINT uiBMPSize;
BYTE *endRow;
UINT16 FAR *colorTable = (UINT16 FAR *)pSrcInfo->bmiColors;
int xOffset;
int yOffset;
#ifdef DC_HICOLOR
unsigned srcIncrement;
unsigned dstIncrement;
#endif
DC_BEGIN_FN("UHDIBCopyBits");
TRC_ASSERT( ((xDst >= 0) && (yDst >= 0)),
(TB,_T("Invalid offset [xDst=%d yDst=%d]"), xDst, yDst ));
dstBitmap = (HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
if (dstBitmap != NULL) {
if (sizeof(dibSection) !=
GetObject(dstBitmap, sizeof(dibSection), &dibSection)) {
TRC_ERR((TB, _T("GetObject failed")));
DC_QUIT;
}
}
else {
TRC_ERR((TB, _T("Failed GetCurrentObject")));
DC_QUIT;
}
TRC_DBG((TB, _T("Blt: src(%d,%d), dest(%d,%d), size %dx%d"),
xSrc, ySrc, xDst, yDst, bltWidth, bltHeight));
#ifdef DC_DEBUG
if (_UH.protocolBpp > 8) {
TRC_ASSERT((bIdentityPalette),(TB,_T("Non-palette depth but identity FALSE")));
}
else {
BOOL bIdent = TRUE;
unsigned i;
// Make sure the passed-in identity flag matches reality.
for (i = 0; i < UH_NUM_8BPP_PAL_ENTRIES; i++) {
if ((BYTE)colorTable[i] != (BYTE)i) {
bIdent = FALSE;
break;
}
}
TRC_ASSERT((bIdent && bIdentityPalette) || (!bIdent && !bIdentityPalette),
(TB,_T("Cached ident flag %u does not match real data"),
bIdentityPalette));
}
#endif // DC_DEBUG
TRC_DBG((TB, _T("%s color map"), bIdentityPalette ? _T("identity") : _T("complex")));
if (_UH.rectReset) {
TRC_DBG((TB, _T("No clipping in force")));
}
else {
TRC_NRM((TB, _T("Clip rect in force (%d,%d)-(%d,%d)"),
_UH.lastLeft, _UH.lastTop, _UH.lastRight, _UH.lastBottom));
// x clip calculations.
xOffset = _UH.lastLeft - xDst;
if (xOffset > 0) {
xDst = _UH.lastLeft;
xSrc += xOffset;
bltWidth -= xOffset;
}
bltWidth = DC_MIN(bltWidth, _UH.lastRight - xDst + 1);
// y clip calculations (remember source is bottom-up!).
yOffset = _UH.lastTop - yDst;
if (yOffset > 0) {
yDst = _UH.lastTop;
bltHeight -= yOffset;
}
yOffset = (yDst + bltHeight - 1) - _UH.lastBottom;
if (yOffset > 0) {
ySrc += yOffset;
bltHeight -= yOffset;
}
TRC_DBG((TB, _T("Post-clip: src(%d,%d), dest(%d,%d), %dx%d"),
xSrc, ySrc, xDst, yDst, bltWidth, bltHeight));
}
pDstBits = (PBYTE)dibSection.dsBm.bmBits;
pDstBitsEnd = pDstBits +
(dibSection.dsBm.bmHeight * dibSection.dsBm.bmWidthBytes);
// Check that we do not over read the bitmap data
uiBMPSize = BMP_SIZE(pSrcInfo->bmiHeader);
if (uiBMPSize > cbSrcBits) {
TRC_ERR((TB,_T("Copying bitmap bits would overread")));
DC_QUIT;
}
pSrcBitsEnd = pSrcBits + uiBMPSize;
#ifndef DC_HICOLOR
// Get starting points for copy.
pSrcRow = pSrcBits + ((ySrc + bltHeight - 1) *
pSrcInfo->bmiHeader.biWidth) + xSrc;
pDstRow = pDstBits + (yDst * dibSection.dsBm.bmWidth) + xDst;
#endif
if (bIdentityPalette || _UH.protocolBpp > 8) {
// Fast path - just copy row-by-row.
#ifdef DC_HICOLOR
// We duplicate the start points calculation below to avoid any
// overhead from a multiplication by 1.
pSrcRow = pSrcBits +
(((ySrc + bltHeight - 1) * pSrcInfo->bmiHeader.biWidth) + xSrc) *
_UH.copyMultiplier;
pDstRow = pDstBits +
((yDst * dibSection.dsBm.bmWidth) + xDst) * _UH.copyMultiplier;
srcIncrement = pSrcInfo->bmiHeader.biWidth * _UH.copyMultiplier;
dstIncrement = dibSection.dsBm.bmWidth * _UH.copyMultiplier;
if (bltHeight) {
CHECK_READ_N_BYTES_2ENDED_NO_HR(pSrcRow-((bltHeight-1)*srcIncrement),
pSrcBits, pSrcBitsEnd,
((bltHeight-1)*srcIncrement) + (bltWidth * _UH.copyMultiplier),
(TB, _T("Blt will buffer overread")));
CHECK_WRITE_N_BYTES_2ENDED_NO_HR(pDstRow, pDstBits, pDstBitsEnd,
((bltHeight-1)*dstIncrement) + (bltWidth * _UH.copyMultiplier),
(TB,_T("Blt will BO")));
}
for (rowsCopied = 0; rowsCopied < bltHeight; rowsCopied++) {
memcpy(pDstRow, pSrcRow, bltWidth * _UH.copyMultiplier);
pSrcRow -= srcIncrement;
pDstRow += dstIncrement;
}
#else
if (bltHeight) {
CHECK_READ_N_BYTES_2ENDED_NO_HR(
pSrcRow-((bltHeight-1)*pSrcInfo->bmiHeader.biWidth),
pSrcBits, pSrcBitsEnd,
((bltHeight-1)*pSrcInfo->bmiHeader.biWidth) + bltWidth,
(TB, _T("Blt will buffer overread")));
CHECK_WRITE_N_BYTES_2ENDED_NO_HR(pDstRow, pDstBits, pDstBitsEnd,
((bltHeight-1)*dibSection.dsBm.bmWidth) + bltWidth,
(TB,_T("Blt will BO")));
}
for (rowsCopied = 0; rowsCopied < bltHeight; rowsCopied++) {
memcpy(pDstRow, pSrcRow, bltWidth);
pSrcRow -= pSrcInfo->bmiHeader.biWidth;
pDstRow += dibSection.dsBm.bmWidth;
}
#endif
}
else {
// Copy pixel-by-pixel, doing color table mapping as we go.
#ifdef DC_HICOLOR
// This code duplicates that above except for the copy multiplier,
// which we know *must* be one for this (8bpp) arm.
TRC_ASSERT((_UH.copyMultiplier == 1),
(TB, _T("Copy multiplier %d must be 1"), _UH.copyMultiplier));
pSrcRow = pSrcBits + ((ySrc + bltHeight - 1) *
pSrcInfo->bmiHeader.biWidth) + xSrc;
pDstRow = pDstBits + (yDst * dibSection.dsBm.bmWidth) + xDst;
#endif
if (bltHeight) {
CHECK_READ_N_BYTES_2ENDED_NO_HR(
pSrcRow-((bltHeight-1)*pSrcInfo->bmiHeader.biWidth),
pSrcBits, pSrcBitsEnd,
((bltHeight-1)*pSrcInfo->bmiHeader.biWidth) + bltWidth,
(TB, _T("Blt will buffer overread")));
CHECK_WRITE_N_BYTES_2ENDED_NO_HR(pDstRow, pDstBits, pDstBitsEnd,
((bltHeight-1) * dibSection.dsBm.bmWidth) + bltWidth,
(TB,_T("Blt will BO")));
}
for (rowsCopied = 0; rowsCopied < bltHeight; rowsCopied++) {
for (pDstPel = pDstRow,
pSrcPel = pSrcRow,
endRow = pDstRow + bltWidth;
pDstPel < endRow;
pDstPel++, pSrcPel++)
{
*pDstPel = (BYTE)colorTable[*pSrcPel];
}
pSrcRow -= pSrcInfo->bmiHeader.biWidth;
pDstRow += dibSection.dsBm.bmWidth;
}
}
rc = TRUE;
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
#endif /* USE_DIBSECTION */
#ifdef DC_DEBUG
/****************************************************************************/
/* Name: UHLabelMemBltOrder */
/* */
/* Purpose: Labels a MemBlt order by drawing text into _UH.hdcDraw */
/* */
/* Returns: Nothing */
/* */
/* Params: dstLeft : destination left coordinate */
/* dstTop : destination top coordinate */
/* cacheId : the color table and bitmap cache ids to use */
/* bitmapCacheEntry: the bitmap cache entry to use */
/****************************************************************************/
void DCINTERNAL CUH::UHLabelMemBltOrder(
int dstLeft,
int dstTop,
unsigned cacheId,
unsigned bitmapCacheEntry)
{
unsigned bitmapCacheId;
TCHAR outputString[20];
int oldBkMode;
HFONT hFont;
HFONT hFontOld;
COLORREF oldBkColor;
COLORREF oldTextColor;
LOGFONT lf;
HRESULT hr;
#ifndef OS_WINCE
UINT oldAlign;
#endif
DC_BEGIN_FN("UHLabelMemBltOrder");
bitmapCacheId = DCLO8(cacheId);
if (_UH.MonitorEntries[0] != NULL) {
hr = StringCchPrintf(
outputString,
SIZE_TCHARS(outputString),
_T("%u:%u(%u) "),
bitmapCacheId, bitmapCacheEntry,
_UH.MonitorEntries[bitmapCacheId][bitmapCacheEntry].UsageCount);
}
else {
hr = StringCchPrintf(outputString, SIZE_TCHARS(outputString),
_T("%u:%u "), bitmapCacheId, bitmapCacheEntry);
}
//Fixed buffer so the sprintf should not fail
TRC_ASSERT(SUCCEEDED(hr),
(TB,_T("Error copying printf'ing outputString: 0x%x"), hr));
lf.lfHeight = 8;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = FW_NORMAL;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfStrikeOut = 0;
lf.lfCharSet = 0;
lf.lfOutPrecision = 0;
lf.lfClipPrecision = 0;
lf.lfQuality = 0;
lf.lfPitchAndFamily = 0;
StringCchCopy(lf.lfFaceName, SIZE_TCHARS(lf.lfFaceName),
_T("Small Fonts"));
hFont = CreateFontIndirect(&lf);
hFontOld = SelectFont(_UH.hdcDraw, hFont);
oldBkColor = SetBkColor(_UH.hdcDraw, RGB(255,0,0));
oldTextColor = SetTextColor(_UH.hdcDraw, RGB(255,255,255));
#ifndef OS_WINCE
// WinCE doesn't support this call, but these would be the defaults anyway.
oldAlign = SetTextAlign(_UH.hdcDraw, TA_TOP | TA_LEFT);
#endif
oldBkMode = SetBkMode(_UH.hdcDraw, OPAQUE);
ExtTextOut( _UH.hdcDraw,
dstLeft,
dstTop,
0,
NULL,
outputString,
DC_TSTRLEN(outputString),
NULL );
#ifndef OS_WINCE
SetTextAlign(_UH.hdcDraw, oldAlign);
#endif // OS_WINCE
SetBkMode(_UH.hdcDraw, oldBkMode);
SetTextColor(_UH.hdcDraw, oldTextColor);
SetBkColor(_UH.hdcDraw, oldBkColor);
SelectFont(_UH.hdcDraw, hFontOld);
DeleteFont(hFont);
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
/* Name: UHInitBitmapCacheMonitor */
/* */
/* Purpose: Initializes the Bitmap Cache Monitor. */
/****************************************************************************/
void DCINTERNAL CUH::UHInitBitmapCacheMonitor()
{
WNDCLASS wndclass;
WNDCLASS tmpWndClass;
DC_BEGIN_FN("UHInitBitmapCacheMonitor");
// Create the bitmap monitor window.
#if !defined(OS_WINCE) || defined(OS_WINCEOWNEDDC)
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
#else // !defined(OS_WINCE) || defined(OS_WINCEOWNEDDC)
wndclass.style = CS_HREDRAW | CS_VREDRAW;
#endif // !defined(OS_WINCE) || defined(OS_WINCEOWNEDDC)
if(!GetClassInfo(_pUi->UI_GetInstanceHandle(),UH_BITMAP_CACHE_MONITOR_CLASS_NAME, &tmpWndClass))
{
wndclass.lpfnWndProc = UHStaticBitmapCacheWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = sizeof(void*);
wndclass.hInstance = _pUi->UI_GetInstanceHandle();
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)GetStockObject(HOLLOW_BRUSH);
wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = UH_BITMAP_CACHE_MONITOR_CLASS_NAME;
RegisterClass(&wndclass);
}
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
#ifndef WS_THICKFRAME
#define WS_THICKFRAME 0x00040000L
#endif
_UH.hwndBitmapCacheMonitor = CreateWindow(
UH_BITMAP_CACHE_MONITOR_CLASS_NAME, _T("Bitmap cache monitor"),
WS_OVERLAPPED | WS_THICKFRAME, 0, 0, 400, 600, NULL, NULL,
_pUi->UI_GetInstanceHandle(), this);
#else // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
_UH.hwndBitmapCacheMonitor = CreateWindow(
UH_BITMAP_CACHE_MONITOR_CLASS_NAME, _T("Bitmap cache monitor"),
WS_OVERLAPPED | WS_BORDER, 0, 0, 400, 500, NULL, NULL,
_pUi->UI_GetInstanceHandle(), this);
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
DC_END_FN();
}
/****************************************************************************/
/* Name: UHTermBitmapCacheMonitor */
/* */
/* Purpose: Terminates the Bitmap Cache Monitor. */
/****************************************************************************/
void DCINTERNAL CUH::UHTermBitmapCacheMonitor()
{
DC_BEGIN_FN("UHTermBitmapCacheMonitor");
/************************************************************************/
/* Destroy the Bitmap Cache Monitor window and unregister its class */
/************************************************************************/
DestroyWindow(_UH.hwndBitmapCacheMonitor);
UnregisterClass(UH_BITMAP_CACHE_MONITOR_CLASS_NAME,
_pUi->UI_GetInstanceHandle());
DC_END_FN();
}
/****************************************************************************/
// UHEnableBitmapCacheMonitor
//
// Initializes the bitmap cache monitor with the current session's
// negotiated bitmap cache settings.
/****************************************************************************/
void DCINTERNAL CUH::UHEnableBitmapCacheMonitor(void)
{
unsigned i;
ULONG NumEntries;
DC_BEGIN_FN("UHEnableBitmapCacheMonitor");
TRC_ASSERT((_UH.MonitorEntries[0] == NULL),(TB,_T("BCMonitor already has ")
_T("allocated memory")));
// Total the number of entries we have, allocate memory for corresponding
// monitor entries.
NumEntries = 0;
for (i = 0; i < _UH.NumBitmapCaches; i++) {
if (_UH.bitmapCache[i].BCInfo.bSendBitmapKeys)
NumEntries += _UH.bitmapCache[i].BCInfo.NumVirtualEntries;
else
NumEntries += _UH.bitmapCache[i].BCInfo.NumEntries;
}
_UH.MonitorEntries[0] = (UH_CACHE_MONITOR_ENTRY_DATA*)UT_MallocHuge(_pUt, NumEntries *
sizeof(UH_CACHE_MONITOR_ENTRY_DATA));
if (_UH.MonitorEntries[0] != NULL) {
// Init the per-cache entry pointers.
for (i = 1; i < _UH.NumBitmapCaches; i++) {
if (_UH.bitmapCache[i - 1].BCInfo.bSendBitmapKeys)
_UH.MonitorEntries[i] = _UH.MonitorEntries[i - 1] +
_UH.bitmapCache[i - 1].BCInfo.NumVirtualEntries;
else
_UH.MonitorEntries[i] = _UH.MonitorEntries[i - 1] +
_UH.bitmapCache[i - 1].BCInfo.NumEntries;
}
// Init all the entries to an unused state.
memset(_UH.MonitorEntries[0], 0, NumEntries *
sizeof(UH_CACHE_MONITOR_ENTRY_DATA));
_UH.displayedCacheId = 0;
_UH.displayedCacheEntry = 0;
// Recalc the cell display characteristics based on the now-negotiated
// capabilities.
SendMessage(_UH.hwndBitmapCacheMonitor, WM_RECALC_CELL_SPACING, 0, 0);
/********************************************************************/
// Force the window to repaint with the new values.
/********************************************************************/
InvalidateRect(_UH.hwndBitmapCacheMonitor, NULL, FALSE);
}
else {
TRC_ERR((TB,_T("Failed to alloc bitmap monitor memory")));
}
DC_END_FN();
}
/****************************************************************************/
// UHDisconnectBitmapCacheMonitor
//
// Closes down the cache monitor and deallocates memory at end of session.
/****************************************************************************/
void DCINTERNAL CUH::UHDisconnectBitmapCacheMonitor(void)
{
DC_BEGIN_FN("UHDisconnectBitmapCacheMonitor");
TRC_ASSERT((_UH.NumBitmapCaches == 0),(TB,_T("Cache settings not reset yet")));
// Free the cache memory and reset the pointers.
if (_UH.MonitorEntries[0] != NULL) {
UT_Free( _pUt, _UH.MonitorEntries[0]);
memset(_UH.MonitorEntries, 0, sizeof(UH_CACHE_MONITOR_ENTRY_DATA *) *
TS_BITMAPCACHE_MAX_CELL_CACHES);
}
// Recalc the cell display characteristics based on the reset
// capabilities.
SendMessage(_UH.hwndBitmapCacheMonitor, WM_RECALC_CELL_SPACING, 0, 0);
/************************************************************************/
/* Force the window to repaint with the new values. */
/************************************************************************/
InvalidateRect(_UH.hwndBitmapCacheMonitor, NULL, FALSE);
DC_END_FN();
}
/****************************************************************************/
/* Name: UHStaticBitmapCacheWndProc */
/* */
/* Purpose: Bitmap Cache Window WndProc (static version) */
/****************************************************************************/
LRESULT CALLBACK CUH::UHStaticBitmapCacheWndProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
CUH* pUH = (CUH*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
if(WM_CREATE == message)
{
//pull out the this pointer and stuff it in the window class
LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
pUH = (CUH*)lpcs->lpCreateParams;
SetWindowLongPtr( hwnd, GWLP_USERDATA, (LONG_PTR)pUH);
}
//
// Delegate the message to the appropriate instance
//
return pUH->UHBitmapCacheWndProc(hwnd, message, wParam, lParam);
}
/****************************************************************************/
/* Name: UHBitmapCacheWndProc */
/* */
/* Purpose: Bitmap Cache Window WndProc */
/****************************************************************************/
LRESULT CALLBACK CUH::UHBitmapCacheWndProc( HWND hwnd,
UINT message,
WPARAM wParam,
LPARAM lParam )
{
LRESULT rc = 0;
DC_BEGIN_FN("UHBitmapCacheWndProc");
switch (message)
{
case WM_SHOWWINDOW:
{
DCBOOL shown;
shown = (DCBOOL)wParam;
/****************************************************************/
/* Only run the timer when the window is visible. */
/****************************************************************/
if (shown)
{
_UH.timerBitmapCacheMonitor =
SetTimer(hwnd, 0, UH_CACHE_MONITOR_UPDATE_PERIOD, NULL);
TRC_NRM((TB, _T("Timer started")));
}
else
{
KillTimer(hwnd, _UH.timerBitmapCacheMonitor);
_UH.timerBitmapCacheMonitor = 0;
TRC_NRM((TB, _T("Timer stopped")));
}
}
break;
case WM_TIMER:
{
UINT32 timeNow;
ULONG Entry, NumEntries;
unsigned cacheId;
RECT rect;
if (_UH.MonitorEntries[0] != NULL) {
timeNow = GetTickCount();
/****************************************************************/
/* Update the timers for every cache entry, and if necessary */
/* invalidate the corresponding cache blob to force a repaint */
/* in the new state. */
/****************************************************************/
for (cacheId = 0; cacheId < _UH.NumBitmapCaches; cacheId++) {
if (!_UH.bitmapCache[cacheId].BCInfo.bSendBitmapKeys)
NumEntries = _UH.bitmapCache[cacheId].BCInfo.NumEntries;
else
NumEntries = _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries;
for (Entry = 0; Entry < NumEntries; Entry++) {
if (_UH.MonitorEntries[cacheId][Entry].EventTime != 0 &&
(timeNow - _UH.MonitorEntries[cacheId][Entry].
EventTime) > UH_CACHE_FLASH_PERIOD) {
// Reset the transition and timer.
_UH.MonitorEntries[cacheId][Entry].EventTime = 0;
_UH.MonitorEntries[cacheId][Entry].FlashTransition =
UH_CACHE_TRANSITION_NONE;
UHGetCacheBlobRect(cacheId, Entry, &rect);
InvalidateRect(_UH.hwndBitmapCacheMonitor, &rect,
FALSE);
}
}
}
}
}
break;
case WM_LBUTTONDOWN:
{
POINT mousePos;
ULONG cacheEntry;
unsigned cacheId;
mousePos.x = LOWORD(lParam);
mousePos.y = HIWORD(lParam);
/****************************************************************/
/* The left button has been clicked. Update the displayed */
/* bitmap if the current position maps to a different cache */
/* entry. */
/****************************************************************/
if (UHGetCacheBlobFromPoint( &mousePos,
&cacheId,
&cacheEntry ))
{
if ( (cacheId != _UH.displayedCacheId) ||
(cacheEntry != _UH.displayedCacheEntry) )
{
_UH.displayedCacheId = cacheId;
_UH.displayedCacheEntry = cacheEntry;
UHRefreshDisplayedCacheEntry();
}
}
}
break;
case WM_MOUSEMOVE:
{
POINT mousePos;
ULONG cacheEntry;
unsigned cacheId;
mousePos.x = LOWORD(lParam);
mousePos.y = HIWORD(lParam);
/****************************************************************/
/* If the left button is pressed then update the displayed */
/* bitmap if the current position maps to a different cache */
/* entry. */
/****************************************************************/
if (wParam & MK_LBUTTON)
{
if (UHGetCacheBlobFromPoint(&mousePos, &cacheId, &cacheEntry))
{
if ( (cacheId != _UH.displayedCacheId) ||
(cacheEntry != _UH.displayedCacheEntry) )
{
_UH.displayedCacheId = cacheId;
_UH.displayedCacheEntry = cacheEntry;
UHRefreshDisplayedCacheEntry();
}
}
}
}
break;
case WM_SIZE:
{
DCUINT clientWidth;
DCUINT outputAreaWidth;
/****************************************************************/
/* The window has been sized. Calculate the positions to */
/* draw each cache and the displayed bitmap. */
/****************************************************************/
clientWidth = LOWORD(lParam);
outputAreaWidth =
clientWidth - (2 * UH_CACHE_WINDOW_BORDER_WIDTH);
_UH.numCacheBlobsPerRow = outputAreaWidth /
UH_CACHE_BLOB_TOTAL_WIDTH;
SendMessage(hwnd, WM_RECALC_CELL_SPACING, 0, 0);
}
break;
case WM_RECALC_CELL_SPACING:
{
unsigned i;
ULONG NumEntries;
_UH.yCacheStart[0] = UH_CACHE_WINDOW_BORDER_WIDTH;
if (_UH.numCacheBlobsPerRow > 0) {
for (i = 1; i < _UH.NumBitmapCaches; i++) {
if (!_UH.bitmapCache[i - 1].BCInfo.bSendBitmapKeys)
NumEntries = _UH.bitmapCache[i - 1].BCInfo.NumEntries;
else
NumEntries = _UH.bitmapCache[i - 1].BCInfo.NumVirtualEntries;
_UH.yCacheStart[i] = _UH.yCacheStart[i - 1] + (unsigned)
(((NumEntries / _UH.numCacheBlobsPerRow) + 1) *
UH_CACHE_BLOB_TOTAL_HEIGHT) +
UH_INTER_CACHE_SPACING;
}
if (_UH.NumBitmapCaches)
{
if (!_UH.bitmapCache[_UH.NumBitmapCaches - 1].BCInfo.bSendBitmapKeys)
NumEntries = _UH.bitmapCache[_UH.NumBitmapCaches - 1].BCInfo.NumEntries;
else
NumEntries = _UH.bitmapCache[_UH.NumBitmapCaches - 1].BCInfo.NumVirtualEntries;
_UH.yDisplayedCacheBitmapStart = _UH.yCacheStart[
_UH.NumBitmapCaches - 1] + (unsigned)
(((NumEntries / _UH.numCacheBlobsPerRow) + 1) *
UH_CACHE_BLOB_TOTAL_HEIGHT) + UH_INTER_CACHE_SPACING;
}
else
{
NumEntries = 0;
}
}
}
break;
case WM_PAINT:
{
HDC hdc;
PAINTSTRUCT ps;
RECT clientRect;
RECT rect;
HBRUSH StateBrush[UH_CACHE_NUM_STATES];
HBRUSH TransitionBrush[UH_CACHE_NUM_TRANSITIONS];
HBRUSH hbrToUse;
HBRUSH hbrGray;
ULONG i, NumEntries;
DCINT outputAreaWidth;
DCUINT numBlobsPerRow;
DCUINT cacheId;
HPALETTE hpalOld;
hdc = BeginPaint(hwnd, &ps);
if (hdc == NULL)
{
TRC_SYSTEM_ERROR("BeginPaint failed");
break;
}
#ifdef DC_HICOLOR
if (_UH.protocolBpp <= 8)
{
#endif
/****************************************************************/
/* Use the current palette, so that the colors are drawn */
/* correctly by UHDisplayCacheEntry. */
/****************************************************************/
hpalOld = SelectPalette(hdc, _UH.hpalCurrent, FALSE);
RealizePalette(hdc);
#ifdef DC_HICOLOR
}
#endif
/****************************************************************/
// Create a bunch of useful brushes.
/****************************************************************/
hbrGray = (HBRUSH)GetStockObject(GRAY_BRUSH);
StateBrush[UH_CACHE_STATE_UNUSED] = (HBRUSH)GetStockObject(LTGRAY_BRUSH);
#ifndef OS_WINCE
StateBrush[UH_CACHE_STATE_IN_MEMORY] =
CreateSolidBrush(UH_RGB_GREEN);
StateBrush[UH_CACHE_STATE_ON_DISK] =
CreateSolidBrush(UH_RGB_BLUE);
TransitionBrush[UH_CACHE_TRANSITION_NONE] = NULL;
TransitionBrush[UH_CACHE_TRANSITION_TOUCHED] =
(HBRUSH)CreateSolidBrush(UH_RGB_YELLOW);
TransitionBrush[UH_CACHE_TRANSITION_EVICTED] =
(HBRUSH)GetStockObject(BLACK_BRUSH);
TransitionBrush[UH_CACHE_TRANSITION_LOADED_FROM_DISK] =
(HBRUSH)GetStockObject(WHITE_BRUSH);
TransitionBrush[UH_CACHE_TRANSITION_KEY_LOAD_ON_SESSION_START] =
(HBRUSH)CreateSolidBrush(UH_RGB_MAGENTA);
TransitionBrush[UH_CACHE_TRANSITION_SERVER_UPDATE] =
(HBRUSH)CreateSolidBrush(UH_RGB_RED);
#else
StateBrush[UH_CACHE_STATE_IN_MEMORY] =
CECreateSolidBrush(UH_RGB_GREEN);
StateBrush[UH_CACHE_STATE_ON_DISK] =
CECreateSolidBrush(UH_RGB_BLUE);
TransitionBrush[UH_CACHE_TRANSITION_NONE] = NULL;
TransitionBrush[UH_CACHE_TRANSITION_TOUCHED] =
(HBRUSH)CECreateSolidBrush(UH_RGB_YELLOW);
TransitionBrush[UH_CACHE_TRANSITION_EVICTED] =
(HBRUSH)GetStockObject(BLACK_BRUSH);
TransitionBrush[UH_CACHE_TRANSITION_LOADED_FROM_DISK] =
(HBRUSH)GetStockObject(WHITE_BRUSH);
TransitionBrush[UH_CACHE_TRANSITION_KEY_LOAD_ON_SESSION_START] =
(HBRUSH)CECreateSolidBrush(UH_RGB_MAGENTA);
TransitionBrush[UH_CACHE_TRANSITION_SERVER_UPDATE] =
(HBRUSH)CECreateSolidBrush(UH_RGB_RED);
#endif
/****************************************************************/
/* Paint the background */
/****************************************************************/
GetClientRect(hwnd, &clientRect);
FillRect(hdc, &clientRect, hbrGray);
/****************************************************************/
/* Draw the cache blobs. */
/****************************************************************/
outputAreaWidth = (clientRect.right - clientRect.left) -
(2 * UH_CACHE_WINDOW_BORDER_WIDTH);
numBlobsPerRow = outputAreaWidth / UH_CACHE_BLOB_TOTAL_WIDTH;
if (_UH.MonitorEntries[0] != NULL) {
for (cacheId = 0; cacheId < _UH.NumBitmapCaches; cacheId++) {
if (!_UH.bitmapCache[cacheId].BCInfo.bSendBitmapKeys)
NumEntries = _UH.bitmapCache[cacheId].BCInfo.NumEntries;
else
NumEntries = _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries;
for (i = 0; i < NumEntries; i++) {
/********************************************************/
/* Get the rectangle that represents this cache entry. */
/********************************************************/
UHGetCacheBlobRect(cacheId, i, &rect);
// Determine the brush to use according to transition and
// state.
if (_UH.MonitorEntries[cacheId][i].FlashTransition ==
UH_CACHE_TRANSITION_NONE)
hbrToUse = StateBrush[_UH.MonitorEntries[cacheId][i].
State];
else
hbrToUse = TransitionBrush[_UH.MonitorEntries[
cacheId][i].FlashTransition];
/********************************************************/
/* Color the blob appropriately. */
/********************************************************/
FillRect(hdc, &rect, hbrToUse);
}
}
}
/****************************************************************/
/* If the update region includes any part of the displayed */
/* cache bitmap area, and we've not exited the session then */
/* paint it. */
/* */
/* This test avoids repainting the displayed cache bitmap */
/* every time a cache blob flashes (which is very often!). */
/****************************************************************/
if (ps.rcPaint.bottom > (int)_UH.yDisplayedCacheBitmapStart &&
_UH.NumBitmapCaches > 0)
UHDisplayCacheEntry(hdc, _UH.displayedCacheId,
_UH.displayedCacheEntry);
// Clean up.
#ifndef OS_WINCE
for (i = 0; i < UH_CACHE_NUM_STATES; i++)
DeleteBrush(StateBrush[i]);
for (i = 1; i < UH_CACHE_NUM_TRANSITIONS; i++)
DeleteBrush(TransitionBrush[i]);
#else
CEDeleteBrush(StateBrush[UH_CACHE_STATE_IN_MEMORY]);
CEDeleteBrush(StateBrush[UH_CACHE_STATE_ON_DISK]);
CEDeleteBrush(TransitionBrush[UH_CACHE_TRANSITION_TOUCHED]);
CEDeleteBrush(TransitionBrush[UH_CACHE_TRANSITION_KEY_LOAD_ON_SESSION_START]);
CEDeleteBrush(TransitionBrush[UH_CACHE_TRANSITION_SERVER_UPDATE]);
#endif
#ifdef DC_HICOLOR
if (_UH.protocolBpp <= 8)
{
#endif
SelectPalette(hdc, hpalOld, FALSE);
#ifdef DC_HICOLOR
}
#endif
EndPaint(hwnd, &ps);
}
break;
default:
{
rc = DefWindowProc(hwnd, message, wParam, lParam);
}
break;
}
DC_END_FN();
return rc;
} /* UHBitmapCacheWndProc */
/****************************************************************************/
// UHSetMonitorEntryState
//
// Common function to change a cache entry to a new state and cause the
// UI to be redrawn.
/****************************************************************************/
void DCINTERNAL CUH::UHSetMonitorEntryState(
unsigned CacheID,
ULONG CacheIndex,
BYTE State,
BYTE Transition)
{
RECT rect;
DC_BEGIN_FN("UHSetMonitorEntryState");
if (_UH.MonitorEntries[0] != NULL ) {
// The state type marks whether this entry in now on disk or in memory.
TRC_ASSERT((State < UH_CACHE_NUM_STATES),
(TB,_T("State out of bounds %d"), State));
_UH.MonitorEntries[CacheID][CacheIndex].State = State;
TRC_NRM((TB, _T("CacheID %d, Index %d: State %d Trans %d"), CacheID,
CacheIndex, State, Transition));
// If this transition is more important (higher in number) than the
// current transition, the timer gets reset to the current time and
// the new transition takes over.
TRC_ASSERT((Transition < UH_CACHE_NUM_TRANSITIONS),
(TB,_T("Transition out of bounds %d"), Transition));
if (Transition > _UH.MonitorEntries[CacheID][CacheIndex].FlashTransition) {
_UH.MonitorEntries[CacheID][CacheIndex].FlashTransition = Transition;
_UH.MonitorEntries[CacheID][CacheIndex].EventTime = GetTickCount();
}
// Force a repaint of the corresponding cache blob.
UHGetCacheBlobRect(CacheID, CacheIndex, &rect);
InvalidateRect(_UH.hwndBitmapCacheMonitor, &rect, FALSE);
}
DC_END_FN();
}
/****************************************************************************/
/* Name: UHCacheDataReceived */
/* */
/* Purpose: Performs required actions when new data for a cache entry is */
/* received. */
/* */
/* Params: cacheId - cache id */
/* cacheEntry - cache entry */
/****************************************************************************/
void DCINTERNAL CUH::UHCacheDataReceived(unsigned cacheId, ULONG cacheEntry)
{
DC_BEGIN_FN("UHCacheDataReceived");
if (_UH.MonitorEntries[0] != NULL) {
/************************************************************************/
/* Reset the usage count. */
/************************************************************************/
_UH.MonitorEntries[cacheId][cacheEntry].UsageCount = 0;
// Change the state.
UHSetMonitorEntryState(cacheId, cacheEntry, UH_CACHE_STATE_IN_MEMORY,
UH_CACHE_TRANSITION_SERVER_UPDATE);
/************************************************************************/
/* If the new data is for the cache entry currently displayed */
/* (unlikely, but it can happen!). */
/************************************************************************/
if (cacheId == _UH.displayedCacheId &&
cacheEntry == _UH.displayedCacheEntry)
UHRefreshDisplayedCacheEntry();
}
DC_END_FN();
}
/****************************************************************************/
/* Name: UHCacheEntryUsed */
/* */
/* Purpose: Performs required actions when a cache entry is used. */
/* */
/* Params: cacheId - cache id */
/* cacheEntry - cache entry */
/****************************************************************************/
// SECURITY - caller must verify cacheId and cacheIndex
void DCINTERNAL CUH::UHCacheEntryUsed(
unsigned cacheId,
ULONG cacheEntry,
unsigned colorTableCacheEntry)
{
DC_BEGIN_FN("UHCacheEntryUsed");
if (_UH.MonitorEntries[0] != NULL) {
// Store the color table.
_UH.MonitorEntries[cacheId][cacheEntry].ColorTable =
(BYTE)colorTableCacheEntry;
UHSetMonitorEntryState(cacheId, cacheEntry, UH_CACHE_STATE_IN_MEMORY,
UH_CACHE_TRANSITION_TOUCHED);
}
DC_END_FN();
}
/****************************************************************************/
/* Name: UHRefreshDisplayedCacheEntry */
/* */
/* Purpose: Forces a repaint of the displayed cache entry. */
/****************************************************************************/
void DCINTERNAL CUH::UHRefreshDisplayedCacheEntry()
{
RECT rect;
DC_BEGIN_FN("UHRefreshDisplayedCacheEntry");
if (_UH.MonitorEntries[0] != NULL) {
// Set the "touched" transition to color the bitmap entry.
if (_UH.MonitorEntries[_UH.displayedCacheId][_UH.displayedCacheEntry].
FlashTransition < UH_CACHE_TRANSITION_TOUCHED) {
_UH.MonitorEntries[_UH.displayedCacheId][_UH.displayedCacheEntry].
FlashTransition = UH_CACHE_TRANSITION_TOUCHED;
_UH.MonitorEntries[_UH.displayedCacheId][_UH.displayedCacheEntry].
EventTime = GetTickCount();
// Force a repaint of the corresponding cache blob.
UHGetCacheBlobRect(_UH.displayedCacheId, _UH.displayedCacheEntry,
&rect);
InvalidateRect(_UH.hwndBitmapCacheMonitor, &rect, FALSE);
}
GetClientRect(_UH.hwndBitmapCacheMonitor, &rect);
rect.top = _UH.yDisplayedCacheBitmapStart;
InvalidateRect(_UH.hwndBitmapCacheMonitor, &rect, FALSE);
}
DC_END_FN();
}
/****************************************************************************/
/* Name: UHDisplayCacheEntry */
/* */
/* Purpose: Displays a given cache entry bitmap. */
/* */
/* Params: hdc - DC handle */
/* cacheId - cache id */
/* cacheEntry - cache entry */
/****************************************************************************/
// SECURITY - caller should verify cacheId and cacheEntry
void DCINTERNAL CUH::UHDisplayCacheEntry(
HDC hdc,
unsigned cacheId,
ULONG cacheEntry)
{
PUHBITMAPCACHEENTRYHDR pCacheEntryHdr;
HBRUSH hbrGray;
RECT rect;
HFONT hFont;
HFONT hFontOld;
DCTCHAR stringBuffer[160];
SIZE stringSize;
LOGFONT lf;
ULONG MemEntry;
MEMBLT_COMMON MB;
HRESULT hr;
DC_BEGIN_FN("UHDisplayCacheEntry");
if (_UH.MonitorEntries[0] != NULL) {
/************************************************************************/
/* Erase the background. */
/************************************************************************/
hbrGray = (HBRUSH)GetStockObject(GRAY_BRUSH);
GetClientRect(_UH.hwndBitmapCacheMonitor, &rect);
rect.top = _UH.yDisplayedCacheBitmapStart;
FillRect(hdc, &rect, hbrGray);
// Do some initial checks to see if we should continue.
TRC_ASSERT((cacheId < _UH.NumBitmapCaches),
(TB,_T("CacheID received (%u) is out of range!"), cacheId));
if (_UH.MonitorEntries[cacheId][cacheEntry].State == UH_CACHE_STATE_UNUSED)
DC_QUIT;
/************************************************************************/
// Load the font for the descriptive text.
/************************************************************************/
lf.lfHeight = UH_CACHE_DISPLAY_FONT_SIZE;
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
lf.lfWeight = UH_CACHE_DISPLAY_FONT_WEIGHT;
lf.lfItalic = 0;
lf.lfUnderline = 0;
lf.lfStrikeOut = 0;
lf.lfCharSet = 0;
lf.lfOutPrecision = 0;
lf.lfClipPrecision = 0;
lf.lfQuality = 0;
lf.lfPitchAndFamily = 0;
StringCchCopy(lf.lfFaceName, SIZE_TCHARS(lf.lfFaceName),
UH_CACHE_DISPLAY_FONT_NAME);
hFont = CreateFontIndirect(&lf);
hFontOld = SelectFont(hdc, hFont);
SetBkMode(hdc, TRANSPARENT);
/************************************************************************/
// Locate the cached bitmap information. If we're using a persistent
// cache with a PTE table, make sure the entry is in memory.
/************************************************************************/
if (_UH.bitmapCache[cacheId].BCInfo.bSendBitmapKeys) {
// Persistent cache.
MemEntry = _UH.bitmapCache[cacheId].PageTable.PageEntries[cacheEntry].
iEntryToMem;
if (MemEntry >= _UH.bitmapCache[cacheId].BCInfo.NumEntries) {
// Entry not in memory.
StringCchCopy(stringBuffer, SIZE_TCHARS(stringBuffer),
_T("Entry not in memory"));
goto DisplayText;
}
}
else {
// Memory cache.
MemEntry = cacheEntry;
}
pCacheEntryHdr = &_UH.bitmapCache[cacheId].Header[MemEntry];
hr = StringCchPrintf(stringBuffer,
SIZE_TCHARS(stringBuffer),
_T("entry(%u:%u) cx(%u) cy(%u) size(%u) cellsize(%u) usage(%u)"),
cacheId, cacheEntry, pCacheEntryHdr->bitmapWidth,
pCacheEntryHdr->bitmapHeight, pCacheEntryHdr->bitmapLength,
pCacheEntryHdr->bitmapWidth * pCacheEntryHdr->bitmapHeight,
_UH.MonitorEntries[cacheId][cacheEntry].UsageCount);
TRC_ASSERT(SUCCEEDED(hr),
(TB,_T("Error copying printf'ing stringBuffer: 0x%x"), hr));
/************************************************************************/
/* Query the string height (so we know where to position the bitmap). */
/************************************************************************/
GetTextExtentPoint(hdc, stringBuffer, DC_TSTRLEN(stringBuffer),
&stringSize);
/************************************************************************/
// Draw the cached bitmap. Must be sure here that the entry in question
// is already in memory since we don't want debug code to cause memory
// cache evictions and disk loads.
/************************************************************************/
MB.cacheId = (UINT16)(cacheId |
((unsigned)(_UH.MonitorEntries[cacheId][cacheEntry].ColorTable) <<
8));
MB.cacheIndex = (UINT16)cacheEntry;
MB.nLeftRect = UH_CACHE_WINDOW_BORDER_WIDTH;
MB.nTopRect = _UH.yDisplayedCacheBitmapStart + stringSize.cy +
UH_CACHE_TEXT_SPACING;
MB.nWidth = pCacheEntryHdr->bitmapWidth;
MB.nHeight = pCacheEntryHdr->bitmapHeight;
MB.bRop = 0xCC;
MB.nXSrc = 0;
MB.nYSrc = 0;
UHDrawMemBltOrder(hdc, &MB);
DisplayText:
ExtTextOut(hdc, UH_CACHE_WINDOW_BORDER_WIDTH,
_UH.yDisplayedCacheBitmapStart, 0, NULL, stringBuffer,
DC_TSTRLEN(stringBuffer), NULL);
SelectFont(hdc, hFontOld);
DeleteFont(hFont);
}
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
/* Name: GetCacheBlobRect */
/* */
/* Purpose: Returns the rectangle (in client coords) that the given */
/* cache entry is displayed in. */
/* */
/* Params: IN: cacheId - cache Id */
/* IN: cacheEntry - cache entry */
/* OUT: pRect - pointer to rect that receives the coordinates */
/****************************************************************************/
void DCINTERNAL CUH::UHGetCacheBlobRect(
unsigned cacheId,
ULONG cacheEntry,
LPRECT pRect)
{
DC_BEGIN_FN("UHGetCacheBlobRect");
/************************************************************************/
/* Check for invisible window. */
/************************************************************************/
if (_UH.numCacheBlobsPerRow == 0)
{
pRect->left = 0;
pRect->top = 0;
pRect->right = 0;
pRect->bottom = 0;
DC_QUIT;
}
/************************************************************************/
/* Do the calculation. */
/************************************************************************/
pRect->left = (int)(UH_CACHE_WINDOW_BORDER_WIDTH +
(cacheEntry % _UH.numCacheBlobsPerRow) *
UH_CACHE_BLOB_TOTAL_WIDTH);
pRect->top = (int)(_UH.yCacheStart[cacheId] +
(cacheEntry / _UH.numCacheBlobsPerRow) *
UH_CACHE_BLOB_TOTAL_HEIGHT);
pRect->right = pRect->left + UH_CACHE_BLOB_WIDTH;
pRect->bottom = pRect->top + UH_CACHE_BLOB_HEIGHT;
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
/* Name: UHGetCacheBlobFromPoint */
/* */
/* Purpose: Returns the cache entry (blob) displayed at a given point */
/* in the Bitmap Cache Monitor Window. */
/* */
/* Returns: TRUE if the given point maps to a cache blob, FALSE otherwise */
/* */
/* Params: IN: pPoint - pointer to coordinates to test */
/* */
/* OUT: pCacheId - pointer to variable that receives the cache */
/* id, if return code is TRUE. */
/* */
/* OUT: pCacheEntry - pointer to variable that receives the */
/* cache entry, if return code is TRUE. */
/****************************************************************************/
BOOL DCINTERNAL CUH::UHGetCacheBlobFromPoint(
LPPOINT pPoint,
unsigned *pCacheId,
ULONG *pCacheEntry)
{
int x, y;
BOOL rc = FALSE;
ULONG cacheEntry;
unsigned cacheId;
DC_BEGIN_FN("UHGetCacheBlobFromPoint");
/************************************************************************/
/* Calculate the x-coord of the selected blob. */
/************************************************************************/
x = (pPoint->x - UH_CACHE_WINDOW_BORDER_WIDTH) /
UH_CACHE_BLOB_TOTAL_WIDTH;
/************************************************************************/
/* If the x-coord is outside the displayed range then exit immediately. */
/************************************************************************/
if (x < 0 || x >= (DCINT)_UH.numCacheBlobsPerRow)
DC_QUIT;
/************************************************************************/
/* Go through each cache in turn, and see if the supplied point */
/* corresponds to a valid blob for that cache. */
/************************************************************************/
for (cacheId = 0; cacheId < _UH.NumBitmapCaches; cacheId++)
{
if (pPoint->y >= (DCINT)_UH.yCacheStart[cacheId])
{
y = (pPoint->y - _UH.yCacheStart[cacheId]) /
UH_CACHE_BLOB_TOTAL_HEIGHT;
cacheEntry = x + (y * _UH.numCacheBlobsPerRow);
if ((!_UH.bitmapCache[cacheId].BCInfo.bSendBitmapKeys &&
cacheEntry < _UH.bitmapCache[cacheId].BCInfo.NumEntries) ||
(_UH.bitmapCache[cacheId].BCInfo.bSendBitmapKeys &&
cacheEntry < _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries))
{
/************************************************************/
/* This is a valid cacheEntry - return it. */
/************************************************************/
*pCacheId = cacheId;
*pCacheEntry = cacheEntry;
rc = TRUE;
DC_QUIT;
}
}
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
#endif /* DC_DEBUG */
/****************************************************************************/
/* Name: UHAllocColorTableCacheMemory */
/* */
/* Purpose: Dynamically allocates memory for the color table cache. */
/* */
/* Returns: TRUE if successful, FALSE otherwise */
/****************************************************************************/
BOOL DCINTERNAL CUH::UHAllocColorTableCacheMemory()
{
UINT32 colorTableCacheSize;
UINT32 mappedColorTableCacheSize;
DCBOOL rc = FALSE;
DC_BEGIN_FN("UHAllocColorTableCacheMemory");
// Calculate the total byte size of the color table cache.
colorTableCacheSize = sizeof(*(_UH.pColorTableCache)) *
UH_COLOR_TABLE_CACHE_ENTRIES;
mappedColorTableCacheSize = sizeof(*(_UH.pMappedColorTableCache)) *
UH_COLOR_TABLE_CACHE_ENTRIES;
// Get the memory.
_UH.pColorTableCache = (PUHCACHEDCOLORTABLE)UT_Malloc(_pUt,
(unsigned)colorTableCacheSize);
if (_UH.pColorTableCache != NULL) {
// Alloc the color map table.
TRC_DBG((TB, _T("Try for color mapped table")));
_UH.pMappedColorTableCache = (PUHBITMAPINFOPALINDEX)UT_Malloc(_pUt,
(unsigned)mappedColorTableCacheSize);
if (_UH.pMappedColorTableCache != NULL) {
// Successfully allocated color table cache memory.
TRC_NRM((TB, _T("Allocated %#x bytes for color table cache"),
(DCUINT)colorTableCacheSize));
TRC_NRM((TB, _T("Allocated %#x bytes for mapped color table cache"),
(DCUINT)mappedColorTableCacheSize));
rc = TRUE;
}
else {
// Memory allocation failure. Free what we allocated already.
TRC_ERR((TB, _T("Failed to allocate %#x bytes for mapped color ")
_T("table cache"), (unsigned)mappedColorTableCacheSize));
UT_Free( _pUt, _UH.pColorTableCache);
_UH.pColorTableCache = NULL;
}
}
else {
// Memory allocation failure.
TRC_ERR((TB, _T("Failed to allocate %#x bytes for color table cache"),
(unsigned)colorTableCacheSize));
}
DC_END_FN();
return rc;
}
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/****************************************************************************/
// UHEvictLRUCacheEntry
//
// Evict the least recently used Cache Entry
/****************************************************************************/
// SECURITY - caller must verify cacheId
UINT32 DCINTERNAL CUH::UHEvictLRUCacheEntry(UINT cacheId)
{
ULONG memEntry;
ULONG iEntry;
ULONG inext;
ULONG iprev;
DC_BEGIN_FN("UHEvictLRUCacheEntry");
TRC_ASSERT((cacheId < TS_BITMAPCACHE_MAX_CELL_CACHES),
(TB, _T("Invalid cache ID %u"), cacheId));
// Evict the last entry in the MRU list
iEntry = _UH.bitmapCache[cacheId].PageTable.MRUTail;
TRC_NRM((TB, _T("Select %u for eviction"), iEntry));
TRC_ASSERT((iEntry < _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries),
(TB, _T("Broken/empty MRU list")));
// We need to update the MRU chain
inext = _UH.bitmapCache[cacheId].PageTable.PageEntries[iEntry].mruList.next;
iprev = _UH.bitmapCache[cacheId].PageTable.PageEntries[iEntry].mruList.prev;
TRC_ASSERT((inext == _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries),
(TB,_T("The MRU Chain is broken")));
if (iprev < _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries) {
// remove this entry from the MRU chain
_UH.bitmapCache[cacheId].PageTable.PageEntries[iprev].mruList.next = inext;
}
else {
// this entry is the head entry from MRU chain, leaving MRU chain empty
_UH.bitmapCache[cacheId].PageTable.MRUHead = inext;
}
// update the tail of the MRU chain
_UH.bitmapCache[cacheId].PageTable.MRUTail = iprev;
// Find the iEntry in the physical cache
memEntry = _UH.bitmapCache[cacheId].PageTable.PageEntries[iEntry].iEntryToMem;
// reset this node's page table entry
_UH.bitmapCache[cacheId].PageTable.PageEntries[iEntry].iEntryToMem =
_UH.bitmapCache[cacheId].BCInfo.NumEntries;
_UH.bitmapCache[cacheId].PageTable.PageEntries[iEntry].mruList.prev =
_UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries;
_UH.bitmapCache[cacheId].PageTable.PageEntries[iEntry].mruList.next =
_UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries;
#ifdef DC_DEBUG
UHCacheEntryEvictedFromMem((unsigned)cacheId, iEntry);
#endif
DC_END_FN();
return memEntry;
}
/****************************************************************************/
// UHFindFreeCacheEntry
//
// Find a free cache entry:
/****************************************************************************/
// SECURITY - caller must verify cacheId
UINT32 DCINTERNAL CUH::UHFindFreeCacheEntry (UINT cacheId)
{
UINT32 memEntry;
DC_BEGIN_FN("UHFindFreeCacheEntry");
TRC_ASSERT((cacheId < TS_BITMAPCACHE_MAX_CELL_CACHES),
(TB, _T("Invalid cache ID %u"), cacheId));
TRC_NRM((TB, _T("Searching cache %u for free entry"), cacheId));
// Get the entry pointed to by free list
memEntry = _UH.bitmapCache[cacheId].PageTable.FreeMemList;
if (memEntry == _UH.bitmapCache[cacheId].BCInfo.NumEntries) {
TRC_NRM((TB, _T("Physical cache %u memory is full"), cacheId));
}
else {
TRC_NRM((TB, _T("Free entry at %u"), memEntry));
// update our free list
_UH.bitmapCache[cacheId].PageTable.FreeMemList =
*(PDCUINT32)(&_UH.bitmapCache[cacheId].Header[memEntry]);
}
DC_END_FN();
return memEntry;
}
/****************************************************************************/
// UHTouchMRUCacheEntry
//
// Move a PTE cache entry to the head of the MRU PTE list
/****************************************************************************/
// SECURITY - caller must verify cacheId and iEntry
VOID DCINTERNAL CUH::UHTouchMRUCacheEntry(UINT cacheId, UINT32 iEntry)
{
ULONG inext;
ULONG iprev;
HPUHBITMAPCACHEPTE pageEntry;
DC_BEGIN_FN("UHTouchMRUCacheEntry");
TRC_ASSERT((cacheId < TS_BITMAPCACHE_MAX_CELL_CACHES),
(TB, _T("Invalid cache ID %u"), cacheId));
// point to the page table entry for this cache
pageEntry = _UH.bitmapCache[cacheId].PageTable.PageEntries;
/************************************************************************/
// Move this entry to the head of the MRU list
/************************************************************************/
if (_UH.bitmapCache[cacheId].PageTable.MRUHead != iEntry) {
iprev = pageEntry[iEntry].mruList.prev;
inext = pageEntry[iEntry].mruList.next;
TRC_NRM((TB, _T("Add/Remove entry %u which was chained off %u to %u"),
iEntry, iprev, inext));
if (iprev != _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries) {
// This entry is currently chained in the MRU list
// Need to remove the entry from the current MRU List first
pageEntry[iprev].mruList.next = inext;
if (inext != _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries) {
pageEntry[inext].mruList.prev = iprev;
}
else {
// this entry was the tail of the mru list. So we need
// to update the MRU tail.
_UH.bitmapCache[cacheId].PageTable.MRUTail = iprev;
}
}
/*********************************************************************/
// Add this entry to the head of the MRU List
/*********************************************************************/
// this entry's next should point to the head of current MRU list
// its prev should point to an invalid entry
inext = _UH.bitmapCache[cacheId].PageTable.MRUHead;
pageEntry[iEntry].mruList.next = inext;
pageEntry[iEntry].mruList.prev = _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries;
// we also need to update the MRU head to point to this entry
_UH.bitmapCache[cacheId].PageTable.MRUHead = iEntry;
if (inext != _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries) {
// link this new head entry to the rest of the mru list
pageEntry[inext].mruList.prev = iEntry;
}
else {
// mru list was empty. This entry is actually the first node
// added to the mru list.
// so the mru tail should point to this node too
_UH.bitmapCache[cacheId].PageTable.MRUTail = iEntry;
}
TRC_NRM((TB, _T("Cache %u entry %u to head of MRU list"), cacheId, iEntry));
}
else {
// this entry is already at the head of MRU list. No update is needed
TRC_NRM((TB, _T("Cache %u entry %u already at head of MRU List"),
cacheId, iEntry));
}
DC_END_FN();
}
/****************************************************************************/
// UHInitBitmapCachePageTable
//
// Initialize the MRU, Free List, etc of a bitmap page table
/****************************************************************************/
// SECURITY - caller must verify cacheId
_inline VOID DCINTERNAL CUH::UHInitBitmapCachePageTable(UINT cacheId)
{
UINT32 i;
PDCUINT32 pFreeList;
DC_BEGIN_FN("UHInitBitmapCachePageTable");
_UH.bitmapCache[cacheId].PageTable.MRUHead = _UH.bitmapCache[cacheId]
.BCInfo.NumVirtualEntries;
_UH.bitmapCache[cacheId].PageTable.MRUTail = _UH.bitmapCache[cacheId]
.BCInfo.NumVirtualEntries;
_UH.bitmapCache[cacheId].PageTable.FreeMemList = 0;
// set up the free list
pFreeList = (PDCUINT32) (_UH.bitmapCache[cacheId].Header);
for (i = 0; i < _UH.bitmapCache[cacheId].BCInfo.NumEntries; i++) {
*pFreeList = i+1;
pFreeList = (PDCUINT32) &(_UH.bitmapCache[cacheId].Header[i+1]);
}
// initialize the mru list
for (i = 0; i < _UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries; i++) {
_UH.bitmapCache[cacheId].PageTable.PageEntries[i].bmpInfo.Key1 = 0;
_UH.bitmapCache[cacheId].PageTable.PageEntries[i].bmpInfo.Key2 = 0;
_UH.bitmapCache[cacheId].PageTable.PageEntries[i].mruList.prev =
_UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries;
_UH.bitmapCache[cacheId].PageTable.PageEntries[i].mruList.next =
_UH.bitmapCache[cacheId].BCInfo.NumVirtualEntries;
_UH.bitmapCache[cacheId].PageTable.PageEntries[i].iEntryToMem =
_UH.bitmapCache[cacheId].BCInfo.NumEntries;
}
DC_END_FN();
}
/****************************************************************************/
// UHAllocBitmapCachePageTable
//
// Dynamically allocates memory for UH bitmap cache Page Table of cacheId
/****************************************************************************/
// SECURITY - caller must verify cacheId
inline BOOL DCINTERNAL CUH::UHAllocBitmapCachePageTable(
UINT32 NumEntries,
UINT cacheId)
{
DCBOOL rc = FALSE;
DCUINT32 dataSize;
DC_BEGIN_FN("UHAllocBitmapCachePageTable");
if (NumEntries) {
/************************************************************************/
/* Calculate the total byte size to allocate for this cache. */
/************************************************************************/
dataSize = (ULONG)NumEntries * (ULONG) sizeof(UHBITMAPCACHEPTE);
TRC_NRM((TB, _T("Allocate Bitmap Page Table with %u entries: %#lx bytes"),
NumEntries, dataSize));
/************************************************************************/
/* Get the memory for the cache data */
/************************************************************************/
_UH.bitmapCache[cacheId].PageTable.PageEntries = (PUHBITMAPCACHEPTE)UT_MallocHuge( _pUt, dataSize);
if (_UH.bitmapCache[cacheId].PageTable.PageEntries != NULL) {
TRC_DBG((TB, _T("Allocated %#lx bytes for bitmap cache page table"), dataSize));
UHInitBitmapCachePageTable(cacheId);
rc = TRUE;
}
else {
TRC_ERR((TB, _T("Failed to allocate %#lx bytes for bitmap cache page table"),
dataSize));
}
}
else {
TRC_ALT((TB, _T("0 bytes are allocated for bitmap cache page table")));
}
DC_END_FN();
return rc;
}
/****************************************************************************/
// UHCreateCacheDirectory
//
// Try to create the bitmap cache directory
/****************************************************************************/
BOOL DCINTERNAL CUH::UHCreateCacheDirectory(void)
{
BOOL rc = TRUE;
int i = 0;
DC_BEGIN_FN("UHCreateCacheDirectory");
// Skip the first : to make sure the directory path contains
// the drive letter
while (_UH.PersistCacheFileName[i] != 0 &&
_UH.PersistCacheFileName[i++] != _T(':'));
// Skip the first \ because it's the one after drive letter
// assuming \ is right after :
if (_UH.PersistCacheFileName[i] != 0) {
i++;
}
// From the root, go through each subdirectory and try to
// create the directory
while (rc && _UH.PersistCacheFileName[i] != 0) {
if (_UH.PersistCacheFileName[i] == _T('\\')) {
_UH.PersistCacheFileName[i] = 0;
if (!CreateDirectory(_UH.PersistCacheFileName, NULL)) {
// we can't create the directory, return failed
if (GetLastError() != ERROR_ALREADY_EXISTS) {
_UH.bPersistenceDisable = TRUE;
rc = FALSE;
}
}
_UH.PersistCacheFileName[i] = _T('\\');
}
i++;
}
DC_END_FN();
return rc;
}
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/****************************************************************************/
/* Name: UHAllocOneBitmapCache */
/* */
/* Purpose: Dynamically allocates memory for one UH bitmap cache. */
/* */
#ifdef DC_HICOLOR
/* Returns: Number of bytes actually allocated */
#else
/* Returns: TRUE if successful, FALSE otherwise */
#endif
/* */
/* */
/* Params: IN maxMemToUse - max cache size which can be alloc'ed */
/* IN entrySize - size of each cache entry */
/* OUT ppCacheData - address of buffer to receive cache data */
/* pointer */
/* OUT ppCacheHdr - address of buffer to receive cache header */
/* pointer */
/****************************************************************************/
#ifdef DC_HICOLOR
DCUINT32 DCINTERNAL CUH::UHAllocOneBitmapCache(DCUINT32 maxMemToUse,
DCUINT entrySize,
HPDCVOID DCPTR ppCacheData,
HPDCVOID DCPTR ppCacheHdr)
#else
DCBOOL DCINTERNAL CUH::UHAllocOneBitmapCache(DCUINT32 maxMemToUse,
DCUINT entrySize,
HPDCVOID DCPTR ppCacheData,
HPDCVOID DCPTR ppCacheHdr)
#endif
{
#ifdef DC_HICOLOR
DCUINT32 sizeAlloced = 0;
#else
DCBOOL rc = FALSE;
#endif
DCUINT32 dataSize;
DCUINT numEntries;
DCUINT32 hdrSize;
DC_BEGIN_FN("UHAllocOneBitmapCache");
TRC_ASSERT((entrySize != 0), (TB, _T("Invalid cache entry size (0)")));
TRC_ASSERT((entrySize <= maxMemToUse),
(TB, _T("Cache entry size exceeds max memory to use")));
TRC_ASSERT(!IsBadWritePtr(ppCacheData, sizeof(ppCacheData)),
(TB, _T("Invalid ppCacheData")));
TRC_ASSERT(!IsBadWritePtr(ppCacheHdr, sizeof(ppCacheHdr)),
(TB, _T("Invalid ppCacheHdr")));
/************************************************************************/
/* Calculate the total byte size to allocate for this cache. */
/************************************************************************/
numEntries = (unsigned)(maxMemToUse / entrySize);
dataSize = (DCUINT32)numEntries * (DCUINT32)entrySize;
TRC_NRM((TB, _T("Allocate %u entries: %#lx bytes from possible %#lx"),
numEntries, dataSize, maxMemToUse));
/************************************************************************/
/* Get the memory for the cache data */
/************************************************************************/
*ppCacheData = UT_MallocHuge( _pUt, dataSize);
if (*ppCacheData != NULL) {
TRC_DBG((TB, _T("Allocated %#lx bytes for bitmap cache data"), dataSize));
#ifdef DC_DEBUG
// Only zero in debug.
DC_MEMSET(*ppCacheData, 0, dataSize);
#endif
// Get the memory for the cache headers.
hdrSize = (DCUINT32)numEntries * (DCUINT32)
sizeof(UHBITMAPCACHEENTRYHDR);
*ppCacheHdr = UT_MallocHuge( _pUt, hdrSize);
if (*ppCacheHdr != NULL) {
TRC_DBG((TB, _T("Allocated %#lx bytes for bitmap cache header"),
hdrSize));
DC_MEMSET(*ppCacheHdr, 0, hdrSize);
#ifdef DC_HICOLOR
sizeAlloced = dataSize;
#else
rc = TRUE;
#endif
}
else {
TRC_ERR((TB, _T("Failed to allocate %#lx bytes for bitmap cache hdrs"),
hdrSize));
// Free what we already allocated.
UT_Free( _pUt, *ppCacheData);
*ppCacheData = NULL;
}
}
else {
TRC_ERR((TB, _T("Failed to allocate %#lx bytes for bitmap cache"),
dataSize));
}
DC_END_FN();
#ifdef DC_HICOLOR
return(sizeAlloced);
#else
return rc;
#endif
}
/****************************************************************************/
// UHAllocBitmapCacheMemory
//
// Prepares the cache client-to-server capabilities and allocates cache memory
// according to the determined server support. Should be called after server
// caps are processed after receipt of a DemandActivePDU.
/****************************************************************************/
void DCINTERNAL CUH::UHAllocBitmapCacheMemory(void)
{
unsigned i, j;
DCUINT32 CacheSize, NumEntries;
unsigned TotalProportion, TotalVirtualProp;
DC_BEGIN_FN("UHAllocBitmapCacheMemory");
// We assume _pCc->_ccCombinedCapabilities.bitmapCacheCaps has been initialized
// before calling this function. See UH_Enable().
/************************************************************************/
// Set up _pCc->_ccCombinedCapabilities.bitmapCacheCaps according to the
// advertised server version.
/************************************************************************/
if (_UH.BitmapCacheVersion > TS_BITMAPCACHE_REV1) {
TS_BITMAPCACHE_CAPABILITYSET_REV2 *pRev2Caps;
// Rev2 caps.
pRev2Caps = (TS_BITMAPCACHE_CAPABILITYSET_REV2 *)
&_pCc->_ccCombinedCapabilities.bitmapCacheCaps;
TRC_ALT((TB,_T("Preparing REV2 caps for server\n")));
pRev2Caps->capabilitySetType = TS_CAPSETTYPE_BITMAPCACHE_REV2;
pRev2Caps->NumCellCaches = (TSUINT8)_UH.RegNumBitmapCaches;
pRev2Caps->bAllowCacheWaitingList = TRUE;
// create cache directory
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
if (!_UH.bPersistenceDisable) {
_UH.PersistCacheFileName[_UH.EndPersistCacheDir - 1] = _T('\0');
if (!CreateDirectory(_UH.PersistCacheFileName, NULL)) {
if (GetLastError() != ERROR_ALREADY_EXISTS) {
// since we can't directly create the cache directory, we need to
// start from the root, traverse every level and see if all the
// subdirectories are properly created
_UH.PersistCacheFileName[_UH.EndPersistCacheDir - 1] = _T('\\');
UHCreateCacheDirectory();
_UH.PersistCacheFileName[_UH.EndPersistCacheDir - 1] = _T('\0');
}
}
// For non WinCE 32bit client, we want to set the file
// attribute so that it doesn't do content indexing
#ifndef OS_WINCE
if (GetFileAttributes(_UH.PersistCacheFileName) != -1) {
SetFileAttributes(_UH.PersistCacheFileName,
GetFileAttributes( _UH.PersistCacheFileName ) |
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED );
}
#endif
_UH.PersistCacheFileName[_UH.EndPersistCacheDir - 1] = _T('\\');
}
// Read in the Persistence flag registry setting
// We read this registry here because the persistent flag
// can change after UH_Init
if (!_UH.bPersistenceDisable) {
_UH.RegPersistenceActive = (UINT16) _pUi->UI_GetBitmapPersistence();
}
else {
_UH.RegPersistenceActive = FALSE;
}
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// Gather proportion total and persistent flag info.
TotalProportion = TotalVirtualProp = 0;
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
_UH.bPersistenceActive = FALSE;
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
for (i = 0; i < _UH.RegNumBitmapCaches; i++) {
TotalProportion += _UH.RegBCProportion[i];
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
if (_UH.RegPersistenceActive) {
// We will send a persistent key PDU if any cache is marked
// persistent.
pRev2Caps->CellCacheInfo[i].bSendBitmapKeys =
_UH.RegBCInfo[i].bSendBitmapKeys;
if (_UH.RegBCInfo[i].bSendBitmapKeys) {
TotalVirtualProp += _UH.RegBCProportion[i];
pRev2Caps->bPersistentKeysExpected = TRUE;
_UH.bPersistenceActive = TRUE;
}
}
else
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
pRev2Caps->CellCacheInfo[i].bSendBitmapKeys = 0;
}
// Now set up the number of physical cache entries according to the
// proportion of the total, and allocate the memory.
_UH.NumBitmapCaches = _UH.RegNumBitmapCaches;
for (i = 0; i < _UH.RegNumBitmapCaches; i++) {
// the cache size allocated for this cache
if (TotalProportion != 0) {
CacheSize = _UH.RegBCProportion[i] * (_UH.RegBitmapCacheSize *
(_UH.RegScaleBitmapCachesByBPP ? _UH.copyMultiplier :
1) / TotalProportion);
}
else {
CacheSize = 0;
}
// Determine the number of entries for this cache
pRev2Caps->CellCacheInfo[i].NumEntries = (CacheSize /
UH_CellSizeFromCacheID(i));
pRev2Caps->CellCacheInfo[i].NumEntries = min(
pRev2Caps->CellCacheInfo[i].NumEntries,
_UH.RegBCMaxEntries[i]);
#ifdef DC_HICOLOR
// Allocate an extra cache entry for the noncached bitmap that's in
// the waiting list to be cached later.
CacheSize = UHGetOffsetIntoCache(pRev2Caps->CellCacheInfo[i].NumEntries + 1, i);
#else
CacheSize = UH_CellSizeFromCacheID(i) *
pRev2Caps->CellCacheInfo[i].NumEntries;
#endif
// Update our local bitmap cache info
_UH.bitmapCache[i].BCInfo.NumEntries = pRev2Caps->CellCacheInfo[i].NumEntries;
#ifdef DC_HICOLOR
_UH.bitmapCache[i].BCInfo.OrigNumEntries = _UH.bitmapCache[i].BCInfo.NumEntries;
#endif
_UH.bitmapCache[i].BCInfo.bSendBitmapKeys = pRev2Caps->CellCacheInfo[i].bSendBitmapKeys;
// allocate memory
#ifdef DC_HICOLOR
if (CacheSize)
{
_UH.bitmapCache[i].BCInfo.MemLen =
UHAllocOneBitmapCache(
CacheSize,
UH_CellSizeFromCacheID(i),
(void**)&_UH.bitmapCache[i].Entries,
(void**)&_UH.bitmapCache[i].Header);
}
if ((CacheSize == 0) || (_UH.bitmapCache[i].BCInfo.MemLen == 0))
#else
if (CacheSize == 0 || !UHAllocOneBitmapCache(CacheSize, UH_CellSizeFromCacheID(i),
(void**)&_UH.bitmapCache[i].Entries, (void**)&_UH.bitmapCache[i].Header))
#endif
{
// Alloc failure. We can only support as many cell caches as
// we've already allocated.
pRev2Caps->NumCellCaches = (TSUINT8)i;
_UH.NumBitmapCaches = i;
TRC_ERR((TB,_T("Failed to alloc cell cache %d, setting to %d cell ")
_T("caches"), i + 1, i));
break;
}
}
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// Allocate Bitmap Virtual Cache Page Table
if (_UH.bPersistenceActive && TotalVirtualProp != 0) {
for (i = 0; i < _UH.NumBitmapCaches; i++) {
if (_UH.RegBCInfo[i].bSendBitmapKeys) {
// the disk cache size allocated for this virtual cache
CacheSize = _UH.RegBCProportion[i] *
(UH_PropVirtualCacheSizeFromMult(_UH.copyMultiplier) /
TotalVirtualProp);
// determine the number of entries for this cache
NumEntries = CacheSize /
(UH_CellSizeFromCacheID(i) +
sizeof(UHBITMAPFILEHDR));
NumEntries = min(NumEntries, _UH.RegBCMaxEntries[i]);
_UH.bitmapCache[i].BCInfo.NumVirtualEntries = NumEntries;
// setup cache file for this bitmap cache
// 8bpp caching uses the same file as win2k
// higher color depths use a different name
// to prevent collisions due to the different cell sizes
//
UHSetCurrentCacheFileName(i, _UH.copyMultiplier);
_UH.bitmapCache[i].PageTable.CacheFileInfo.hCacheFile =
CreateFile( _UH.PersistCacheFileName,
GENERIC_READ | GENERIC_WRITE,
FILE_SHARE_READ,
NULL,
OPEN_ALWAYS, //create if not exist
FILE_ATTRIBUTE_NORMAL,
NULL);
if (INVALID_HANDLE_VALUE !=
_UH.bitmapCache[i].PageTable.CacheFileInfo.hCacheFile) {
#ifdef VM_BMPCACHE
_UH.bitmapCache[i].PageTable.CacheFileInfo.pMappedView = NULL;
HANDLE hMap =
CreateFileMapping(_UH.bitmapCache[i].PageTable.CacheFileInfo.hCacheFile,
NULL,
PAGE_READWRITE,
0,
CacheSize,
NULL);
if (hMap)
{
_UH.bitmapCache[i].PageTable.CacheFileInfo.pMappedView =
(LPBYTE)MapViewOfFile( hMap, FILE_MAP_WRITE, 0, 0, CacheSize);
CloseHandle(hMap);
hMap = INVALID_HANDLE_VALUE;
}
else
{
TRC_ERR((TB,_T("CreateFileMapping for cache file failed: %s - x%x"),
_UH.PersistCacheFileName, GetLastError()));
_UH.bitmapCache[i].BCInfo.NumVirtualEntries = 0;
break;
}
if(!_UH.bitmapCache[i].PageTable.CacheFileInfo.pMappedView)
{
TRC_ERR((TB,_T("MapViewOfFile failed 0x%x"),
GetLastError()));
_UH.bitmapCache[i].BCInfo.NumVirtualEntries = 0;
break;
}
#endif
// allocate memory for cache page table
if (UHAllocBitmapCachePageTable(NumEntries, i)) {
pRev2Caps->CellCacheInfo[i].NumEntries = NumEntries;
}
else {
_UH.bitmapCache[i].BCInfo.NumVirtualEntries = 0;
break;
}
}
else {
TRC_ERR((TB,_T("CreateFile for cache file failed: %s - x%x"),
_UH.PersistCacheFileName, GetLastError()));
pRev2Caps->CellCacheInfo[i].bSendBitmapKeys = 0;
_UH.bitmapCache[i].BCInfo.bSendBitmapKeys = 0;
_UH.bitmapCache[i].BCInfo.NumVirtualEntries = 0;
}
}
}
}
else {
// No persistency for this session
// below we redetermine the cache persistency. Here we
// need to set i to 0 so that we will iterate through
// all caches to reset the persistence flag
i = 0;
}
// Need to redetermine cache persistence flag
_UH.bPersistenceActive = FALSE;
for (j = i; j < _UH.NumBitmapCaches; j++) {
_UH.bitmapCache[j].BCInfo.bSendBitmapKeys = 0;
pRev2Caps->CellCacheInfo[j].bSendBitmapKeys = 0;
}
for (j = 0; j < i; j++) {
if (_UH.bitmapCache[j].BCInfo.bSendBitmapKeys) {
_UH.bPersistenceActive = TRUE;
}
}
#if DC_DEBUG
TRC_NRM((TB, _T("Num cell caches = %d, params:"), _UH.NumBitmapCaches));
for (i = 0; i < _UH.NumBitmapCaches; i++) {
TRC_NRM((TB,_T(" %d: Proportion=%d, persistent=%s, cellsize=%u"),
i, _UH.RegBCProportion[i],
(_UH.RegBCInfo[i].bSendBitmapKeys ? "TRUE" : "FALSE"),
UH_CellSizeFromCacheID(i)));
#ifdef DC_HICOLOR
TRC_ALT((TB,_T("Cache %d created with %d entries"), i,
_UH.bitmapCache[i].BCInfo.NumEntries));
#endif
}
#endif
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
TRC_NRM((TB,_T("Allocated REV2 buffers OK\n")));
}
else {
TS_BITMAPCACHE_CAPABILITYSET *pRev1Caps;
TRC_ALT((TB,_T("Preparing REV1 caps for server\n")));
// Set up rev1 capabilities by treating _pCc->_ccCombinedCapabilities.
// bitmapCacheCaps as a rev1 structure.
pRev1Caps = (TS_BITMAPCACHE_CAPABILITYSET *)&_pCc->_ccCombinedCapabilities.
bitmapCacheCaps;
pRev1Caps->capabilitySetType = TS_CAPSETTYPE_BITMAPCACHE;
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
_UH.bPersistenceActive = FALSE;
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// If we don't have at least three caches configured, we can simply
// send all zeroes in the caps -- rev1 bitmap caching is disabled
// if any cache is unavailable.
if (_UH.RegNumBitmapCaches >= 3) {
// Gather proportion total.
TotalProportion = _UH.RegBCProportion[0] + _UH.RegBCProportion[1] +
_UH.RegBCProportion[2];
_UH.NumBitmapCaches = 3;
// Now set up the number of cache entries according to the
// proportion of the total, and allocate the memory.
// CacheID 0.
CacheSize = _UH.RegBCProportion[0] * _UH.RegBitmapCacheSize *
(_UH.RegScaleBitmapCachesByBPP ? _UH.copyMultiplier : 1) /
TotalProportion;
pRev1Caps->Cache1MaximumCellSize = (TSUINT16)
UH_CellSizeFromCacheID(0);
_UH.bitmapCache[0].BCInfo.bSendBitmapKeys = FALSE;
#ifdef DC_HICOLOR
_UH.bitmapCache[0].BCInfo.MemLen =
UHAllocOneBitmapCache(
CacheSize,
pRev1Caps->Cache1MaximumCellSize,
(void**)&_UH.bitmapCache[0].Entries,
(void**)&_UH.bitmapCache[0].Header);
if (_UH.bitmapCache[0].BCInfo.MemLen == 0)
{
#else
if (!UHAllocOneBitmapCache(CacheSize,
pRev1Caps->Cache1MaximumCellSize,
(void**)&_UH.bitmapCache[0].Entries, (void**)&_UH.bitmapCache[0].Header)) {
#endif
// Alloc failure. No caches will be supported on the server.
TRC_ERR((TB,_T("Failed alloc CacheID 0, rev1 caching disabled")));
goto AllocErr;
}
pRev1Caps->Cache1Entries = (TSUINT16)(CacheSize /
UH_CellSizeFromCacheID(0));
_UH.bitmapCache[0].BCInfo.NumEntries = pRev1Caps->Cache1Entries;
#ifdef DC_HICOLOR
_UH.bitmapCache[0].BCInfo.OrigNumEntries = _UH.bitmapCache[0].BCInfo.NumEntries;
#endif
// CacheID 1.
CacheSize = _UH.RegBCProportion[1] * _UH.RegBitmapCacheSize *
(_UH.RegScaleBitmapCachesByBPP ? _UH.copyMultiplier : 1) /
TotalProportion;
pRev1Caps->Cache2MaximumCellSize = (TSUINT16)
UH_CellSizeFromCacheID(1);
_UH.bitmapCache[1].BCInfo.bSendBitmapKeys = FALSE;
#ifdef DC_HICOLOR
_UH.bitmapCache[1].BCInfo.MemLen =
UHAllocOneBitmapCache(
CacheSize,
pRev1Caps->Cache2MaximumCellSize,
(void**)&_UH.bitmapCache[1].Entries,
(void**)&_UH.bitmapCache[1].Header);
if (_UH.bitmapCache[1].BCInfo.MemLen == 0)
{
#else
if (!UHAllocOneBitmapCache(CacheSize,
pRev1Caps->Cache2MaximumCellSize,
(void**)&_UH.bitmapCache[1].Entries, (void**)&_UH.bitmapCache[1].Header)) {
#endif
// Alloc failure. No caches will be supported on the server.
TRC_ERR((TB,_T("Failed alloc CacheID 1, rev1 caching disabled")));
goto AllocErr;
}
pRev1Caps->Cache2Entries = (TSUINT16)(CacheSize /
UH_CellSizeFromCacheID(1));
_UH.bitmapCache[1].BCInfo.NumEntries = pRev1Caps->Cache2Entries;
#ifdef DC_HICOLOR
_UH.bitmapCache[1].BCInfo.OrigNumEntries = _UH.bitmapCache[1].BCInfo.NumEntries;
#endif
// CacheID 2.
CacheSize = _UH.RegBCProportion[2] * _UH.RegBitmapCacheSize *
(_UH.RegScaleBitmapCachesByBPP ? _UH.copyMultiplier : 1) /
TotalProportion;
pRev1Caps->Cache3MaximumCellSize = (TSUINT16)
UH_CellSizeFromCacheID(2);
_UH.bitmapCache[2].BCInfo.bSendBitmapKeys = FALSE;
#ifdef DC_HICOLOR
_UH.bitmapCache[2].BCInfo.MemLen =
UHAllocOneBitmapCache(
CacheSize,
pRev1Caps->Cache3MaximumCellSize,
(void**)&_UH.bitmapCache[2].Entries,
(void**)&_UH.bitmapCache[2].Header);
if (_UH.bitmapCache[2].BCInfo.MemLen == 0)
{
#else
if (!UHAllocOneBitmapCache(CacheSize,
pRev1Caps->Cache3MaximumCellSize,
(void**)&_UH.bitmapCache[2].Entries, (void**)&_UH.bitmapCache[2].Header)) {
#endif
// Alloc failure. No caches will be supported on the server.
TRC_ERR((TB,_T("Failed alloc CacheID 2, rev1 caching disabled")));
goto AllocErr;
}
pRev1Caps->Cache3Entries = (TSUINT16)(CacheSize /
UH_CellSizeFromCacheID(2));
_UH.bitmapCache[2].BCInfo.NumEntries = pRev1Caps->Cache3Entries;
#ifdef DC_HICOLOR
_UH.bitmapCache[2].BCInfo.OrigNumEntries = _UH.bitmapCache[2].BCInfo.NumEntries;
#endif
TRC_NRM((TB,_T("Allocated rev1 buffers")));
TRC_NRM((TB,_T("Allocated REV1 buffers OK\n")));
}
else {
TRC_ALT((TB,_T("Need at least 3 configured caches for rev1 ")
_T("server, BC disabled")));
goto ExitFunc;
}
}
#ifdef OS_WINCE //
/************************************************************************/
/* Create a cached memory DC and DIB for use by bitmap caching code. */
/* The memory DC can also be used for the StretchDIBits workaround in */
/* BitmapUpdatePDU handling. */
/************************************************************************/
_UH.hdcMemCached = CreateCompatibleDC(NULL);
if (_UH.hdcMemCached == NULL)
{
TRC_ERR((TB, _T("Unable to create memory hdc")));
goto AllocErr;
}
// Use protocol-implied tile sizes scaled to the number of caches we have.
_UH.bitmapInfo.hdr.biWidth = _UH.bitmapInfo.hdr.biHeight =
(UH_CACHE_0_DIMENSION << (_UH.NumBitmapCaches - 1));
_UH.hBitmapCacheDIB = CreateDIBSection(_UH.hdcMemCached,
(BITMAPINFO *)&_UH.bitmapInfo.hdr,
#ifdef DC_HICOLOR
_UH.DIBFormat,
#else
DIB_PAL_COLORS,
#endif
(VOID**)&_UH.hBitmapCacheDIBits,
NULL,
0);
if (_UH.hBitmapCacheDIB == NULL)
{
TRC_ERR((TB, _T("Failed to create DIB, disabling bitmap caching: %d"),
GetLastError()));
DeleteDC(_UH.hdcMemCached);
_UH.hdcMemCached = NULL;
goto AllocErr;
}
#endif
ExitFunc:
DC_END_FN();
return;
// Error handling
AllocErr:
// Since we failed to allocate everything we needed we therefore need to
// free the memory to return resources to the client machine, then
// disable bitmap caching from the server based on the cache version.
for (i = 0; i < TS_BITMAPCACHE_MAX_CELL_CACHES; i++) {
if (_UH.bitmapCache[i].Header != NULL) {
UT_Free( _pUt, _UH.bitmapCache[i].Header);
_UH.bitmapCache[i].Header = NULL;
}
if (_UH.bitmapCache[i].Entries != NULL) {
UT_Free( _pUt, _UH.bitmapCache[i].Entries);
_UH.bitmapCache[i].Entries = NULL;
}
_UH.NumBitmapCaches = 0;
if (_UH.BitmapCacheVersion > TS_BITMAPCACHE_REV1) {
TS_BITMAPCACHE_CAPABILITYSET_REV2 *pRev2Caps;
pRev2Caps = (TS_BITMAPCACHE_CAPABILITYSET_REV2 *)
&_pCc->_ccCombinedCapabilities.bitmapCacheCaps;
pRev2Caps->NumCellCaches = 0;
}
else {
TS_BITMAPCACHE_CAPABILITYSET *pRev1Caps;
// If any of the CacheNNumEntries values is zero a rev1 server
// will disable caching.
pRev1Caps = (TS_BITMAPCACHE_CAPABILITYSET *)
&_pCc->_ccCombinedCapabilities.bitmapCacheCaps;
pRev1Caps->Cache1Entries = 0;
}
}
}
/****************************************************************************/
// UHReadBitmapCacheSettings
//
// Called at init time to preload the bitmap cache registry settings so we
// will not have to take the performance hit during connect.
/****************************************************************************/
VOID DCINTERNAL CUH::UHReadBitmapCacheSettings(VOID)
{
unsigned i;
DC_BEGIN_FN("UHReadBitmapCacheSettings");
/************************************************************************/
// Find out how much memory we can use for the cell caches.
/************************************************************************/
// Physical memory cache size.
_UH.RegBitmapCacheSize = _pUi->_UI.RegBitmapCacheSize;
if (_UH.RegBitmapCacheSize < UH_BMC_LOW_THRESHOLD) {
// The total cache size is too low to be of any use - set to
// the low threshold
TRC_ALT((TB, _T("Bitmap cache size set to %#x. Must be at least %#x"),
(unsigned)_UH.RegBitmapCacheSize, UH_BMC_LOW_THRESHOLD));
_UH.RegBitmapCacheSize = UH_BMC_LOW_THRESHOLD;
}
TRC_NRM((TB, _T("%#x (%u) Kbytes configured for bitmap physical caches"),
(unsigned)_UH.RegBitmapCacheSize,
(unsigned)_UH.RegBitmapCacheSize));
_UH.RegBitmapCacheSize *= 1024; // Convert to bytes.
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// Virtual memory cache size
// for each of the 3 copy multiplier settings
//
_UH.PropBitmapVirtualCacheSize[0] =
_pUi->_UI.RegBitmapVirtualCache8BppSize;
// Convert to bytes.
_UH.PropBitmapVirtualCacheSize[0] *= (UINT32)1024 * (UINT32)1024;
_UH.PropBitmapVirtualCacheSize[1] =
_pUi->_UI.RegBitmapVirtualCache16BppSize;
// Convert to bytes.
_UH.PropBitmapVirtualCacheSize[1] *= (UINT32)1024 * (UINT32)1024;
_UH.PropBitmapVirtualCacheSize[2] =
_pUi->_UI.RegBitmapVirtualCache24BppSize;
// Convert to bytes.
_UH.PropBitmapVirtualCacheSize[2] *= (UINT32)1024 * (UINT32)1024;
if (UH_PropVirtualCacheSizeFromMult(_UH.copyMultiplier) <
_UH.RegBitmapCacheSize) {
// The total virtual cache size is too low - set to memory cache size.
TRC_ALT((TB, _T("Bitmap virtual cache size set to %#x. Must be at least %#x"),
(unsigned)UH_PropVirtualCacheSizeFromMult(_UH.copyMultiplier),
(unsigned)_UH.RegBitmapCacheSize));
//
// Be careful to correctly map to the array (-1 for 0 based)
//
_UH.PropBitmapVirtualCacheSize[_UH.copyMultiplier-1] = _UH.RegBitmapCacheSize;
}
TRC_NRM((TB, _T("%#x (%u) Mbytes configured for bitmap virtual caches"),
(unsigned)UH_PropVirtualCacheSizeFromMult(_UH.copyMultiplier),
(unsigned)UH_PropVirtualCacheSizeFromMult(_UH.copyMultiplier)));
// Get the persistent disk cache location
_pUt->UT_ReadRegistryString(UTREG_SECTION,
UTREG_UH_BM_PERSIST_CACHE_LOCATION,
_T(""),
_UH.PersistCacheFileName,
MAX_PATH - 1);
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// Get the high-color scaling flag for the caches. If this value is
// nonzero, we scale the mem sizes specified for memory and persistent
// caches by the bit depth of the protocol at connection time.
_UH.RegScaleBitmapCachesByBPP = _pUi->_UI.RegScaleBitmapCachesByBPP;
/************************************************************************/
// Get the number of cell caches configured .
/************************************************************************/
_UH.RegNumBitmapCaches = (TSUINT8)_pUi->_UI.RegNumBitmapCaches;
if (_UH.RegNumBitmapCaches > TS_BITMAPCACHE_MAX_CELL_CACHES)
_UH.RegNumBitmapCaches = TS_BITMAPCACHE_MAX_CELL_CACHES;
/************************************************************************/
// Grab cell cache params: Proportion, persistence and MaxEntries.
/************************************************************************/
for (i = 0; i < _UH.RegNumBitmapCaches; i++)
{
_UH.RegBCProportion[i] = _pUi->_UI.RegBCProportion[i];
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
_UH.RegBCInfo[i].bSendBitmapKeys = _pUi->_UI.bSendBitmapKeys[i];
#endif
_UH.RegBCMaxEntries[i] = _pUi->_UI.RegBCMaxEntries[i];
}
DC_END_FN();
}
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
#ifndef VM_BMPCACHE
/****************************************************************************/
// UHSavePersistentBitmap
//
// Disk write logic to write out a bitmap in the persistent cache.
// Returns FALSE on failure -- file was unseekable or a write error occurred.
// The bitmap is saved in compressed form.
/****************************************************************************/
BOOL DCINTERNAL CUH::UHSavePersistentBitmap(
HANDLE hFile,
UINT32 fileOffset,
PDCUINT8 pBitmapBits,
UINT noBCHeader,
PUHBITMAPINFO pBitmapInfo)
{
BOOL rc = FALSE;
UHBITMAPFILEHDR fileHdr;
DC_BEGIN_FN("UHSavePersistentBitmap");
TRC_ASSERT((pBitmapBits != NULL), (TB, _T("Empty bitmap data")));
TRC_ASSERT((pBitmapInfo != NULL), (TB, _T("Empty bitmap info")));
TRC_ASSERT((hFile != INVALID_HANDLE_VALUE), (TB, _T("Invalid file handle")));
TRC_NRM((TB, _T("Saving bitmap at offset: %x"), fileOffset));
if (SetFilePointer( hFile, fileOffset, NULL, FILE_BEGIN) !=
INVALID_SET_FILE_POINTER)
{
// fill in the file header information
fileHdr.bmpInfo.Key1 = pBitmapInfo->Key1;
fileHdr.bmpInfo.Key2 = pBitmapInfo->Key2;
fileHdr.bmpInfo.bitmapWidth = pBitmapInfo->bitmapWidth;
fileHdr.bmpInfo.bitmapHeight = pBitmapInfo->bitmapHeight;
fileHdr.bmpInfo.bitmapLength = pBitmapInfo->bitmapLength;
fileHdr.bmpVersion = TS_BITMAPCACHE_REV2;
fileHdr.pad = 0;
// bitmap data is compressed or not
#ifdef DC_HICOLOR
if (pBitmapInfo->bitmapLength < (UINT32) (fileHdr.bmpInfo.bitmapWidth *
fileHdr.bmpInfo.bitmapHeight * _UH.copyMultiplier)) {
#else
if (pBitmapInfo->bitmapLength < (UINT32) (fileHdr.bmpInfo.bitmapWidth *
fileHdr.bmpInfo.bitmapHeight)) {
#endif
fileHdr.bCompressed = TRUE;
}
else {
fileHdr.bCompressed = FALSE;
}
// bitmap data contains compression header or not
if (noBCHeader) {
fileHdr.bNoBCHeader = TRUE;
}
else {
fileHdr.bNoBCHeader = FALSE;
}
DWORD cbWritten=0;
if(WriteFile( hFile, &fileHdr, sizeof(fileHdr),
&cbWritten, NULL) && sizeof(fileHdr) == cbWritten)
{
if(WriteFile( hFile, pBitmapBits,
(UINT)fileHdr.bmpInfo.bitmapLength, &cbWritten,
NULL) &&
((DWORD)cbWritten == fileHdr.bmpInfo.bitmapLength))
{
TRC_NRM((TB, _T("Bitmap file is saved successfully")));
rc = TRUE;
}
else
{
TRC_ERR((TB, _T("Failed to write bitmap file 0x%x"),GetLastError()));
}
}
else
{
TRC_ERR((TB, _T("Failed to write bitmap file 0x%x"),GetLastError()));
}
}
else {
TRC_ERR((TB, _T("failed to save to file: x%x"),GetLastError()));
}
DC_END_FN();
return rc;
}
/****************************************************************************/
// UHLoadPersistentCellBitmap
//
// Load the bitmap file on disk to memory cache entry
/****************************************************************************/
// SECURITY - caller must verify cacheId and cacheIndex
HRESULT DCINTERNAL CUH::UHLoadPersistentBitmap(
HANDLE hFile,
UINT32 offset,
UINT cacheId,
UINT32 cacheIndex,
PUHBITMAPCACHEPTE pPTE)
{
HRESULT hr = E_FAIL;
PUHBITMAPCACHEENTRYHDR pHeader;
BYTE FAR *pBitmapData;
UHBITMAPFILEHDR fileHdr;
DWORD cbRead = 0;
DC_BEGIN_FN("UHLoadPersistentBitmap");
TRC_ASSERT((hFile != INVALID_HANDLE_VALUE), (TB, _T("Invalid FILE handle")));
TRC_ASSERT((cacheId < TS_BITMAPCACHE_MAX_CELL_CACHES),
(TB, _T("Invalid cache ID %u"), cacheId));
if (SetFilePointer( hFile, offset, NULL, FILE_BEGIN) !=
INVALID_SET_FILE_POINTER)
{
// Read the bitmap contents into the cell cache
pHeader = &_UH.bitmapCache[cacheId].Header[cacheIndex];
#ifdef DC_HICOLOR
pBitmapData = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(cacheIndex, cacheId);
#else
pBitmapData = _UH.bitmapCache[cacheId].Entries + cacheIndex *
UH_CellSizeFromCacheID(cacheId);
#endif
// Read the header and load the bitmap contents
#ifdef DC_HICOLOR
if (ReadFile( hFile, &fileHdr, sizeof(fileHdr), &cbRead, NULL) &&
sizeof(fileHdr) == cbRead &&
fileHdr.bmpVersion == TS_BITMAPCACHE_REV2 &&
fileHdr.bmpInfo.bitmapLength <= (unsigned)fileHdr.bmpInfo.bitmapHeight
* fileHdr.bmpInfo.bitmapWidth
* _UH.copyMultiplier &&
fileHdr.bmpInfo.bitmapLength <= (unsigned)UH_CellSizeFromCacheID(cacheId) &&
fileHdr.bmpInfo.Key1 == pPTE->bmpInfo.Key1 &&
fileHdr.bmpInfo.Key2 == pPTE->bmpInfo.Key2)
#else
if (ReadFile( hFile, &fileHdr, sizeof(fileHdr), &cbRead, NULL) &&
sizeof(fileHdr) == cbRead &&
fileHdr.bmpVersion == TS_BITMAPCACHE_REV2 &&
fileHdr.bmpInfo.bitmapLength <= (unsigned)fileHdr.bmpInfo.bitmapHeight *
fileHdr.bmpInfo.bitmapWidth &&
fileHdr.bmpInfo.bitmapLength <= (unsigned)UH_CellSizeFromCacheID(cacheId) &&
fileHdr.bmpInfo.Key1 == pPTE->bmpInfo.Key1 &&
fileHdr.bmpInfo.Key2 == pPTE->bmpInfo.Key2)
#endif
{
if (fileHdr.bCompressed == TRUE)
{
// Allocate bitmap decompression buffer if it's not already
// allocated
if (_UH.bitmapDecompressionBuffer == NULL) {
_UH.bitmapDecompressionBufferSize = max(
UH_DECOMPRESSION_BUFFER_LENGTH,
UH_CellSizeFromCacheID(_UH.NumBitmapCaches));
_UH.bitmapDecompressionBuffer = (PDCUINT8)UT_Malloc( _pUt, _UH.bitmapDecompressionBufferSize);
if (_UH.bitmapDecompressionBuffer == NULL) {
TRC_ERR((TB,_T("Failing to allocate decomp buffer")));
_UH.bitmapDecompressionBufferSize = 0;
DC_QUIT;
}
}
if (ReadFile( hFile, _UH.bitmapDecompressionBuffer,
(UINT)fileHdr.bmpInfo.bitmapLength, &cbRead, NULL) &&
(UINT) fileHdr.bmpInfo.bitmapLength == cbRead)
{
#ifdef DC_HICOLOR
hr = BD_DecompressBitmap(_UH.bitmapDecompressionBuffer,
pBitmapData,
(UINT) fileHdr.bmpInfo.bitmapLength,
_UH.bitmapDecompressionBufferSize,
(UINT) fileHdr.bNoBCHeader,
(DCUINT8)_UH.protocolBpp,
(DCUINT16)fileHdr.bmpInfo.bitmapWidth,
(DCUINT16)fileHdr.bmpInfo.bitmapHeight);
#else
hr = BD_DecompressBitmap(_UH.bitmapDecompressionBuffer,
pBitmapData,
(UINT) fileHdr.bmpInfo.bitmapLength,
_UH.bitmapDecompressionBufferSize,
(UINT) fileHdr.bNoBCHeader,
8, fileHdr.bmpInfo.bitmapWidth,
fileHdr.bmpInfo.bitmapHeight);
#endif
DC_QUIT_ON_FAIL(hr);
}
else {
TRC_ERR((TB, _T("Error reading bitmap bits 0x%x"),GetLastError()));
DC_QUIT;
}
}
else {
if (!(ReadFile( hFile, pBitmapData,
(UINT)fileHdr.bmpInfo.bitmapLength, &cbRead, NULL) &&
(UINT) fileHdr.bmpInfo.bitmapLength == cbRead))
{
TRC_ERR((TB, _T("Error reading bitmap bits 0x%x"),GetLastError()));
DC_QUIT;
}
}
pHeader->bitmapWidth = fileHdr.bmpInfo.bitmapWidth;
pHeader->bitmapHeight = fileHdr.bmpInfo.bitmapHeight;
#ifdef DC_HICOLOR
pHeader->bitmapLength = fileHdr.bmpInfo.bitmapWidth * fileHdr.bmpInfo.bitmapHeight
* _UH.copyMultiplier;
#else
pHeader->bitmapLength = fileHdr.bmpInfo.bitmapWidth * fileHdr.bmpInfo.bitmapHeight;
#endif
pHeader->hasData = TRUE;
TRC_NRM((TB, _T("Bitmap loaded: cache %u entry %u"), cacheId, cacheIndex));
hr = S_OK;
}
else {
TRC_ERR((TB, _T("Error reading bitmap file")));
}
}
else {
TRC_NRM((TB, _T("Bad bitmap file. Seek error 0x%x"),GetLastError()));
}
DC_EXIT_POINT:
DC_END_FN();
return hr;
}
#else //VM_BMPCACHE
/****************************************************************************/
// UHSavePersistentBitmap (VM Version)
//
// Disk write logic to write out a bitmap in the persistent cache.
// Returns FALSE on failure -- file was unseekable or a write error occurred.
// The bitmap is saved in compressed form.
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHSavePersistentBitmap(
UINT cacheId,
UINT32 fileOffset,
PDCUINT8 pBitmapBits,
UINT noBCHeader,
PUHBITMAPINFO pBitmapInfo)
{
HRESULT hr = E_FAIL;
PUHBITMAPFILEHDR pFileHdr;
LPBYTE pMappedView = NULL;
LPBYTE pWritePtr = NULL;
DWORD status = ERROR_SUCCESS;
DC_BEGIN_FN("UHSavePersistentBitmap");
TRC_ASSERT((cacheId < TS_BITMAPCACHE_MAX_CELL_CACHES),
(TB, _T("Invalid cache ID %u"), cacheId));
pMappedView = _UH.bitmapCache[cacheId].PageTable.CacheFileInfo.pMappedView;
TRC_ASSERT(pMappedView,
(TB, _T("Invalid mapped view for cacheId %d"), cacheId));
TRC_ASSERT((pBitmapBits != NULL), (TB, _T("Empty bitmap data")));
TRC_ASSERT((pBitmapInfo != NULL), (TB, _T("Empty bitmap info")));
TRC_NRM((TB, _T("Saving bitmap at offset: %x"), fileOffset));
pWritePtr = pMappedView + fileOffset;
__try
{
pFileHdr = (PUHBITMAPFILEHDR)pWritePtr;
// fill in the file header information
pFileHdr->bmpInfo.Key1 = pBitmapInfo->Key1;
pFileHdr->bmpInfo.Key2 = pBitmapInfo->Key2;
pFileHdr->bmpInfo.bitmapWidth = pBitmapInfo->bitmapWidth;
pFileHdr->bmpInfo.bitmapHeight = pBitmapInfo->bitmapHeight;
pFileHdr->bmpInfo.bitmapLength = pBitmapInfo->bitmapLength;
pFileHdr->bmpVersion = TS_BITMAPCACHE_REV2;
pFileHdr->pad = 0;
if (pBitmapInfo->bitmapLength < (UINT32) (pFileHdr->bmpInfo.bitmapWidth *
pFileHdr->bmpInfo.bitmapHeight * _UH.copyMultiplier)) {
pFileHdr->bCompressed = TRUE;
}
else {
pFileHdr->bCompressed = FALSE;
}
// bitmap data contains compression header or not
if (noBCHeader) {
pFileHdr->bNoBCHeader = TRUE;
}
else {
pFileHdr->bNoBCHeader = FALSE;
}
pWritePtr += sizeof(UHBITMAPFILEHDR);
//
// Write the actual bitmap bits
//
memcpy(pWritePtr, pBitmapBits,
pFileHdr->bmpInfo.bitmapLength);
hr = S_OK;
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
}
if (ERROR_SUCCESS == status && SUCCEEDED(hr))
{
return hr;
}
else
{
TRC_ERR((TB,
_T("Failed to save file-0x%x hdr:%d status:%d"),
status, hr));
return hr;
}
DC_END_FN();
return hr;
}
/****************************************************************************/
// UHLoadPersistentCellBitmap (VM version)
//
// Load the bitmap file on disk to memory cache entry
/****************************************************************************/
HRESULT DCINTERNAL CUH::UHLoadPersistentBitmap(
HANDLE hFile,
UINT32 offset,
UINT cacheId,
UINT32 cacheIndex,
PUHBITMAPCACHEPTE pPTE)
{
BOOL rc = FALSE;
PUHBITMAPCACHEENTRYHDR pHeader;
BYTE FAR *pBitmapData;
PUHBITMAPFILEHDR pFileHdr = NULL;
DWORD cbRead = 0;
LPBYTE pMappedView = NULL;
LPBYTE pReadPtr = NULL;
DWORD status = ERROR_SUCCESS;
BOOL fFileHdrOK = FALSE;
BOOL fReadOK = FALSE;
DC_BEGIN_FN("UHLoadPersistentBitmap");
UNREFERENCED_PARAMETER(hFile);
TRC_ASSERT((cacheId < TS_BITMAPCACHE_MAX_CELL_CACHES),
(TB, _T("Invalid cache ID %u"), cacheId));
pMappedView = _UH.bitmapCache[cacheId].PageTable.CacheFileInfo.pMappedView;
TRC_ASSERT(pMappedView,
(TB, _T("Invalid mapped view for cacheId %d"), cacheId));
__try
{
pHeader = &_UH.bitmapCache[cacheId].Header[cacheIndex];
pBitmapData = _UH.bitmapCache[cacheId].Entries +
UHGetOffsetIntoCache(cacheIndex, cacheId);
// Read the header and load the bitmap contents
pFileHdr = (PUHBITMAPFILEHDR)(pMappedView + offset);
if (pFileHdr->bmpVersion == TS_BITMAPCACHE_REV2 &&
pFileHdr->bmpInfo.bitmapLength <=
(unsigned)pFileHdr->bmpInfo.bitmapHeight *
pFileHdr->bmpInfo.bitmapWidth *
_UH.copyMultiplier &&
pFileHdr->bmpInfo.bitmapLength <=
(unsigned)UH_CellSizeFromCacheID(cacheId) &&
pFileHdr->bmpInfo.Key1 == pPTE->bmpInfo.Key1 &&
pFileHdr->bmpInfo.Key2 == pPTE->bmpInfo.Key2)
{
fFileHdrOK = TRUE;
//
// Read the bitmap bits
// In the compressed case we decompress directly within
// the exception handler otherwise we make a copy so that we
// don't need to wrap every possible access in try/except.
//
pReadPtr = (LPBYTE)(pFileHdr + 1);
if (pFileHdr->bCompressed == TRUE)
{
// Allocate bitmap decompression buffer if it's not already
// allocated
hr = BD_DecompressBitmap(pReadPtr,
pBitmapData,
(UINT) pFileHdr->bmpInfo.bitmapLength,
UH_CellSizeFromCacheID(cacheId),
(UINT) pFileHdr->bNoBCHeader,
(DCUINT8)_UH.protocolBpp,
(DCUINT16)pFileHdr->bmpInfo.bitmapWidth,
(DCUINT16)pFileHdr->bmpInfo.bitmapHeight);
DC_QUIT_ON_FAIL(hr);
}
else
{
memcpy(pBitmapData,
pReadPtr,
pFileHdr->bmpInfo.bitmapLength);
}
pHeader->bitmapWidth = pFileHdr->bmpInfo.bitmapWidth;
pHeader->bitmapHeight = pFileHdr->bmpInfo.bitmapHeight;
pHeader->bitmapLength = pFileHdr->bmpInfo.bitmapWidth *
pFileHdr->bmpInfo.bitmapHeight *
_UH.copyMultiplier;
pHeader->hasData = TRUE;
fReadOK = TRUE;
}
}
__except(EXCEPTION_EXECUTE_HANDLER)
{
status = GetExceptionCode();
}
if (ERROR_SUCCESS == status && fReadOK)
{
return TRUE;
}
else
{
TRC_ERR((TB,
_T("Header read from mapped file failed status-0x%x hdr:%d readok:%d"),
status, fFileHdrOK, fReadOK));
return FALSE;
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
#endif //VM_BMPCACHE
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
/****************************************************************************/
/* Name: UHAllocOneGlyphCache */
/* */
/* Purpose: Dynamically allocates memory for one UH glyph cache. */
/* */
/* Returns: TRUE if successful, FALSE otherwise */
/* */
/* Params: IN maxMemToUse - max cache size which can be alloc'ed */
/* IN pCache - address of glyph cache struct */
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHAllocOneGlyphCache(PUHGLYPHCACHE pCache,
DCUINT32 numEntries)
{
DCBOOL rc = FALSE;
DCUINT32 dataSize;
DCUINT32 hdrSize;
DC_BEGIN_FN("UHAllocOneGlyphCache");
TRC_ASSERT((pCache->cbEntrySize != 0),
(TB, _T("Invalid cache entry size (0)")));
/************************************************************************/
/* Calculate the total byte size to allocate for this cache. */
/************************************************************************/
dataSize = numEntries * pCache->cbEntrySize;
/************************************************************************/
/* Get the memory for the cache data */
/************************************************************************/
pCache->pData = (PDCUINT8)UT_MallocHuge( _pUt, dataSize);
if (pCache->pData == NULL)
{
/********************************************************************/
/* Memory allocation failure. */
/********************************************************************/
TRC_ERR((TB, _T("Failed to alloc %#lx bytes for glyph cache"), dataSize));
DC_QUIT;
}
/************************************************************************/
/* Get the memory for the cache headers */
/************************************************************************/
hdrSize = (DCUINT32) numEntries * sizeof(pCache->pHdr[0]);
pCache->pHdr = (PUHGLYPHCACHEENTRYHDR)UT_MallocHuge( _pUt, hdrSize);
if (pCache->pHdr == NULL)
{
/********************************************************************/
/* Memory allocation failure. */
/********************************************************************/
TRC_ERR((TB, _T("Failed to alloc %#lx bytes for glyph cache hdrs"), hdrSize));
DC_QUIT;
}
rc = TRUE;
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
/* Name: UHAllocOneFragCache */
/* */
/* Purpose: Dynamically allocates memory for one UH glyph cache. */
/* */
/* Returns: TRUE if successful, FALSE otherwise */
/* */
/* Params: IN maxMemToUse - max cache size which can be alloc'ed */
/* IN pCache - address of glyph cache struct */
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHAllocOneFragCache(PUHFRAGCACHE pCache,
DCUINT32 numEntries)
{
DCBOOL rc = FALSE;
DCUINT32 dataSize;
DCUINT32 hdrSize;
DC_BEGIN_FN("UHAllocOneFragCache");
TRC_ASSERT((pCache->cbEntrySize != 0),
(TB, _T("Invalid cache entry size (0)")));
/************************************************************************/
/* Calculate the total byte size to allocate for this cache. */
/************************************************************************/
dataSize = numEntries * pCache->cbEntrySize;
/************************************************************************/
/* Get the memory for the cache data */
/************************************************************************/
pCache->pData = (PDCUINT8)UT_MallocHuge( _pUt, dataSize);
if (pCache->pData == NULL)
{
/********************************************************************/
/* Memory allocation failure. */
/********************************************************************/
TRC_ERR((TB, _T("Failed to alloc %#lx bytes for frag cache"), dataSize));
DC_QUIT;
}
/************************************************************************/
/* Get the memory for the cache headers */
/************************************************************************/
hdrSize = (DCUINT32) numEntries * sizeof(pCache->pHdr[0]);
pCache->pHdr = (PUHFRAGCACHEENTRYHDR)UT_MallocHuge( _pUt, hdrSize);
if (pCache->pHdr == NULL)
{
/********************************************************************/
/* Memory allocation failure. */
/********************************************************************/
TRC_ERR((TB, _T("Failed to alloc %#lx bytes for glyph cache hdrs"), hdrSize));
DC_QUIT;
}
rc = TRUE;
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
/* Name: UHAllocGlyphCacheMemory */
/* */
/* Purpose: Dynamically allocates memory for the UH glyph caches. */
/* */
/* Returns: TRUE if successful, FALSE otherwise. */
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHAllocGlyphCacheMemory()
{
DCINT i;
DCINT j;
DCBOOL rc;
DCINT GlyphSupportLevel;
DCINT CellSize;
DCUINT CellEntries;
DC_BEGIN_FN("UHAllocGlyphCacheMemory");
rc = FALSE;
/************************************************************************/
/* Determine Glyph Support Level */
/************************************************************************/
GlyphSupportLevel = _pUi->_UI.GlyphSupportLevel;
if ((GlyphSupportLevel < 0) || (GlyphSupportLevel > 3))
GlyphSupportLevel = UTREG_UH_GL_SUPPORT_DFLT;
_pCc->_ccCombinedCapabilities.glyphCacheCapabilitySet.
GlyphSupportLevel = (DCUINT16) GlyphSupportLevel;
if (GlyphSupportLevel > 0)
{
/********************************************************************/
/* Determine Glyph cache cell sizes */
/********************************************************************/
for(i=0; i<UH_GLC_NUM_CACHES; i++)
{
_UH.glyphCache[i].cbEntrySize = _pUi->_UI.cbGlyphCacheEntrySize[i];
}
/************************************************************************/
/* Allocate each of the glyph caches. */
/************************************************************************/
for (i = 0; i<UH_GLC_NUM_CACHES; i++)
{
CellSize = (int)(_UH.glyphCache[i].cbEntrySize >> 1);
if (CellSize > 0)
{
for (j = 0; CellSize > 0; j++)
CellSize >>= 1;
CellSize = DC_MIN(1 << j, UH_GLC_CACHE_MAXIMUMCELLSIZE);
CellEntries = (unsigned)((128L * 1024) / CellSize);
CellEntries = DC_MIN(CellEntries, UH_GLC_CACHE_MAXIMUMCELLCOUNT);
CellEntries = DC_MAX(CellEntries, UH_GLC_CACHE_MINIMUMCELLCOUNT);
_UH.glyphCache[i].cbEntrySize = CellSize;
if (UHAllocOneGlyphCache(&_UH.glyphCache[i], CellEntries))
{
_pCc->_ccCombinedCapabilities.glyphCacheCapabilitySet.
GlyphCache[i].CacheEntries = (DCUINT16) CellEntries;
_pCc->_ccCombinedCapabilities.glyphCacheCapabilitySet.GlyphCache[i].
CacheMaximumCellSize = (DCUINT16) _UH.glyphCache[i].cbEntrySize;
rc = TRUE;
}
#ifdef OS_WINCE
else
{
rc = FALSE;
break;
}
#endif
}
}
/************************************************************************/
/* Allocate the fragment cache. */
/************************************************************************/
if (rc == TRUE)
{
/********************************************************************/
/* Determine fragment cell size */
/********************************************************************/
CellSize = _pUi->_UI.fragCellSize;
if (CellSize > 0)
{
_UH.fragCache.cbEntrySize =
DC_MIN(CellSize, UH_FGC_CACHE_MAXIMUMCELLSIZE);
if (UHAllocOneFragCache(&_UH.fragCache, UH_FGC_CACHE_MAXIMUMCELLCOUNT))
{
_pCc->_ccCombinedCapabilities.glyphCacheCapabilitySet.
FragCache.CacheEntries = UH_FGC_CACHE_MAXIMUMCELLCOUNT;
_pCc->_ccCombinedCapabilities.glyphCacheCapabilitySet.FragCache.
CacheMaximumCellSize = (DCUINT16) _UH.fragCache.cbEntrySize;
}
#ifdef OS_WINCE
else
{
rc = FALSE;
}
#endif
}
}
}
DC_END_FN();
return rc;
}
/****************************************************************************/
/* Name: UHAllocBrushCacheMemory */
/* */
/* Purpose: Dynamically allocates memory for the UH brush caches. */
/* */
/* Returns: TRUE if successful, FALSE otherwise. */
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHAllocBrushCacheMemory()
{
DCBOOL rc;
DCINT brushSupportLevel;
DCSIZE bitmapSize;
#ifndef OS_WINCE
HWND hwndDesktop;
#endif
HDC hdcScreen;
DC_BEGIN_FN("UHAllocBrushCacheMemory");
rc = FALSE;
/************************************************************************/
/* Determine Brush Support Level */
/************************************************************************/
brushSupportLevel = _pUi->_UI.brushSupportLevel;
if ((brushSupportLevel < TS_BRUSH_DEFAULT) ||
(brushSupportLevel > TS_BRUSH_COLOR_FULL))
brushSupportLevel = UTREG_UH_BRUSH_SUPPORT_DFLT;
_pCc->_ccCombinedCapabilities.brushCapabilitySet.brushSupportLevel =
brushSupportLevel;
TRC_NRM((TB, _T("Read Brush support level %d"), brushSupportLevel));
/**********************************************************************/
/* Allocate the mono brush cache */
/**********************************************************************/
_UH.pMonoBrush = (PUHMONOBRUSHCACHE)UT_Malloc( _pUt, sizeof(UHMONOBRUSHCACHE) * UH_MAX_MONO_BRUSHES);
_UH.bmpMonoPattern = CreateBitmap(8,8,1,1,NULL);
/**********************************************************************/
/* Create a compatible bitmap for color brushes since we can't be sure*/
/* how the actual pixel data is represented on each OS version. The */
/* server always sends 8bpp brush data and SetDIBits() is used to */
/* convert to the native format. */
/**********************************************************************/
_UH.pColorBrush = (PUHCOLORBRUSHCACHE)UT_Malloc( _pUt, sizeof(UHCOLORBRUSHCACHE) * UH_MAX_COLOR_BRUSHES);
_UH.pColorBrushInfo = (PUHCOLORBRUSHINFO)UT_Malloc( _pUt, sizeof(UHCOLORBRUSHINFO));
#ifdef DC_HICOLOR
_UH.pHiColorBrushInfo = (PUHHICOLORBRUSHINFO)UT_Malloc( _pUt, sizeof(UHHICOLORBRUSHINFO));
#endif
#ifdef DC_HICOLOR
if (_UH.pColorBrushInfo && _UH.pHiColorBrushInfo)
{
// Set up the brush bitmap info header
_UH.pColorBrushInfo->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
_UH.pColorBrushInfo->bmi.bmiHeader.biWidth = 8;
_UH.pColorBrushInfo->bmi.bmiHeader.biHeight = 8;
_UH.pColorBrushInfo->bmi.bmiHeader.biPlanes = 1;
_UH.pColorBrushInfo->bmi.bmiHeader.biBitCount = 8;
_UH.pColorBrushInfo->bmi.bmiHeader.biCompression = BI_RGB;
_UH.pColorBrushInfo->bmi.bmiHeader.biSizeImage = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biXPelsPerMeter = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biYPelsPerMeter = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biClrUsed = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biClrImportant = 0;
// and copy it to the hicolor brush header
memcpy(_UH.pHiColorBrushInfo,
_UH.pColorBrushInfo,
sizeof(BITMAPINFOHEADER));
// Setup the bitmasks used at 16bpp
*((PDCUINT32)&_UH.pHiColorBrushInfo->bmiColors[0]) =
TS_RED_MASK_16BPP;
*((PDCUINT32)&_UH.pHiColorBrushInfo->bmiColors[1]) =
TS_GREEN_MASK_16BPP;
*((PDCUINT32)&_UH.pHiColorBrushInfo->bmiColors[2]) =
TS_BLUE_MASK_16BPP;
// Set up the other brush related resources
bitmapSize.width = 8;
bitmapSize.height = 8;
#ifndef OS_WINCE
hwndDesktop = GetDesktopWindow();
hdcScreen = GetWindowDC(hwndDesktop);
#else // !OS_WINCE
hdcScreen = GetDC(NULL);
#endif // !OS_WINCE
if (hdcScreen) {
_UH.bmpColorPattern = CreateCompatibleBitmap(hdcScreen, 8, 8);
_UH.hdcBrushBitmap = CreateCompatibleDC(hdcScreen);
#ifndef OS_WINCE
ReleaseDC(hwndDesktop, hdcScreen);
#else // !OS_WINCE
DeleteDC(hdcScreen);
#endif // !OS_WINCE
}
}
#else
if (_UH.pColorBrushInfo) {
_UH.pColorBrushInfo->bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
_UH.pColorBrushInfo->bmi.bmiHeader.biWidth = 8;
_UH.pColorBrushInfo->bmi.bmiHeader.biHeight = 8;
_UH.pColorBrushInfo->bmi.bmiHeader.biPlanes = 1;
_UH.pColorBrushInfo->bmi.bmiHeader.biBitCount = 8;
_UH.pColorBrushInfo->bmi.bmiHeader.biCompression = BI_RGB;
_UH.pColorBrushInfo->bmi.bmiHeader.biSizeImage = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biXPelsPerMeter = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biYPelsPerMeter = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biClrUsed = 0;
_UH.pColorBrushInfo->bmi.bmiHeader.biClrImportant = 0;
bitmapSize.width = 8;
bitmapSize.height = 8;
#ifndef OS_WINCE
hwndDesktop = GetDesktopWindow();
hdcScreen = GetWindowDC(hwndDesktop);
#else // !OS_WINCE
hdcScreen = GetDC(NULL);
#endif // !OS_WINCE
_UH.bmpColorPattern = CreateCompatibleBitmap(hdcScreen, 8, 8);
_UH.hdcBrushBitmap = CreateCompatibleDC(hdcScreen);
#ifndef OS_WINCE
ReleaseDC(hwndDesktop, hdcScreen);
#else // !OS_WINCE
DeleteDC(hdcScreen);
#endif // !OS_WINCE
}
#endif
#ifdef DC_HICOLOR
if (_UH.pMonoBrush &&
_UH.pColorBrush && _UH.pColorBrushInfo && _UH.pHiColorBrushInfo &&
_UH.bmpMonoPattern && _UH.bmpColorPattern)
#else
if (_UH.pMonoBrush &&
_UH.pColorBrush && _UH.pColorBrushInfo &&
_UH.bmpMonoPattern && _UH.bmpColorPattern)
#endif
{
TRC_NRM((TB, _T("Brush support OK")));
rc = TRUE;
}
else
{
TRC_NRM((TB, _T("Failure - Brush support level set to Default")));
_pCc->_ccCombinedCapabilities.brushCapabilitySet.brushSupportLevel = TS_BRUSH_DEFAULT;
if (_UH.pMonoBrush)
{
UT_Free( _pUt, _UH.pMonoBrush);
_UH.pMonoBrush = NULL;
}
if (_UH.pColorBrushInfo)
{
UT_Free( _pUt, _UH.pColorBrushInfo);
_UH.pColorBrushInfo = NULL;
}
#ifdef DC_HICOLOR
if (_UH.pHiColorBrushInfo)
{
UT_Free( _pUt, _UH.pHiColorBrushInfo);
_UH.pHiColorBrushInfo = NULL;
}
#endif
if (_UH.pColorBrush)
{
UT_Free( _pUt, _UH.pColorBrush);
_UH.pColorBrush = NULL;
}
if (_UH.bmpColorPattern)
{
DeleteObject(_UH.bmpColorPattern);
_UH.bmpColorPattern = NULL;
}
DC_QUIT;
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
/****************************************************************************/
// Name: UHAllocOffscreenCacheMemory
//
// Purpose: Dynamically allocates memory for the UH offscreen caches.
//
// Returns: TRUE if successful, FALSE otherwise.
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHAllocOffscreenCacheMemory()
{
DCBOOL rc;
DCINT offscrSupportLevel;
HDC hdcDesktop;
DC_BEGIN_FN("UHAllocOffscreenCacheMemory");
rc = FALSE;
/************************************************************************/
// Determine Offscreen Support Level
/************************************************************************/
offscrSupportLevel = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_OFFSCREEN_SUPPORT,
UTREG_UH_OFFSCREEN_SUPPORT_DFLT);
_UH.offscrCacheSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_OFFSCREEN_CACHESIZE,
UTREG_UH_OFFSCREEN_CACHESIZE_DFLT *
_UH.copyMultiplier);
_UH.offscrCacheEntries = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_OFFSCREEN_CACHEENTRIES,
UTREG_UH_OFFSCREEN_CACHEENTRIES_DFLT);
// Check boundary values for offscreen cache parameters
if ((offscrSupportLevel < TS_OFFSCREEN_DEFAULT))
offscrSupportLevel = UTREG_UH_OFFSCREEN_SUPPORT_DFLT;
if (_UH.offscrCacheSize < UH_OBC_LOW_CACHESIZE ||
_UH.offscrCacheSize > UH_OBC_HIGH_CACHESIZE) {
_UH.offscrCacheSize = TS_OFFSCREEN_CACHE_SIZE_CLIENT_DEFAULT * _UH.copyMultiplier;
}
if (_UH.offscrCacheEntries < UH_OBC_LOW_CACHEENTRIES ||
_UH.offscrCacheEntries > UH_OBC_HIGH_CACHEENTRIES) {
_UH.offscrCacheEntries = TS_OFFSCREEN_CACHE_ENTRIES_DEFAULT;
}
if (offscrSupportLevel > TS_OFFSCREEN_DEFAULT) {
// Create DC for the offscreen drawing
hdcDesktop = GetWindowDC(HWND_DESKTOP);
if (hdcDesktop) {
_UH.hdcOffscreenBitmap = CreateCompatibleDC(hdcDesktop);
if (_UH.hdcOffscreenBitmap) {
unsigned size;
SelectPalette(_UH.hdcOffscreenBitmap, _UH.hpalCurrent, FALSE);
RealizePalette(_UH.hdcOffscreenBitmap);
// Create offscreen cache
size = sizeof(UHOFFSCRBITMAPCACHE) * _UH.offscrCacheEntries;
_UH.offscrBitmapCache = (HPUHOFFSCRBITMAPCACHE)UT_MallocHuge(_pUt, size);
if (_UH.offscrBitmapCache != NULL) {
memset(_UH.offscrBitmapCache, 0, size);
rc = TRUE;
} else {
DeleteDC(_UH.hdcOffscreenBitmap);
_UH.hdcOffscreenBitmap = NULL;
offscrSupportLevel = TS_OFFSCREEN_DEFAULT;
}
}
else {
offscrSupportLevel = TS_OFFSCREEN_DEFAULT;
}
ReleaseDC(HWND_DESKTOP, hdcDesktop);
}
else {
offscrSupportLevel = TS_OFFSCREEN_DEFAULT;
}
}
TRC_NRM((TB, _T("Read Offscreen support level %d"), offscrSupportLevel));
if (offscrSupportLevel > TS_OFFSCREEN_DEFAULT) {
_pCc->_ccCombinedCapabilities.offscreenCapabilitySet.offscreenSupportLevel =
offscrSupportLevel;
_pCc->_ccCombinedCapabilities.offscreenCapabilitySet.offscreenCacheSize =
(DCUINT16) _UH.offscrCacheSize;
_pCc->_ccCombinedCapabilities.offscreenCapabilitySet.offscreenCacheEntries =
(DCUINT16) _UH.offscrCacheEntries;
}
else {
_pCc->_ccCombinedCapabilities.offscreenCapabilitySet.offscreenSupportLevel =
TS_OFFSCREEN_DEFAULT;
_pCc->_ccCombinedCapabilities.offscreenCapabilitySet.offscreenCacheSize = 0;
_pCc->_ccCombinedCapabilities.offscreenCapabilitySet.offscreenCacheEntries = 0;
}
DC_EXIT_POINT:
DC_END_FN();
return rc;
}
#ifdef DRAW_NINEGRID
/****************************************************************************/
// Name: UHAllocDrawNineGridCacheMemory
//
// Purpose: Dynamically allocates memory for the UH drawninegrid caches.
//
// Returns: TRUE if successful, FALSE otherwise.
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHAllocDrawNineGridCacheMemory()
{
DCBOOL rc;
DCINT dngSupportLevel;
DCINT dngEmulate;
HDC hdcDesktop = NULL;
DC_BEGIN_FN("UHAllocDrawNineGridCacheMemory");
rc = FALSE;
/************************************************************************/
// Determine DrawNineGrid Support Level
/************************************************************************/
dngSupportLevel = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_DRAW_NINEGRID_SUPPORT,
UTREG_UH_DRAW_NINEGRID_SUPPORT_DFLT);
dngEmulate = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_DRAW_NINEGRID_EMULATE,
UTREG_UH_DRAW_NINEGRID_EMULATE_DFLT);
_UH.drawNineGridCacheSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_DRAW_NINEGRID_CACHESIZE,
UTREG_UH_DRAW_NINEGRID_CACHESIZE_DFLT);
_UH.drawNineGridCacheEntries = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_DRAW_NINEGRID_CACHEENTRIES,
UTREG_UH_DRAW_NINEGRID_CACHEENTRIES_DFLT);
// Check boundary values for drawninegrid cache parameters
if ((dngSupportLevel < TS_DRAW_NINEGRID_DEFAULT))
dngSupportLevel = UTREG_UH_DRAW_NINEGRID_SUPPORT_DFLT;
if (_UH.drawNineGridCacheSize < UH_OBC_LOW_CACHESIZE ||
_UH.drawNineGridCacheSize > UH_OBC_HIGH_CACHESIZE) {
_UH.drawNineGridCacheSize = TS_DRAW_NINEGRID_CACHE_SIZE_DEFAULT;
}
if (_UH.drawNineGridCacheEntries < UH_OBC_LOW_CACHEENTRIES ||
_UH.drawNineGridCacheEntries > UH_OBC_HIGH_CACHEENTRIES) {
_UH.drawNineGridCacheEntries = TS_DRAW_NINEGRID_CACHE_ENTRIES_DEFAULT;
}
if (dngSupportLevel > TS_DRAW_NINEGRID_DEFAULT) {
if (_pUi->UI_GetOsMinorType() == TS_OSMINORTYPE_WINDOWS_NT) {
if (dngEmulate == 0) {
// get the handle to gdi32.dll library
_UH.hModuleGDI32 = LoadLibrary(TEXT("GDI32.DLL"));
if (_UH.hModuleGDI32 != NULL) {
// get the proc address for GdiDrawStream
_UH.pfnGdiDrawStream = (FNGDI_DRAWSTREAM *)GetProcAddress(_UH.hModuleGDI32,
"GdiDrawStream");
if (_UH.pfnGdiDrawStream == NULL) {
dngSupportLevel = TS_DRAW_NINEGRID_DEFAULT;
}
}
else {
dngSupportLevel = TS_DRAW_NINEGRID_DEFAULT;
}
}
else {
dngSupportLevel = TS_DRAW_NINEGRID_DEFAULT;
}
// If the platform doesn't support GdiDrawStream, see if it supports alphablend
// and transparent blt, if so, we can emulate the GdiDrawStream call
if (dngSupportLevel == TS_DRAW_NINEGRID_DEFAULT) {
_UH.hModuleMSIMG32 = LoadLibrary(TEXT("MSIMG32.DLL"));
if (_UH.hModuleMSIMG32 != NULL) {
// get the proc address for GdiAlphaBlend
_UH.pfnGdiAlphaBlend = (FNGDI_ALPHABLEND *)GetProcAddress(_UH.hModuleMSIMG32,
"AlphaBlend");
// get the proc address for GdiTransparentBlt
_UH.pfnGdiTransparentBlt = (FNGDI_TRANSPARENTBLT *)GetProcAddress(_UH.hModuleMSIMG32,
"TransparentBlt");
if (_UH.pfnGdiAlphaBlend != NULL && _UH.pfnGdiTransparentBlt != NULL) {
dngSupportLevel = TS_DRAW_NINEGRID_SUPPORTED_REV2;
}
}
else {
dngSupportLevel = TS_DRAW_NINEGRID_DEFAULT;
}
}
}
else {
// We don't support drawninegrid on win9x so far
dngSupportLevel = TS_DRAW_NINEGRID_DEFAULT;
}
}
if (dngSupportLevel > TS_DRAW_NINEGRID_DEFAULT) {
// Create DC for the drawNineGrid drawing
hdcDesktop = GetWindowDC(HWND_DESKTOP);
if (hdcDesktop) {
_UH.hdcDrawNineGridBitmap = CreateCompatibleDC(hdcDesktop);
if (_UH.hdcDrawNineGridBitmap) {
unsigned size;
SelectPalette(_UH.hdcDrawNineGridBitmap, _UH.hpalCurrent, FALSE);
RealizePalette(_UH.hdcDrawNineGridBitmap);
_UH.hDrawNineGridClipRegion = CreateRectRgn(0, 0, 0, 0);
if (_UH.hDrawNineGridClipRegion != NULL) {
// Create drawNineGrid cache
size = sizeof(UHDRAWSTREAMBITMAPCACHE) * _UH.drawNineGridCacheEntries;
_UH.drawNineGridBitmapCache = (PUHDRAWSTREAMBITMAPCACHE)UT_Malloc(_pUt, size);
if (_UH.drawNineGridBitmapCache != NULL) {
memset(_UH.drawNineGridBitmapCache, 0, size);
rc = TRUE;
DC_QUIT;
}
}
}
}
}
dngSupportLevel = TS_DRAW_NINEGRID_DEFAULT;
if (_UH.hdcDrawNineGridBitmap != NULL) {
DeleteDC(_UH.hdcDrawNineGridBitmap);
_UH.hdcDrawNineGridBitmap = NULL;
}
if (_UH.hDrawNineGridClipRegion != NULL) {
DeleteObject(_UH.hDrawNineGridClipRegion);
_UH.hDrawNineGridClipRegion = NULL;
}
if (_UH.drawNineGridBitmapCache != NULL) {
UT_Free(_pUt, _UH.drawNineGridBitmapCache);
_UH.drawNineGridBitmapCache = NULL;
}
DC_EXIT_POINT:
TRC_NRM((TB, _T("Read draw nine grid support level %d"), dngSupportLevel));
if (hdcDesktop != NULL) {
ReleaseDC(HWND_DESKTOP, hdcDesktop);
}
if (dngSupportLevel > TS_DRAW_NINEGRID_DEFAULT) {
_pCc->_ccCombinedCapabilities.drawNineGridCapabilitySet.drawNineGridSupportLevel =
dngSupportLevel;
_pCc->_ccCombinedCapabilities.drawNineGridCapabilitySet.drawNineGridCacheSize =
(DCUINT16) _UH.drawNineGridCacheSize;
_pCc->_ccCombinedCapabilities.drawNineGridCapabilitySet.drawNineGridCacheEntries =
(DCUINT16) _UH.drawNineGridCacheEntries;
}
else {
_pCc->_ccCombinedCapabilities.drawNineGridCapabilitySet.drawNineGridSupportLevel =
TS_DRAW_NINEGRID_DEFAULT;
_pCc->_ccCombinedCapabilities.drawNineGridCapabilitySet.drawNineGridCacheSize = 0;
_pCc->_ccCombinedCapabilities.drawNineGridCapabilitySet.drawNineGridCacheEntries = 0;
}
DC_END_FN();
return rc;
}
#endif
#ifdef DRAW_GDIPLUS
/****************************************************************************/
// Name: UHAllocDrawescapeCacheMemory
//
// Purpose: Dynamically allocates memory for the UH drawescape caches.
//
// Returns: TRUE if successful, FALSE otherwise.
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHAllocDrawGdiplusCacheMemory()
{
DCBOOL rc;
UINT GdipVersion;
UINT32 GdiplusSupportLevel;
unsigned size;
unsigned i;
DC_BEGIN_FN("UHAllocDrawEscapeCacheMemory");
rc = FALSE;
/************************************************************************/
// Determine DrawGdiplus Support Level
/************************************************************************/
GdiplusSupportLevel = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_DRAW_GDIPLUS_SUPPORT,
UTREG_UH_DRAW_GDIPLUS_SUPPORT_DFLT);
_UH.GdiplusCacheLevel = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH_DRAW_GDIPLUS_CACHE_LEVEL,
UTREG_UH_DRAW_GDIPLUS_CACHE_LEVEL_DFLT);
_UH.GdiplusGraphicsCacheEntries = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_GRAPHICS_CACHEENTRIES,
UTREG_UH_DRAW_GDIP_GRAPHICS_CACHEENTRIES_DFLT);
_UH.GdiplusObjectBrushCacheEntries = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_BRUSH_CACHEENTRIES,
UTREG_UH_DRAW_GDIP_BRUSH_CACHEENTRIES_DFLT);
_UH.GdiplusObjectPenCacheEntries = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_PEN_CACHEENTRIES,
UTREG_UH_DRAW_GDIP_PEN_CACHEENTRIES_DFLT);
_UH.GdiplusObjectImageCacheEntries = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_IMAGE_CACHEENTRIES,
UTREG_UH_DRAW_GDIP_IMAGE_CACHEENTRIES_DFLT);
_UH.GdiplusGraphicsCacheChunkSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_GRAPHICS_CACHE_CHUNKSIZE,
UTREG_UH_DRAW_GDIP_GRAPHICS_CACHE_CHUNKSIZE_DFLT);
_UH.GdiplusObjectBrushCacheChunkSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_BRUSH_CACHE_CHUNKSIZE,
UTREG_UH_DRAW_GDIP_BRUSH_CACHE_CHUNKSIZE_DFLT);
_UH.GdiplusObjectPenCacheChunkSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_PEN_CACHE_CHUNKSIZE,
UTREG_UH_DRAW_GDIP_PEN_CACHE_CHUNKSIZE_DFLT);
_UH.GdiplusObjectImageAttributesCacheChunkSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_IMAGEATTRIBUTES_CACHE_CHUNKSIZE,
UTREG_UH_DRAW_GDIP_IMAGEATTRIBUTES_CACHE_CHUNKSIZE_DFLT);
_UH.GdiplusObjectImageCacheChunkSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_IMAGE_CACHE_CHUNKSIZE,
UTREG_UH_DRAW_GDIP_IMAGE_CACHE_CHUNKSIZE_DFLT);
_UH.GdiplusObjectImageCacheTotalSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_IMAGE_CACHE_TOTALSIZE,
UTREG_UH_DRAW_GDIP_IMAGE_CACHE_TOTALSIZE_DFLT);
_UH.GdiplusObjectImageCacheMaxSize = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_IMAGE_CACHE_MAXSIZE,
UTREG_UH_DRAW_GDIP_IMAGE_CACHE_MAXSIZE_DFLT);
_UH.GdiplusObjectImageAttributesCacheEntries = _pUt->UT_ReadRegistryInt(UTREG_SECTION,
UTREG_UH__GDIPLUS_IMAGEATTRIBUTES_CACHEENTRIES,
UTREG_UH_DRAW_GDIP_IMAGEATTRIBUTES_CACHEENTRIES_DFLT);
// Check boundary values for drawgdiplus cache parameters
if (_UH.GdiplusGraphicsCacheEntries < UH_GDIP_LOW_CACHEENTRIES ||
_UH.GdiplusGraphicsCacheEntries > UH_GDIP_HIGH_CACHEENTRIES) {
_UH.GdiplusGraphicsCacheEntries = TS_GDIP_GRAPHICS_CACHE_ENTRIES_DEFAULT;
}
if (_UH.GdiplusObjectBrushCacheEntries < UH_GDIP_LOW_CACHEENTRIES ||
_UH.GdiplusObjectBrushCacheEntries > UH_GDIP_HIGH_CACHEENTRIES) {
_UH.GdiplusObjectBrushCacheEntries = TS_GDIP_BRUSH_CACHE_ENTRIES_DEFAULT;
}
if (_UH.GdiplusObjectPenCacheEntries < UH_GDIP_LOW_CACHEENTRIES ||
_UH.GdiplusObjectPenCacheEntries > UH_GDIP_HIGH_CACHEENTRIES) {
_UH.GdiplusObjectPenCacheEntries = TS_GDIP_PEN_CACHE_ENTRIES_DEFAULT;
}
if (_UH.GdiplusObjectImageCacheEntries < UH_GDIP_LOW_CACHEENTRIES ||
_UH.GdiplusObjectImageCacheEntries > UH_GDIP_HIGH_CACHEENTRIES) {
_UH.GdiplusObjectImageCacheEntries = TS_GDIP_IMAGE_CACHE_ENTRIES_DEFAULT;
}
if (_UH.GdiplusObjectImageAttributesCacheEntries < UH_GDIP_LOW_CACHEENTRIES ||
_UH.GdiplusObjectImageAttributesCacheEntries > UH_GDIP_HIGH_CACHEENTRIES) {
_UH.GdiplusObjectImageAttributesCacheEntries = TS_GDIP_IMAGEATTRIBUTES_CACHE_ENTRIES_DEFAULT;
}
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusSupportLevel =
TS_DRAW_GDIPLUS_DEFAULT;
// Adjust the client gdiplus support level to server support level
if (GdiplusSupportLevel > _UH.ServerGdiplusSupportLevel) {
GdiplusSupportLevel = _UH.ServerGdiplusSupportLevel;
}
if (GdiplusSupportLevel < TS_DRAW_GDIPLUS_SUPPORTED) {
DC_QUIT;
}
_UH.fSendDrawGdiplusErrorPDU = FALSE;
_UH.DrawGdiplusFailureCount = 0;
// get the handle to gdiplus.dll library
// Here we use LoadLibrarayA is because we want to avoid unicode wrapper
// it will be replace with IsolationAwareLoadLibraryA so that we can load the right
// version of gdiplus.dll
_UH.hModuleGDIPlus = LoadLibraryA("GDIPLUS.DLL");
if (_UH.hModuleGDIPlus != NULL) {
// get the proc address for GdipPlayTSClientRecord
_UH.pfnGdipPlayTSClientRecord = (FNGDIPPLAYTSCLIENTRECORD *)GetProcAddress(_UH.hModuleGDIPlus,
"GdipPlayTSClientRecord");
_UH.pfnGdiplusStartup = (FNGDIPLUSSTARTUP *)GetProcAddress(_UH.hModuleGDIPlus,
"GdiplusStartup");
_UH.pfnGdiplusShutdown = (FNGDIPLUSSHUTDOWN *)GetProcAddress(_UH.hModuleGDIPlus,
"GdiplusShutdown");
if ((NULL == _UH.pfnGdipPlayTSClientRecord) ||
(NULL == _UH.pfnGdiplusStartup) ||
(NULL == _UH.pfnGdiplusShutdown)) {
TRC_ERR((TB, _T("Can't load GdipPlayTSClientRecord")));
DC_QUIT;
}
else {
// Gdiplus Startup
if (!UHDrawGdiplusStartup(0)){
TRC_ERR((TB, _T("UHDrawGdiplusStartup failed")));
DC_QUIT;
}
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusSupportLevel =
TS_DRAW_GDIPLUS_SUPPORTED;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheEntries.GdipGraphicsCacheEntries =
(TSINT16)_UH.GdiplusGraphicsCacheEntries;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheEntries.GdipObjectBrushCacheEntries =
(TSINT16)_UH.GdiplusObjectBrushCacheEntries;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheEntries.GdipObjectPenCacheEntries =
(TSINT16)_UH.GdiplusObjectPenCacheEntries;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheEntries.GdipObjectImageCacheEntries =
(TSINT16)_UH.GdiplusObjectImageCacheEntries;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheEntries.GdipObjectImageAttributesCacheEntries =
(TSINT16)_UH.GdiplusObjectImageAttributesCacheEntries;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheChunkSize.GdipGraphicsCacheChunkSize =
(TSINT16)_UH.GdiplusGraphicsCacheChunkSize;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheChunkSize.GdipObjectBrushCacheChunkSize =
(TSINT16)_UH.GdiplusObjectBrushCacheChunkSize;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheChunkSize.GdipObjectPenCacheChunkSize =
(TSINT16)_UH.GdiplusObjectPenCacheChunkSize;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipCacheChunkSize.GdipObjectImageAttributesCacheChunkSize =
(TSINT16)_UH.GdiplusObjectImageAttributesCacheChunkSize;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipImageCacheProperties.GdipObjectImageCacheChunkSize =
(TSINT16)_UH.GdiplusObjectImageCacheChunkSize;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipImageCacheProperties.GdipObjectImageCacheTotalSize =
(TSINT16)_UH.GdiplusObjectImageCacheTotalSize;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.GdipImageCacheProperties.GdipObjectImageCacheMaxSize =
(TSINT16)_UH.GdiplusObjectImageCacheMaxSize;
}
}
else {
TRC_ERR((TB, _T("Can't load gdiplus.dll")));
DC_QUIT;
}
if (_UH.GdiplusCacheLevel < TS_DRAW_GDIPLUS_CACHE_LEVEL_ONE) {
TRC_NRM((TB, _T("Don't support drawGdiplus Cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = sizeof(UHGDIPLUSOBJECTCACHE) * _UH.GdiplusGraphicsCacheEntries;
_UH.GdiplusGraphicsCache = (PUHGDIPLUSOBJECTCACHE)UT_Malloc(_pUt, size);
if (_UH.GdiplusGraphicsCache != NULL) {
memset(_UH.GdiplusGraphicsCache, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = sizeof(UHGDIPLUSOBJECTCACHE) * _UH.GdiplusObjectBrushCacheEntries;
_UH.GdiplusObjectBrushCache = (PUHGDIPLUSOBJECTCACHE)UT_Malloc(_pUt, size);
if (_UH.GdiplusObjectBrushCache != NULL) {
memset(_UH.GdiplusObjectBrushCache, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = sizeof(UHGDIPLUSOBJECTCACHE) * _UH.GdiplusObjectPenCacheEntries;
_UH.GdiplusObjectPenCache = (PUHGDIPLUSOBJECTCACHE)UT_Malloc(_pUt, size);
if (_UH.GdiplusObjectPenCache != NULL) {
memset(_UH.GdiplusObjectPenCache, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = sizeof(UHGDIPLUSOBJECTCACHE) * _UH.GdiplusObjectImageAttributesCacheEntries;
_UH.GdiplusObjectImageAttributesCache = (PUHGDIPLUSOBJECTCACHE)UT_Malloc(_pUt, size);
if (_UH.GdiplusObjectImageAttributesCache != NULL) {
memset(_UH.GdiplusObjectImageAttributesCache, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = sizeof(UHGDIPLUSIMAGECACHE) * _UH.GdiplusObjectImageCacheEntries;
_UH.GdiplusObjectImageCache = (PUHGDIPLUSIMAGECACHE)UT_Malloc(_pUt, size);
if (_UH.GdiplusObjectImageCache != NULL) {
memset(_UH.GdiplusObjectImageCache, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = _UH.GdiplusGraphicsCacheChunkSize * _UH.GdiplusGraphicsCacheEntries;
_UH.GdipGraphicsCacheData = (BYTE *)UT_Malloc(_pUt, size);
if (_UH.GdipGraphicsCacheData != NULL) {
memset(_UH.GdipGraphicsCacheData, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
for (i=0; i<_UH.GdiplusGraphicsCacheEntries; i++) {
_UH.GdiplusGraphicsCache[i].CacheData = _UH.GdipGraphicsCacheData + i * _UH.GdiplusGraphicsCacheChunkSize;
}
size = _UH.GdiplusObjectBrushCacheChunkSize * _UH.GdiplusObjectBrushCacheEntries;
_UH.GdipBrushCacheData = (BYTE *)UT_Malloc(_pUt, size);
if (_UH.GdipBrushCacheData != NULL) {
memset(_UH.GdipBrushCacheData, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
for (i=0; i<_UH.GdiplusObjectBrushCacheEntries; i++) {
_UH.GdiplusObjectBrushCache[i].CacheData = _UH.GdipBrushCacheData + i * _UH.GdiplusObjectBrushCacheChunkSize;
}
size = _UH.GdiplusObjectPenCacheChunkSize * _UH.GdiplusObjectPenCacheEntries;
_UH.GdipPenCacheData = (BYTE *)UT_Malloc(_pUt, size);
if (_UH.GdipPenCacheData != NULL) {
memset(_UH.GdipPenCacheData, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
for (i=0; i<_UH.GdiplusObjectPenCacheEntries; i++) {
_UH.GdiplusObjectPenCache[i].CacheData = _UH.GdipPenCacheData + i * _UH.GdiplusObjectPenCacheChunkSize;
}
size = _UH.GdiplusObjectImageAttributesCacheChunkSize * _UH.GdiplusObjectImageAttributesCacheEntries;
_UH.GdipImageAttributesCacheData = (BYTE *)UT_Malloc(_pUt, size);
if (_UH.GdipImageAttributesCacheData != NULL) {
memset(_UH.GdipImageAttributesCacheData, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
for (i=0; i<_UH.GdiplusObjectImageAttributesCacheEntries; i++) {
_UH.GdiplusObjectImageAttributesCache[i].CacheData = _UH.GdipImageAttributesCacheData + i * _UH.GdiplusObjectImageAttributesCacheChunkSize;
}
size = _UH.GdiplusObjectImageCacheChunkSize * _UH.GdiplusObjectImageCacheTotalSize;
_UH.GdipImageCacheData = (BYTE *)UT_Malloc(_pUt, size);
if (_UH.GdipImageCacheData != NULL) {
memset(_UH.GdipImageCacheData, 0, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = sizeof(INT16) * _UH.GdiplusObjectImageCacheTotalSize;
_UH.GdipImageCacheFreeList = (INT16 *)UT_Malloc(_pUt, size);
if (_UH.GdipImageCacheFreeList != NULL) {
memset(_UH.GdipImageCacheFreeList, GDIP_CACHE_INDEX_DEFAULT, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
size = sizeof(INT16) * _UH.GdiplusGraphicsCacheEntries * _UH.GdiplusObjectImageCacheMaxSize;
_UH.GdipImageCacheIndex = (INT16 *)UT_Malloc(_pUt, size);
if (_UH.GdipImageCacheIndex != NULL) {
memset(_UH.GdipImageCacheIndex, GDIP_CACHE_INDEX_DEFAULT, size);
}
else {
TRC_ERR((TB, _T("Can't allocate memory for gdiplus cache")));
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_DEFAULT;
goto NO_CACHE;
}
for (i=0; i<_UH.GdiplusObjectImageCacheEntries; i++) {
_UH.GdiplusObjectImageCache[i].CacheDataIndex = (_UH.GdipImageCacheIndex + i * (TSINT16)_UH.GdiplusObjectImageCacheMaxSize);
}
for (i=0; i<_UH.GdiplusObjectImageCacheTotalSize - 1; i++) {
_UH.GdipImageCacheFreeList[i] = i + 1;
}
_UH.GdipImageCacheFreeList[_UH.GdiplusObjectImageCacheTotalSize - 1] = GDIP_CACHE_INDEX_DEFAULT;
_UH.GdipImageCacheFreeListHead = 0;
_pCc->_ccCombinedCapabilities.drawGdiplusCapabilitySet.drawGdiplusCacheLevel =
TS_DRAW_GDIPLUS_CACHE_LEVEL_ONE;
NO_CACHE:
rc = TRUE;
return rc;
DC_EXIT_POINT:
if (_UH.hModuleGDIPlus != NULL) {
FreeLibrary(_UH.hModuleGDIPlus);
_UH.pfnGdipPlayTSClientRecord = NULL;
_UH.hModuleGDIPlus = NULL;
}
DC_END_FN();
return rc;
}
#endif // DRAW_GDIPLUS
/****************************************************************************/
/* Name: UHFreeCacheMemory */
/* */
/* Purpose: Frees memory allocated for the UH caches. Called at app exit. */
/****************************************************************************/
void DCINTERNAL CUH::UHFreeCacheMemory()
{
DCUINT i;
DC_BEGIN_FN("UHFreeCacheMemory");
// Color table cache
if (_UH.pColorTableCache != NULL) {
UT_Free(_pUt, _UH.pColorTableCache);
}
if (_UH.pMappedColorTableCache != NULL) {
UT_Free(_pUt, _UH.pMappedColorTableCache);
}
// Bitmap cache. These should already have been freed in UH_Disable(),
// but check again here on exit.
for (i = 0; i < TS_BITMAPCACHE_MAX_CELL_CACHES; i++)
{
if (_UH.bitmapCache[i].Header != NULL) {
UT_Free( _pUt, _UH.bitmapCache[i].Header);
_UH.bitmapCache[i].Header = NULL;
}
if (_UH.bitmapCache[i].Entries != NULL) {
UT_Free( _pUt, _UH.bitmapCache[i].Entries);
_UH.bitmapCache[i].Entries = NULL;
}
#if ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
// free the bitmap page table
if (_UH.bitmapCache[i].PageTable.PageEntries != NULL) {
UT_Free( _pUt, _UH.bitmapCache[i].PageTable.PageEntries);
_UH.bitmapCache[i].PageTable.PageEntries = NULL;
}
// free the bitmap key database
if (_UH.pBitmapKeyDB[i] != NULL) {
UT_Free( _pUt, _UH.pBitmapKeyDB[i]);
_UH.pBitmapKeyDB[i] = NULL;
}
#endif // ((!defined(OS_WINCE)) || (defined(ENABLE_BMP_CACHING_FOR_WINCE)))
}
_UH.NumBitmapCaches = 0;
// Glyph cache
for (i = 0; i < UH_GLC_NUM_CACHES; i++) {
if (_UH.glyphCache[i].pHdr != NULL) {
UT_Free( _pUt, _UH.glyphCache[i].pHdr);
_UH.glyphCache[i].pHdr = NULL;
}
if (_UH.glyphCache[i].pData != NULL) {
UT_Free( _pUt, _UH.glyphCache[i].pData);
_UH.glyphCache[i].pData = NULL;
}
}
// Frag cache
if (_UH.fragCache.pHdr != NULL) {
UT_Free( _pUt, _UH.fragCache.pHdr);
_UH.fragCache.pHdr = NULL;
}
if (_UH.fragCache.pData != NULL) {
UT_Free( _pUt, _UH.fragCache.pData);
_UH.fragCache.pData = NULL;
}
// Brush caches and bitmap patterns
if (_UH.pMonoBrush)
{
UT_Free( _pUt, _UH.pMonoBrush);
_UH.pMonoBrush = NULL;
}
if (_UH.bmpMonoPattern) {
DeleteObject(_UH.bmpMonoPattern);
_UH.bmpMonoPattern = NULL;
}
if (_UH.pColorBrushInfo)
{
UT_Free( _pUt, _UH.pColorBrushInfo);
_UH.pColorBrushInfo = NULL;
}
#ifdef DC_HICOLOR
if (_UH.pHiColorBrushInfo)
{
UT_Free( _pUt, _UH.pHiColorBrushInfo);
_UH.pHiColorBrushInfo = NULL;
}
#endif
if (_UH.pColorBrush)
{
UT_Free( _pUt, _UH.pColorBrush);
_UH.pColorBrush = NULL;
}
if (_UH.bmpColorPattern)
{
DeleteObject(_UH.bmpColorPattern);
_UH.bmpColorPattern = NULL;
}
#ifdef OS_WINCE //
if (_UH.hdcMemCached != NULL)
DeleteDC(_UH.hdcMemCached);
if (_UH.hBitmapCacheDIB != NULL)
{
DeleteBitmap(_UH.hBitmapCacheDIB);
_UH.hBitmapCacheDIBits = NULL;
}
#endif
// Offscreen Cache
if (_UH.offscrBitmapCache != NULL) {
UT_Free(_pUt, _UH.offscrBitmapCache);
}
#ifdef DRAW_NINEGRID
// DrawNineGrid Cache
if (_UH.drawNineGridBitmapCache != NULL) {
UT_Free(_pUt, _UH.drawNineGridBitmapCache);
}
#endif
#ifdef DRAW_GDIPLUS
// DrawGdiplus Cache Index
if (_UH.GdiplusGraphicsCache != NULL) {
UT_Free(_pUt, _UH.GdiplusGraphicsCache);
}
if (_UH.GdiplusObjectBrushCache != NULL) {
UT_Free(_pUt, _UH.GdiplusObjectBrushCache);
}
if (_UH.GdiplusObjectPenCache != NULL) {
UT_Free(_pUt, _UH.GdiplusObjectPenCache);
}
if (_UH.GdiplusObjectImageCache != NULL) {
UT_Free(_pUt, _UH.GdiplusObjectImageCache);
}
if (_UH.GdiplusObjectImageAttributesCache != NULL) {
UT_Free(_pUt, _UH.GdiplusObjectImageAttributesCache);
}
// DrawGdiplus Cache Data
if (_UH.GdipGraphicsCacheData != NULL) {
UT_Free(_pUt, _UH.GdipGraphicsCacheData);
}
if (_UH.GdipBrushCacheData != NULL) {
UT_Free(_pUt, _UH.GdipBrushCacheData);
}
if (_UH.GdipPenCacheData != NULL) {
UT_Free(_pUt, _UH.GdipPenCacheData);
}
if (_UH.GdipImageAttributesCacheData != NULL) {
UT_Free(_pUt, _UH.GdipImageAttributesCacheData);
}
// DrawGdiplus Image Cache Free Chunk List
if (_UH.GdipImageCacheFreeList != NULL) {
UT_Free(_pUt, _UH.GdipImageCacheFreeList);
}
if (_UH.GdipImageCacheIndex != NULL) {
UT_Free(_pUt, _UH.GdipImageCacheIndex);
}
if (_UH.GdipImageCacheData != NULL) {
UT_Free(_pUt, _UH.GdipImageCacheData);
}
#endif // DRAW_GDIPLUS
DC_END_FN();
}
/****************************************************************************/
/* Name: UHCreateBitmap */
/* */
/* Purpose: Creates a bitmap of the specified size and selects it into */
/* the specified device context. */
/* */
/* Returns: TRUE if successful, FALSE otherwise. */
/* */
/* Params: OUT phBitmap - handle to new bitmap */
/* OUT phdcBitmap - new DC handle */
/* OUT phUnusedBitmap - handle of DC's previous bitmap */
/* IN bitmapSize - requested bitmap size */
/* IN OPTIONAL nForceBmpBpp - forces bpp to specific value */
/* */
/****************************************************************************/
DCBOOL DCINTERNAL CUH::UHCreateBitmap(
HBITMAP *phBitmap,
HDC *phdcBitmap,
HBITMAP *phUnusedBitmap,
DCSIZE bitmapSize,
INT nForceBmpBpp)
{
HDC hdcDesktop = NULL;
BOOL rc = TRUE;
#ifdef USE_DIBSECTION
unsigned size;
UINT16 FAR *pColors;
unsigned i;
LPBITMAPINFO pbmi = NULL;
PVOID pBitmapBits;
#endif /* USE_DIBSECTION */
DC_BEGIN_FN("UHCreateBitmap");
TRC_ASSERT((NULL == *phBitmap),
(TB, _T("phBitmap non-NULL: %p"), *phBitmap));
TRC_ASSERT(NULL == (*phdcBitmap),
(TB, _T("phdcBitmap non-NULL: %p"), *phdcBitmap));
TRC_ASSERT((NULL == *phUnusedBitmap),
(TB, _T("phUnusedBitmap non-NULL: %p"), *phUnusedBitmap));
TRC_NRM((TB, _T("Bitmap size: (%u x %u)"), bitmapSize.width,
bitmapSize.height));
hdcDesktop = GetWindowDC(HWND_DESKTOP);
// Create the bitmap DC.
TRC_DBG((TB, _T("Create the bitmap DC")));
*phdcBitmap = CreateCompatibleDC(hdcDesktop);
if (NULL == *phdcBitmap)
{
TRC_ERR((TB, _T("Failed to create phdcBitmap")));
rc = FALSE;
DC_QUIT;
}
#ifdef USE_DIBSECTION
/************************************************************************/
/* Don't use DibSection on 4bpp displays - it slows down the Win32 */
/* Client something rotten. */
/************************************************************************/
if (_pUi->UI_GetColorDepth() != 4)
{
/********************************************************************/
/* Calcuate the amount of memory that we need to allocate. This is */
/* the size of the bitmap header plus a color table. */
/********************************************************************/
size = sizeof(BITMAPINFOHEADER) +
(UH_NUM_8BPP_PAL_ENTRIES * sizeof(DCUINT16));
/********************************************************************/
/* Now allocate the memory. */
/********************************************************************/
pbmi = (LPBITMAPINFO) UT_Malloc( _pUt, size);
if (NULL == pbmi)
{
TRC_ERR((TB, _T("Failed to allocate %u bytes for bitmapinfo"), size));
DC_QUIT;
}
/********************************************************************/
/* Now fill-in the bitmap info header. */
/* */
/* Use a negative value for the height to create a "top-down" */
/* bitmap. This makes little (no) difference for the current code, */
/* but will make things easier in future if we access the shadow */
/* DibSection bits directly. */
/********************************************************************/
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = (int)bitmapSize.width;
pbmi->bmiHeader.biHeight = -(int)bitmapSize.height;
pbmi->bmiHeader.biPlanes = 1;
#ifdef DC_HICOLOR
#ifdef USE_GDIPLUS
pbmi->bmiHeader.biBitCount = 32;
#else // USE_GDIPLUS
if (!nForceBmpBpp) {
pbmi->bmiHeader.biBitCount = (WORD)_UH.bitmapBpp;
}
else {
pbmi->bmiHeader.biBitCount = (WORD)nForceBmpBpp;
}
#endif // USE_GDIPLUS
#else
pbmi->bmiHeader.biBitCount = 8;
#endif
pbmi->bmiHeader.biCompression = BI_RGB;
pbmi->bmiHeader.biSizeImage = 0;
pbmi->bmiHeader.biXPelsPerMeter = 0;
pbmi->bmiHeader.biYPelsPerMeter = 0;
pbmi->bmiHeader.biClrUsed = 0;
pbmi->bmiHeader.biClrImportant = 0;
if (!nForceBmpBpp) {
#ifndef USE_GDIPLUS
#ifdef DC_HICOLOR
/********************************************************************/
/* Do color depth-specific setup */
/********************************************************************/
if (_UH.protocolBpp == 16)
{
/****************************************************************/
/* 16 bpp uses two bytes, with the color masks defined in the */
/* bmiColors field in the order R, G, B. We use */
/* - LS 5 bits = blue = 0x001f */
/* - next 6 bits = green mask = 0x07e0 */
/* - next 5 bits = red mask = 0xf800 */
/****************************************************************/
pbmi->bmiHeader.biCompression = BI_BITFIELDS;
pbmi->bmiHeader.biClrUsed = 3;
*((PDCUINT32)&pbmi->bmiColors[0]) = TS_RED_MASK_16BPP;
*((PDCUINT32)&pbmi->bmiColors[1]) = TS_GREEN_MASK_16BPP;
*((PDCUINT32)&pbmi->bmiColors[2]) = TS_BLUE_MASK_16BPP;
}
else
if (_UH.protocolBpp < 15)
{
#endif
/********************************************************************/
/* Fill in the color table. The color indexes we use are indexes */
/* into the currently selected palette. However, the values used */
/* are irrelevant (so we simply use 0 for every color) as we will */
/* always receive a new palette before we receive any updates, and */
/* UHProcessPalettePDU will set the DIBSection color table */
/* correctly. */
/********************************************************************/
pColors = (PDCUINT16) pbmi->bmiColors;
for (i = 0; i < UH_NUM_8BPP_PAL_ENTRIES; i++)
{
*pColors = (DCUINT16) 0;
pColors++;
}
#ifdef DC_HICOLOR
}
#endif
#endif // USE_GDIPLUS
}
/********************************************************************/
/* Attempt to create the DIB section. */
/********************************************************************/
*phBitmap = CreateDIBSection(hdcDesktop,
pbmi,
#ifdef DC_HICOLOR
_UH.DIBFormat,
#else
DIB_PAL_COLORS,
#endif
&pBitmapBits,
NULL,
0);
#ifdef DC_HICOLOR
if (NULL == *phBitmap)
{
TRC_ERR((TB, _T("Failed to create dib section, last error %d"),
GetLastError() ));
}
#endif
TRC_NRM((TB, _T("Using DIBSection")));
_UH.usingDIBSection = TRUE;
}
else
#endif /* USE_DIBSECTION */
{
/********************************************************************/
/* Create the bitmap. */
/********************************************************************/
*phBitmap = CreateCompatibleBitmap(hdcDesktop,
(int)bitmapSize.width,
(int)bitmapSize.height);
TRC_NRM((TB, _T("Not using DIBSection")));
_UH.usingDIBSection = FALSE;
}
if (NULL == *phBitmap)
{
TRC_ERR((TB, _T("Failed to create bitmap of size (%u, %u)"),
bitmapSize.width, bitmapSize.height));
/********************************************************************/
/* if the bitmap creation failed tidy up the DC we created */
/********************************************************************/
DeleteDC(*phdcBitmap);
*phdcBitmap = NULL;
/********************************************************************/
/* and quit */
/********************************************************************/
rc = FALSE;
DC_QUIT;
}
/************************************************************************/
/* Select the bitmap into hdcBitmap. */
/************************************************************************/
*phUnusedBitmap = SelectBitmap(*phdcBitmap, *phBitmap);
TRC_NRM((TB, _T("Created Bitmap(%u x %u): %p"), bitmapSize.width,
bitmapSize.height,
*phBitmap));
#ifdef DC_HICOLOR
if (_UH.protocolBpp <= 8)
{
#endif
/************************************************************************/
/* Also select the default palette. */
/************************************************************************/
TRC_DBG((TB, _T("Select default palette %p"), _UH.hpalDefault));
SelectPalette(*phdcBitmap, _UH.hpalDefault, FALSE);
#ifdef DC_HICOLOR
}
#endif
DC_EXIT_POINT:
if (NULL != hdcDesktop)
{
ReleaseDC(HWND_DESKTOP, hdcDesktop);
}
#ifdef USE_DIBSECTION
/************************************************************************/
/* Free the memory that we allocated for the bitmap info header. */
/************************************************************************/
if (NULL != pbmi)
{
TRC_NRM((TB, _T("Freeing mem (at %p) for bitmap info header"), pbmi));
UT_Free( _pUt, pbmi);
}
#endif /* USE_DIBSECTION */
DC_END_FN();
return rc;
}
/****************************************************************************/
/* Name: UHDeleteBitmap */
/* */
/* Purpose: Deletes a Bitmap. */
/* */
/* Params: IN/OUT phdcBitmap - handle of DC to be deleted */
/* IN/OUT phBitmap - handle of bitmap to be deleted */
/* IN/OUT phUnused - handle of DC's previous bitmap */
/* */
/* Operation: All parameters set to NULL on return */
/****************************************************************************/
DCVOID DCINTERNAL CUH::UHDeleteBitmap(HDC* phdcBitmap,
HBITMAP* phBitmap,
HBITMAP* phUnused)
{
HBITMAP hBitmapScratch;
HPALETTE hpalCurrent;
DC_BEGIN_FN("UHDeleteBitmap");
TRC_ASSERT((NULL != *phBitmap),
(TB, _T("phBitmap is NULL")));
TRC_NRM((TB, _T("Delete Bitmap: %#hx"), *phBitmap));
#ifdef DC_HICOLOR
if (_UH.protocolBpp <= 8)
{
#endif
/************************************************************************/
/* Restore the default palette. But DO NOT delete the returned */
/* palette, as it may be in use by other DCs. */
/************************************************************************/
hpalCurrent = SelectPalette(*phdcBitmap,
_UH.hpalDefault,
FALSE);
#ifndef DC_HICOLOR // consider the case where we previously had no palette...
TRC_ASSERT((hpalCurrent == _UH.hpalCurrent),
(TB, _T("Palettes differ: (%p) (%p)"),
hpalCurrent, _UH.hpalCurrent));
#endif
#ifdef DC_HICOLOR
}
#endif
/************************************************************************/
/* Deselect the bitmap from the DC. */
/************************************************************************/
hBitmapScratch = SelectBitmap(*phdcBitmap, *phUnused);
TRC_ASSERT((hBitmapScratch == *phBitmap), (TB,_T("Bad bitmap deselected")));
/************************************************************************/
/* Now delete the bitmap and DC. */
/************************************************************************/
DeleteBitmap(*phBitmap);
DeleteDC(*phdcBitmap);
*phUnused = NULL;
*phBitmap = NULL;
*phdcBitmap = NULL;
DC_END_FN();
}
/****************************************************************************/
/* Name: GHSetShadowBitmapInfo */
/* */
/* Purpose: Sets UH shadow bitmap bitmap info. */
/****************************************************************************/
DCVOID DCINTERNAL CUH::GHSetShadowBitmapInfo(DCVOID)
{
#ifdef USE_DIBSECTION
DIBSECTION dibSection;
#endif
DC_BEGIN_FN("GHSetShadowBitmapInfo");
_UH.bmShadowBits = NULL;
_UH.bmShadowWidth = 0;
_UH.bmShadowHeight = 0;
#ifdef USE_DIBSECTION
if ((_UH.hShadowBitmap != NULL) && _UH.usingDIBSection)
{
if (sizeof(dibSection) == GetObject(_UH.hShadowBitmap,
sizeof(dibSection), &dibSection))
{
_UH.bmShadowBits = (PDCUINT8)dibSection.dsBm.bmBits;
_UH.bmShadowWidth = dibSection.dsBm.bmWidth;
_UH.bmShadowHeight = dibSection.dsBm.bmHeight;
}
}
#endif
#ifdef OS_WINCE
#ifdef HDCL1171PARTIAL
if (_UH.bmShadowBits == NULL)
{
int cx;
int cy;
int cbSize;
LPVOID pvPhysical;
LPVOID pvVirtual;
cx = GetDeviceCaps((HDC)NULL, HORZRES);
cy = GetDeviceCaps((HDC)NULL, VERTRES);
cbSize = cx * cy + (cx << 1);
pvPhysical = (LPVOID) 0xaa000000;
if ((pvVirtual = VirtualAlloc(0, cbSize, MEM_RESERVE, PAGE_NOACCESS))
!= NULL)
{
if (VirtualCopy(pvVirtual, pvPhysical, cbSize,
PAGE_NOCACHE | PAGE_READWRITE))
{
_UH.bmShadowBits = (PDCUINT8) pvVirtual + (cx << 1);
_UH.bmShadowWidth = cx;
_UH.bmShadowHeight = cy;
}
}
}
#endif // HDCL1171PARTIAL
#endif // OS_WINCE
DC_EXIT_POINT:
DC_END_FN();
}
/****************************************************************************/
/* Name: UHMaybeCreateShadowBitmap */
/* */
/* Purpose: Decides whether to create the Shadow Bitmap for this */
/* connection. */
/****************************************************************************/
DCVOID DCINTERNAL CUH::UHMaybeCreateShadowBitmap(DCVOID)
{
DCSIZE desktopSize;
DC_BEGIN_FN("UHMaybeCreateShadowBitmap");
if (NULL != _UH.hShadowBitmap)
{
/********************************************************************/
/* A Shadow Bitmap exists. If it's the wrong size or has been */
/* disabled, delete it. */
/********************************************************************/
BITMAP bitmapDetails;
/********************************************************************/
/* See if the bitmap size matches the current desktop size. */
/********************************************************************/
if (sizeof(bitmapDetails) != GetObject(_UH.hShadowBitmap,
sizeof(bitmapDetails),
&bitmapDetails))
{
TRC_ERR((TB, _T("Failed to get bitmap details (%#hx)"),
_UH.hShadowBitmap));
}
_pUi->UI_GetDesktopSize(&desktopSize);
TRC_NRM((TB, _T("desktop(%u x %u) bitmap(%u x %u)"),
desktopSize.width, desktopSize.height,
bitmapDetails.bmWidth, bitmapDetails.bmHeight));
if ((bitmapDetails.bmWidth != (int)desktopSize.width) ||
(bitmapDetails.bmHeight != (int)desktopSize.height) ||
#ifdef DC_HICOLOR
(_UH.shadowBitmapBpp != _UH.protocolBpp) ||
#endif
!_UH.shadowBitmapRequested)
{
/****************************************************************/
/* Size is wrong or bitmap is no longer wanted. Delete it and */
/* clear the 'enabled' flag. */
/****************************************************************/
TRC_NRM((TB, _T("Shadow Bitmap size incorrect or unwanted")));
UHDeleteBitmap(&_UH.hdcShadowBitmap,
&_UH.hShadowBitmap,
&_UH.hunusedBitmapForShadowDC);
_UH.shadowBitmapEnabled = FALSE;
}
}
if ((_UH.shadowBitmapRequested) && (NULL == _UH.hShadowBitmap))
{
/********************************************************************/
/* The Shadow Bitmap was enabled, so attempt to create it. */
/********************************************************************/
TRC_DBG((TB, _T("Shadow Bitmap specified")));
/********************************************************************/
/* Get the current desktop size. */
/* The desktop size is specified by CC before calling this */
/* function, so assert that this has happened. */
/********************************************************************/
_pUi->UI_GetDesktopSize(&desktopSize);
if ((desktopSize.width == 0) &&
(desktopSize.height == 0))
{
TRC_ABORT((TB, _T("Desktop size not yet initialized")));
DC_QUIT;
}
if (UHCreateBitmap(&_UH.hShadowBitmap,
&_UH.hdcShadowBitmap,
&_UH.hunusedBitmapForShadowDC,
desktopSize))
{
TRC_NRM((TB, _T("Created Shadow Bitmap")));
_UH.shadowBitmapEnabled = TRUE;
#ifdef USE_GDIPLUS
_UH.shadowBitmapBpp = 32;
#else // USE_GDIPLUS
_UH.shadowBitmapBpp = _UH.protocolBpp;
#endif // USE_GDIPLUS
// inform CLX for the new shadow bitmap
_pClx->CLX_ClxEvent(CLX_EVENT_SHADOWBITMAPDC, (WPARAM)_UH.hdcShadowBitmap);
_pClx->CLX_ClxEvent(CLX_EVENT_SHADOWBITMAP, (WPARAM)_UH.hShadowBitmap);
}
else
{
TRC_ALT((TB, _T("Failed to create shadow bitmap")));
}
}
/********************************************************************/
/* Make sure the shadow bitmap info is correct */
/********************************************************************/
GHSetShadowBitmapInfo();
DC_EXIT_POINT:
DC_END_FN();
} /* UHMaybeCreateShadowBitmap */
/****************************************************************************/
/* Name: UHMaybeCreateSaveScreenBitmap */
/* */
/* Purpose: Decides whether to create the SSB bitmap */
/****************************************************************************/
DCVOID DCINTERNAL CUH::UHMaybeCreateSaveScreenBitmap(DCVOID)
{
DCSIZE size;
DC_BEGIN_FN("UHMaybeCreateSaveScreenBitmap");
if (_UH.shadowBitmapEnabled || _UH.dedicatedTerminal)
{
/********************************************************************/
/* Need an SSB bitmap */
/********************************************************************/
if (_UH.hSaveScreenBitmap == NULL)
{
/****************************************************************/
/* Attempt to create the SSB bitmap, provided it doesn't exist */
/* already. We will only get this far if */
/* - we have created a Shadow Bitmap OR */
/* - we're running Full Screen mode and don't need the shadow. */
/****************************************************************/
TRC_NRM((TB, _T("Attempt to create SSB bitmap")));
size.width = UH_SAVE_BITMAP_WIDTH;
size.height = UH_SAVE_BITMAP_HEIGHT;
if (UHCreateBitmap(&_UH.hSaveScreenBitmap,
&_UH.hdcSaveScreenBitmap,
&_UH.hunusedBitmapForSSBDC,
size))
{
TRC_NRM((TB, _T("SSB bitmap created")));
}
else
{
/************************************************************/
/* We failed to create the save screen bitmap. Just */
/* return. */
/************************************************************/
TRC_ALT((TB, _T("Failed to create SaveScreen bitmap")));
}
}
}
else if (_UH.hSaveScreenBitmap != NULL)
{
/********************************************************************/
/* We have an unwanted SSB bitmap. Delete it. */
/* This happens if it was created in a previous connection and we */
/* have now specified to run without the Shadow Bitmap and are not */
/* a dedicated terminal. */
/********************************************************************/
TRC_NRM((TB, _T("Delete unwanted SSB bitmap")));
UHDeleteBitmap(&_UH.hdcSaveScreenBitmap,
&_UH.hSaveScreenBitmap,
&_UH.hunusedBitmapForSSBDC);
}
DC_END_FN();
} /* UHMaybeCreateSaveScreenBitmap */
#ifdef OS_WINCE
/**PROC+*********************************************************************/
/* Name: UHGetPaletteCaps */
/* */
/* Purpose: Determine the palette capabilities for the device */
/* This function is NEVER called by WBT only by */
/* MAXALL/MINSHELL/etc... configs */
/* */
/* Returns: None */
/* */
/* Params: None */
/* */
/**PROC-*********************************************************************/
DCVOID DCINTERNAL CUH::UHGetPaletteCaps(DCVOID)
{
HDC hdcGlobal;
int iRasterCaps;
hdcGlobal = GetDC(NULL);
iRasterCaps = GetDeviceCaps(hdcGlobal, RASTERCAPS);
_UH.paletteIsFixed = (iRasterCaps & RC_PALETTE) ? FALSE : TRUE;
// Special hack for devices which return bogus information above.
// "CLIO" -> Vadem Clio
// "PV-6000" -> Sharp PV-6000
// "PC companion" -> Compaq C-Series
// "C600 I.T." -> NTS DreamWriter
if (!_UH.paletteIsFixed)
{
TCHAR szOEMInfo[32];
if (SystemParametersInfo(SPI_GETOEMINFO, sizeof(szOEMInfo)/sizeof(TCHAR), szOEMInfo, 0))
{
if ((_wcsnicmp(szOEMInfo, L"CLIO", 4) == 0) ||
(_wcsnicmp(szOEMInfo, L"PV-6000", 7) == 0) ||
(_wcsnicmp(szOEMInfo, L"PC companion", 12) == 0) ||
(_wcsnicmp(szOEMInfo, L"C600 I.T.", 9) == 0))
_UH.paletteIsFixed = TRUE;
}
}
// Allow users or OEMs to override the default palette settings with a registry key
if(_pUi->_UI.fOverrideDefaultPaletteIsFixed)
{
_UH.paletteIsFixed = _pUi->_UI.paletteIsFixed ? TRUE : FALSE;
}
ReleaseDC(NULL, hdcGlobal);
} /* UHGetPaletteCaps */
#endif // OS_WINCE
/****************************************************************************/
/* Name: UHGetANSICodePage */
/* */
/* Purpose: Get the local ANSI code page */
/* */
/* Operation: Look at the version info for GDI.EXE */
/****************************************************************************/
DCUINT DCINTERNAL CUH::UHGetANSICodePage(DCVOID)
{
DCUINT codePage;
DC_BEGIN_FN("UHGetANSICodePage");
//
// Get the ANSI code page. This function always returns a valid value.
//
codePage = GetACP();
TRC_NRM((TB, _T("Return codepage %u"), codePage));
DC_END_FN();
return(codePage);
} /* UHGetANSICodePage */
#if (defined(OS_WINCE) && defined (WINCE_SDKBUILD) && defined(SHx))
#pragma optimize("", off)
#endif
VOID CUH::UHResetAndRestartEnumeration()
{
DC_BEGIN_FN("UHResetAndRestartEnumeration");
TRC_NRM((TB,_T("Reseting and re-enumerating keys")));
//
// This fn is intended to be called to re-enumerate
// for a different color-depth
//
TRC_ASSERT(_UH.bBitmapKeyEnumComplete,
(TB,_T("Prev enum should be complete bBitmapKeyEnumComplete")));
UINT i = 0;
for (i = 0; i<_UH.NumBitmapCaches; i++)
{
_UH.numKeyEntries[i] = 0;
}
for (i=0; i<TS_BITMAPCACHE_MAX_CELL_CACHES; i++)
{
if (_UH.pBitmapKeyDB[i])
{
UT_Free( _pUt, _UH.pBitmapKeyDB[i]);
_UH.pBitmapKeyDB[i] = NULL;
}
}
_UH.currentFileHandle = INVALID_HANDLE_VALUE;
_UH.currentBitmapCacheId = 0;
_UH.bBitmapKeyEnumerating = FALSE;
_UH.bBitmapKeyEnumComplete = FALSE;
TRC_NRM((TB,_T("Re-enumerating for different color depth")));
_pCd->CD_DecoupleSimpleNotification(CD_SND_COMPONENT, this,
CD_NOTIFICATION_FUNC(CUH,UHEnumerateBitmapKeyList), 0);
DC_END_FN();
}
#if (defined(OS_WINCE) && defined (WINCE_SDKBUILD) && defined(SHx))
#pragma optimize("", on)
#endif
//
// Figure out the cache file name based on cacheId and copyMult
//
HRESULT CUH::UHSetCurrentCacheFileName(UINT cacheId, UINT copyMultiplier)
{
HRESULT hr = E_FAIL;
UINT cchLenRemain;
DC_BEGIN_FN("UHSetCurrentCacheFileName");
cchLenRemain = SIZE_TCHARS(_UH.PersistCacheFileName) -
(_UH.EndPersistCacheDir + 1);
if (1 == copyMultiplier) {
hr = StringCchPrintf(
&_UH.PersistCacheFileName[_UH.EndPersistCacheDir],
cchLenRemain,
_T("bcache%d.bmc"),
cacheId);
}
else {
hr = StringCchPrintf(
&_UH.PersistCacheFileName[_UH.EndPersistCacheDir],
cchLenRemain,
_T("bcache%d%d.bmc"),
cacheId,
copyMultiplier);
}
if (FAILED(hr)) {
TRC_ERR((TB,_T("Failed to printf cache file name: 0x%x"), hr));
}
TRC_NRM((TB,_T("Set cachefilename to %s"),
_UH.PersistCacheFileName));
DC_END_FN();
return hr;
}
BOOL CUH::UHCreateDisconnectedBitmap()
{
BOOL fResult = FALSE;
DCSIZE desktopSize;
DC_BEGIN_FN("UHCreateDisconnectedBitmap");
_pUi->UI_GetDesktopSize(&desktopSize);
if ((desktopSize.width == 0) &&
(desktopSize.height == 0)) {
TRC_ABORT((TB, _T("Desktop size not yet initialized")));
DC_QUIT;
}
//
// Delete any existing disabled bitmaps
//
if (_UH.hbmpDisconnectedBitmap && _UH.hdcDisconnected) {
UHDeleteBitmap(&_UH.hdcDisconnected,
&_UH.hbmpDisconnectedBitmap,
&_UH.hbmpUnusedDisconnectedBitmap);
}
//
// Create the disconnected backing bitmap
//
if (UHCreateBitmap(&_UH.hbmpDisconnectedBitmap,
&_UH.hdcDisconnected,
&_UH.hbmpUnusedDisconnectedBitmap,
desktopSize,
24)) {
TRC_NRM((TB, _T("Created UH disabled bitmap")));
fResult = TRUE;
}
else {
TRC_ALT((TB, _T("Failed to create UH disabled bitmap")));
}
//
// Get the window contents
//
if (fResult) {
HDC hdc = UH_GetCurrentOutputDC();
if (hdc) {
fResult = BitBlt(_UH.hdcDisconnected,
0, 0,
desktopSize.width,
desktopSize.height,
hdc,
0, 0,
SRCCOPY);
}
if (!fResult) {
TRC_ERR((TB, _T("BitBlt from screen to disconnect bmp failed")));
}
}
DC_EXIT_POINT:
DC_END_FN();
return fResult;
}