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.
 
 
 
 
 
 

645 lines
26 KiB

/****************************************************************************/
// ghapi.cpp
//
// Glyph handler - Windows specific
//
// Copyright (C) 1997-1999 Microsoft Corporation
/****************************************************************************/
#include <adcg.h>
extern "C" {
#define TRC_GROUP TRC_GROUP_CORE
#define TRC_FILE "wghapi"
#include <atrcapi.h>
}
#define TSC_HR_FILEID TSC_HR_GHAPI_CPP
#include "autil.h"
#include "gh.h"
#include "uh.h"
#include "clx.h"
static const PFN_MASTERTEXTTYPE MasterTextTypeTable[8] =
{
CGH::draw_nf_ntb_o_to_temp_start,
CGH::draw_f_ntb_o_to_temp_start,
CGH::draw_nf_ntb_o_to_temp_start,
CGH::draw_f_ntb_o_to_temp_start,
CGH::draw_nf_tb_no_to_temp_start,
CGH::draw_f_tb_no_to_temp_start,
CGH::draw_nf_ntb_o_to_temp_start,
CGH::draw_f_ntb_o_to_temp_start
};
CGH::CGH(CObjs* objs)
{
_pClientObjects = objs;
_pClipGlyphBitsBuffer = NULL;
_ClipGlyphBitsBufferSize = 0;
}
CGH::~CGH()
{
if (_pClipGlyphBitsBuffer!=NULL) {
LocalFree(_pClipGlyphBitsBuffer);
}
}
DCVOID DCAPI CGH::GH_Init(DCVOID)
{
DC_BEGIN_FN("GH_GlyphOut");
_pUh = _pClientObjects->_pUHObject;
_pClx = _pClientObjects->_pCLXObject;
_pUt = _pClientObjects->_pUtObject;
DC_END_FN();
}
/****************************************************************************/
/* Name: GH_GlyphOut */
/* */
/* Purpose: Process glyph output requests */
/* */
/* Returns: Process input event TRUE / FALSE */
/****************************************************************************/
HRESULT DCAPI CGH::GH_GlyphOut(
LPINDEX_ORDER pOrder,
LPVARIABLE_INDEXBYTES pVariableBytes)
{
HRESULT hr = E_FAIL;
BYTE szTextBuffer[GH_TEXT_BUFFER_SIZE];
BYTE ajFrag[256];
UINT16 ajUnicode[256];
unsigned ulBufferWidth;
unsigned fDrawFlags;
PDCUINT8 pjBuffer;
PDCUINT8 pjEndBuffer;
unsigned crclFringe;
RECT arclFringe[4];
unsigned i;
int x;
int y;
PDCUINT8 pjData;
PDCUINT8 pjDataEnd;
unsigned iGlyph;
unsigned cacheIndex;
unsigned cbFrag;
PDCUINT8 pjFrag;
PDCUINT8 pjFragEnd;
int dx;
INT16 delta;
ULONG BufferAlign;
ULONG BufferOffset;
unsigned ulBytes;
unsigned ulHeight;
PFN_MASTERTEXTTYPE pfnMasterType;
DC_BEGIN_FN("GH_GlyphOut");
dx = 0;
// SECURITY 558128: GH_GlyphOut must verify data in VARAIBLE_INDEXBYTES
// parameter which is defined as 255 elements
if (255 < pVariableBytes->len) {
TRC_ABORT(( TB, _T("variable bytes len too long %u"),
pVariableBytes->len));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
/************************************************************************/
// Alloc a temp work buffer -- use the stack buffer if large enough, or
// alloc heap memory if need be.
/************************************************************************/
// Make the buffer width WORD aligned.
ulBufferWidth = (unsigned)(((pOrder->BkRight + 31) & ~31) -
(pOrder->BkLeft & ~31)) >> 3;
ulHeight = (unsigned)(pOrder->BkBottom - pOrder->BkTop);
if ((ulBufferWidth <= FIFTEEN_BITS) && (ulHeight <= FIFTEEN_BITS)) {
ulBytes = ulBufferWidth * ulHeight + 64;
#ifdef DC_DEBUG
g_ulBytes = ulBytes;
#endif
// If the temp buffer is big enough, use it. Otherwise attempt to
// allocate enough memory to satisfy the request.
if (ulBytes <= (sizeof(szTextBuffer) - 20)) {
pjBuffer = szTextBuffer;
memset(szTextBuffer, 0, ulBytes);
}
else {
TRC_NRM((TB, _T("Allocating %d byte temp glyph buffer"), ulBytes));
pjBuffer = (PDCUINT8)UT_Malloc( _pUt, ulBytes);
if (pjBuffer != NULL) {
memset(pjBuffer, 0, ulBytes);
}
else {
TRC_NRM((TB, _T("Unable to alloc temp glyph buffer")));
DC_QUIT;
}
}
}
else {
TRC_NRM((TB, _T("Temp glyph buffer calc overflow")));
hr = E_TSC_UI_GLYPH;
DC_QUIT;
}
pjEndBuffer = pjBuffer + ulBytes;
#ifdef DC_HICOLOR
TRC_NRM((TB, _T("Glyph order w %d, h %d, fc %#06lx, bc %#06lx"),
ulBufferWidth, ulHeight, pOrder->ForeColor, pOrder->BackColor));
#endif
/************************************************************************/
// Clear the fringe opaque rect if need be.
/************************************************************************/
// crclFringe ends up holding the number of fringe rectangles to
// post-process.
crclFringe = 0;
if (pOrder->OpTop < pOrder->OpBottom) {
// Establish solid brush.
UHUseBrushOrg(0, 0, _pUh);
_pUh->UHUseSolidPaletteBrush(pOrder->ForeColor);
// If the background brush is a solid brush, we need to compute the
// fringe opaque area outside the text rectangle and include the
// remaining rectangle in the text output. The fringe rectangles will
// be output last to reduce flickering when a string is "moved"
// continuously across the screen.
if (pOrder->BrushStyle == BS_SOLID) {
// Top fragment
if (pOrder->BkTop > pOrder->OpTop) {
arclFringe[crclFringe].left = (int) pOrder->OpLeft;
arclFringe[crclFringe].top = (int) pOrder->OpTop;
arclFringe[crclFringe].right = (int) pOrder->OpRight;
arclFringe[crclFringe].bottom = (int) pOrder->BkTop;
crclFringe++;
}
// Left fragment
if (pOrder->BkLeft > pOrder->OpLeft) {
arclFringe[crclFringe].left = (int) pOrder->OpLeft;
arclFringe[crclFringe].top = (int) pOrder->BkTop;
arclFringe[crclFringe].right = (int) pOrder->BkLeft;
arclFringe[crclFringe].bottom = (int) pOrder->BkBottom;
crclFringe++;
}
// Right fragment
if (pOrder->BkRight < pOrder->OpRight) {
arclFringe[crclFringe].left = (int) pOrder->BkRight;
arclFringe[crclFringe].top = (int) pOrder->BkTop;
arclFringe[crclFringe].right = (int) pOrder->OpRight;
arclFringe[crclFringe].bottom = (int) pOrder->BkBottom;
crclFringe++;
}
// Bottom fragment
if (pOrder->BkBottom < pOrder->OpBottom) {
arclFringe[crclFringe].left = (int) pOrder->OpLeft;
arclFringe[crclFringe].top = (int) pOrder->BkBottom;
arclFringe[crclFringe].right = (int) pOrder->OpRight;
arclFringe[crclFringe].bottom = (int) pOrder->OpBottom;
crclFringe++;
}
}
else {
// If the background brush is a pattern brush, we will output the
// whole rectangle now.
PatBlt(_pUh->_UH.hdcDraw,
(int)pOrder->OpLeft,
(int)pOrder->OpTop,
(int)(pOrder->OpRight - pOrder->OpLeft),
(int)(pOrder->OpBottom - pOrder->OpTop),
PATCOPY);
}
}
/************************************************************************/
// Get fixed pitch, overlap, and top & bottom Y alignment flags.
/************************************************************************/
if ((pOrder->flAccel & SO_HORIZONTAL) &&
!(pOrder->flAccel & SO_REVERSED)) {
fDrawFlags = ((pOrder->ulCharInc != 0) |
(((pOrder->flAccel &
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT)) !=
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT)) << 1) |
(((pOrder->flAccel &
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE)) ==
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE)) << 2));
}
else {
fDrawFlags = 0;
}
/************************************************************************/
/* Draw the text into the temp buffer by selecting and calling the */
/* appropriate glyph dispatch routine */
/************************************************************************/
pfnMasterType = MasterTextTypeTable[fDrawFlags];
x = (int)pOrder->x;
y = (int)pOrder->y;
pjData = &(pVariableBytes->arecs[0].byte);
pjDataEnd = pjData + pVariableBytes->len;
BufferAlign = (pOrder->BkLeft & 31);
BufferOffset = (pOrder->BkLeft - BufferAlign);
iGlyph = 0;
GHFRAGRESET(0);
while (pjData < pjDataEnd) {
/********************************************************************/
/* 'Add Fragment' */
/********************************************************************/
if (*pjData == ORD_INDEX_FRAGMENT_ADD) {
HPUHFRAGCACHE pCache;
HPDCUINT8 pCacheEntryData;
PUHFRAGCACHEENTRYHDR pCacheEntryHdr;
pjData++;
CHECK_READ_N_BYTES(pjData, pjDataEnd, 2, hr,
( TB, _T("reading glyph data off end")));
cacheIndex = *pjData++;
hr = _pUh->UHIsValidFragmentCacheIndex(cacheIndex);
DC_QUIT_ON_FAIL(hr);
cbFrag = *pjData++;
// Add the fragment to the cache.
pCache = &_pUh->_UH.fragCache;
if (cbFrag > pCache->cbEntrySize) {
TRC_ABORT((TB,_T("Invalid fragment size")));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
pCacheEntryHdr = &(pCache->pHdr[cacheIndex]);
pCacheEntryHdr->cbFrag = cbFrag;
pCacheEntryHdr->cacheId = pOrder->cacheId;
pCacheEntryData = &(pCache->pData[cacheIndex *
pCache->cbEntrySize]);
CHECK_READ_N_BYTES_2ENDED(pjData - cbFrag - 3, &(pVariableBytes->arecs[0].byte),
pjDataEnd, cbFrag, hr, (TB,_T("Fragment for ADD begins before data")))
memcpy(pCacheEntryData, pjData - cbFrag - 3, cbFrag);
if (pOrder->ulCharInc == 0) {
if ((pOrder->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) == 0) {
if (pCacheEntryData[1] & 0x80) {
pCacheEntryData[2] = 0;
pCacheEntryData[3] = 0;
}
else {
pCacheEntryData[1] = 0;
}
}
}
}
/********************************************************************/
/* 'Use Fragment' */
/********************************************************************/
else if (*pjData == ORD_INDEX_FRAGMENT_USE) {
PUHFRAGCACHE pCache;
PDCUINT8 pCacheEntryData;
PUHFRAGCACHEENTRYHDR pCacheEntryHdr;
unsigned cbFrag;
pjData++;
CHECK_READ_ONE_BYTE(pjData, pjDataEnd, hr,
( TB, _T("reading glyph data off end")));
cacheIndex = *pjData++;
hr = _pUh->UHIsValidFragmentCacheIndex(cacheIndex);
DC_QUIT_ON_FAIL(hr);
if ((pOrder->ulCharInc == 0) &&
((pOrder->flAccel & SO_CHAR_INC_EQUAL_BM_BASE) == 0)) {
CHECK_READ_ONE_BYTE(pjData, pjDataEnd, hr,
( TB, _T("reading glyph data off end")))
delta = (*(PDCINT8)pjData++);
if (delta & 0x80) {
CHECK_READ_N_BYTES(pjData, pjDataEnd, sizeof(DCINT16), hr,
( TB, _T("reading glyph data off end")))
delta = (*(PDCINT16)pjData);
pjData += sizeof(DCINT16);
}
if (pOrder->flAccel & SO_HORIZONTAL)
x += delta;
else
y += delta;
}
// Get the fragment from the cache.
pCache = &_pUh->_UH.fragCache;
pCacheEntryHdr = &(pCache->pHdr[cacheIndex]);
pCacheEntryData = &(pCache->pData[cacheIndex *
pCache->cbEntrySize]);
if (pCacheEntryHdr->cacheId != pOrder->cacheId) {
TRC_ABORT((TB,_T("Fragment cache id mismatch")));
hr = E_TSC_CORE_CACHEVALUE;
DC_QUIT;
}
cbFrag = (unsigned)pCacheEntryHdr->cbFrag;
if (cbFrag > sizeof(ajFrag)) {
TRC_ABORT(( TB, _T("cbFrag > sizeof (ajFrag)")));
hr = E_TSC_CORE_LENGTH;
DC_QUIT;
}
memcpy(ajFrag, pCacheEntryData, cbFrag);
GHFRAGLEFT(x);
pjFrag = ajFrag;
pjFragEnd = &ajFrag[cbFrag];
while (pjFrag < pjFragEnd) {
hr = pfnMasterType(this, pOrder, iGlyph++, &pjFrag, pjFragEnd, &x, &y,
pjBuffer, pjEndBuffer, BufferOffset, ulBufferWidth, ajUnicode, &dx);
DC_QUIT_ON_FAIL(hr);
}
if (pOrder->flAccel & SO_CHAR_INC_EQUAL_BM_BASE)
GHFRAGRIGHT(x);
else
GHFRAGRIGHT(x+dx);
}
/********************************************************************/
/* Normal glyph out */
/********************************************************************/
else {
int dummy;
/****************************************************************/
/* if we have more than 255 glyphs, we won't get any unicode */
/* beyond 255 glyphs because ajUnicode has length of 256 */
/****************************************************************/
if (iGlyph < 255) {
hr = pfnMasterType(this, pOrder, iGlyph++, &pjData, pjDataEnd, &x, &y,
pjBuffer, pjEndBuffer, BufferOffset, ulBufferWidth, ajUnicode, &dummy);
DC_QUIT_ON_FAIL(hr);
} else {
hr = pfnMasterType(this, pOrder, iGlyph++, &pjData, pjDataEnd, &x, &y,
pjBuffer, pjEndBuffer, BufferOffset, ulBufferWidth, NULL, &dummy);
DC_QUIT_ON_FAIL(hr);
}
}
}
if (iGlyph < 255)
ajUnicode[iGlyph] = 0;
else
ajUnicode[255] = 0;
/************************************************************************/
/* Draw the temp buffer to the output device */
/************************************************************************/
#if defined(OS_WINCE) || defined(OS_WINNT)
/************************************************************************/
// For WinCE, Win9x, and NT use a fast path if possible.
/************************************************************************/
#ifdef USE_GDIPLUS
if (_pUh->_UH.bmShadowBits != NULL &&
_pUh->_UH.protocolBpp == _pUh->_UH.shadowBitmapBpp &&
_pUh->_UH.hdcDraw == _pUh->_UH.hdcShadowBitmap) {
#else // USE_GDIPLUS
if (_pUh->_UH.bmShadowBits != NULL &&
_pUh->_UH.hdcDraw == _pUh->_UH.hdcShadowBitmap) {
#endif // USE_GDIPLUS
INT32 left, right, top, bottom;
UINT32 dx, dy;
if (_pUh->_UH.rectReset) {
left = pOrder->BkLeft;
right = pOrder->BkRight;
top = pOrder->BkTop;
bottom = pOrder->BkBottom;
}
else {
left = DC_MAX(pOrder->BkLeft, _pUh->_UH.lastLeft);
right = DC_MIN(pOrder->BkRight, _pUh->_UH.lastRight + 1);
top = DC_MAX(pOrder->BkTop, _pUh->_UH.lastTop);
bottom = DC_MIN(pOrder->BkBottom, _pUh->_UH.lastBottom + 1);
}
//
// Fix for bug#699321. In case the shadow bitmap is enabled and we will
// use the "performant" functions to copy the glyph fragment into
// the shadow buffer we have to make sure that the dest rect is clipped
// to the screen area. If it is not we might overflow the shadow screen
// buffer. The server should not send us orders that will result in
// the dest rect not being fully contained by the screen area. This is
// purely a security surface reduction fix.
//
if ((left < right) && (top < bottom) &&
(left >= 0) && (right <= (INT32)_pUh->_UH.bmShadowWidth) &&
(top >= 0) && (bottom <= (INT32)_pUh->_UH.bmShadowHeight)) {
#ifdef OS_WINNT
// On NT and Win9x we need to make sure all GDI buffered output
// is flushed out to the offscreen bitmap.
GdiFlush();
#endif
dx = (UINT32)(left - pOrder->BkLeft);
dy = (UINT32)(top - pOrder->BkTop);
if (pOrder->OpTop < pOrder->OpBottom) {
#ifdef DC_HICOLOR
TRC_NRM((TB, _T("Opaque glyph order w %d, h %d, fc %#06lx, bc %#06lx"),
ulBufferWidth, ulHeight, pOrder->ForeColor, pOrder->BackColor));
if (_pUh->_UH.protocolBpp == 24)
{
vSrcOpaqCopyS1D8_24(pjBuffer + dy * ulBufferWidth,
BufferAlign + dx,
ulBufferWidth,
_pUh->_UH.bmShadowBits + top * _pUh->_UH.bmShadowWidth * _pUh->_UH.copyMultiplier,
left,
right,
_pUh->_UH.bmShadowWidth,
bottom - top,
pOrder->BackColor.u.rgb,
pOrder->ForeColor.u.rgb);
}
else if ((_pUh->_UH.protocolBpp == 16) || (_pUh->_UH.protocolBpp == 15))
{
vSrcOpaqCopyS1D8_16(pjBuffer + dy * ulBufferWidth,
BufferAlign + dx,
ulBufferWidth,
_pUh->_UH.bmShadowBits + top * _pUh->_UH.bmShadowWidth * _pUh->_UH.copyMultiplier,
left,
right,
_pUh->_UH.bmShadowWidth,
bottom - top,
*((PDCUINT16)&(pOrder->BackColor)),
*((PDCUINT16)&(pOrder->ForeColor)));
}
else
{
#endif
vSrcOpaqCopyS1D8(pjBuffer + dy * ulBufferWidth, // pointer to beginning of current scan line of src buffer
BufferAlign + dx, // left (starting) pixel in src rectangle
ulBufferWidth, // bytes from one src scan line to next
_pUh->_UH.bmShadowBits + top * _pUh->_UH.bmShadowWidth, // pointer to beginning of current scan line of Dst buffer
left, // left(first) dst pixel
right, // right(last) dst pixel
_pUh->_UH.bmShadowWidth, // bytes from one Dst scan line to next
bottom - top, // number of scan lines
pOrder->BackColor.u.index, // Foreground color
pOrder->ForeColor.u.index); // Background color
#ifdef DC_HICOLOR
}
#endif
}
else {
#ifdef DC_HICOLOR
TRC_NRM((TB, _T("Transparent glyph order w %d, h %d, fc %#06lx, bc %#06lx"),
ulBufferWidth, ulHeight, pOrder->ForeColor, pOrder->BackColor));
if (_pUh->_UH.protocolBpp == 24)
{
vSrcTranCopyS1D8_24(pjBuffer + dy * ulBufferWidth,
BufferAlign + dx,
ulBufferWidth,
_pUh->_UH.bmShadowBits + top * _pUh->_UH.bmShadowWidth * _pUh->_UH.copyMultiplier,
left,
right,
_pUh->_UH.bmShadowWidth,
bottom - top,
pOrder->BackColor.u.rgb);
}
else if ((_pUh->_UH.protocolBpp == 16) || (_pUh->_UH.protocolBpp == 15))
{
vSrcTranCopyS1D8_16(pjBuffer + dy * ulBufferWidth,
BufferAlign + dx,
ulBufferWidth,
_pUh->_UH.bmShadowBits + top * _pUh->_UH.bmShadowWidth * _pUh->_UH.copyMultiplier,
left,
right,
_pUh->_UH.bmShadowWidth,
bottom - top,
*((PDCUINT16)&(pOrder->BackColor)));
}
else
{
#endif
vSrcTranCopyS1D8(pjBuffer + dy * ulBufferWidth,
BufferAlign + dx,
ulBufferWidth,
_pUh->_UH.bmShadowBits + top * _pUh->_UH.bmShadowWidth,
left,
right,
_pUh->_UH.bmShadowWidth,
bottom - top,
pOrder->BackColor.u.index,
pOrder->ForeColor.u.index);
#ifdef DC_HICOLOR
}
#endif
}
} else {
if ((left > right) || (top > bottom)) {
TRC_NRM((TB, _T("Non-ordered glyph paint rect (%d, %d, %d, %d)."),
left, top, right, bottom));
} else if ((left == right) || (top == bottom)) {
TRC_NRM((TB, _T("Zero width/height glyph paint rect (%d, %d, %d, %d)."),
left, top, right, bottom));
} else {
TRC_ERR((TB, _T("Bad glyph paint rect (%d, %d, %d, %d)->(%d, %d)."),
left, top, right, bottom,
_pUh->_UH.bmShadowWidth, _pUh->_UH.bmShadowHeight));
}
}
}
else
#endif // defined(OS_WINCE) || defined(OS_WINNT)
{
#ifdef DC_HICOLOR
TRC_NRM((TB, _T("Slow glyph order w %d, h %d, fc %#06lx, bc %#06lx"),
ulBufferWidth, ulHeight, pOrder->ForeColor, pOrder->BackColor));
#endif
GHSlowOutputBuffer(pOrder, pjBuffer, BufferAlign, ulBufferWidth);
}
// Send the bitmap thru CLX
_pClx->CLX_ClxGlyphOut((UINT)(ulBufferWidth << 3),
(UINT)(pOrder->BkBottom - pOrder->BkTop), pjBuffer);
#ifdef DC_DEBUG
// In debug, hatch the output yellow if the option is turned on.
if (_pUh->_UH.hatchIndexPDUData) {
unsigned i;
for (i = 0; i < g_Fragment; i++)
_pUh->UH_HatchRect((int)(g_FragmentLeft[i]),
(int)pOrder->BkTop,
(int)(g_FragmentRight[i]),
(int)pOrder->BkBottom,
UH_RGB_YELLOW,
UH_BRUSHTYPE_FDIAGONAL);
}
#endif
/************************************************************************/
// Post-process draw fringe rects.
/************************************************************************/
for (i = 0; i < crclFringe; i++) {
if (!PatBlt(_pUh->_UH.hdcDraw,
arclFringe[i].left,
arclFringe[i].top,
(int)(arclFringe[i].right - arclFringe[i].left),
(int)(arclFringe[i].bottom - arclFringe[i].top),
PATCOPY))
{
TRC_ERR((TB, _T("Glyph PatBlt failed")));
}
}
/************************************************************************/
/* Free up any memory we may have allocated for the temp buffer */
/************************************************************************/
if (pjBuffer != szTextBuffer)
UT_Free( _pUt, pjBuffer);
/************************************************************************/
/* Let the clx have a look-see at the unicode text data */
/************************************************************************/
if ( _pUh->_UH.hdcDraw == _pUh->_UH.hdcOffscreenBitmap ) {
_pClx->CLX_ClxTextOut(ajUnicode, iGlyph, _pUh->_UH.hdcDraw,
pOrder->BkLeft, pOrder->BkRight, pOrder->BkTop, pOrder->BkBottom);
}
else {
_pClx->CLX_ClxTextOut(ajUnicode, iGlyph, NULL,
pOrder->BkLeft, pOrder->BkRight, pOrder->BkTop, pOrder->BkBottom);
}
hr = S_OK;
DC_EXIT_POINT:
DC_END_FN();
return hr;
}