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.
 
 
 
 
 
 

719 lines
25 KiB

/******************************Module*Header***********************************\
* Module Name: text.c
*
* Non-cached glyph rendering functions.
*
* Copyright (c) 1994-1998 3Dlabs Inc. Ltd. All rights reserved.
* Copyright (c) 1995-1999 Microsoft Corporation. All rights reserved.
*
\******************************************************************************/
#include "precomp.h"
#include "gdi.h"
// The shift equations are a nuisance. We want x<<32 to be
// zero but some processors only use the bottom 5 bits
// of the shift value. So if we want to shift by n bits
// where we know that n may be 32, we do it in two parts.
// It turns out that in the algorithms below we get either
// (32 <= n < 0) or (32 < n <= 0). We use the macro for
// the first one and a normal shift for the second.
//
#define SHIFT_LEFT(src, n) (((src) << ((n)-1)) << 1)
//------------------------------------------------------------------------------
// FUNC: bClippedText
//
// Renders an array of proportional or monospaced glyphs within a non-trivial
// clip region
//
// ppdev------pointer to physical device object
// pgp--------array of glyphs to render (all members of the pcf font)
// cGlyph-----number of glyphs to render
// ulCharInc--fixed character spacing increment (0 if proportional font)
// pco--------pointer to the clip region object
//
// Returns TRUE if string object rendered
//------------------------------------------------------------------------------
BOOL
bClippedText(PDev* ppdev,
GLYPHPOS* pgp,
LONG cGlyph,
ULONG ulCharInc,
CLIPOBJ* pco)
{
LONG cGlyphOriginal;
GLYPHPOS *pgpOriginal;
GLYPHBITS* pgb;
POINTL ptlOrigin;
BOOL bMore;
ClipEnum ce;
RECTL* prclClip;
LONG cxGlyph;
LONG cyGlyph;
BYTE* pjGlyph;
LONG x;
DWORD renderBits;
LONG unused;
LONG rShift;
ULONG bits;
ULONG bitWord;
ULONG* pBuffer;
ULONG* pBufferEnd;
ULONG* pReservationEnd;
PERMEDIA_DECL;
DBG_GDI((7, "bClippedText: entered for %d glyphs", cGlyph));
ASSERTDD(pco != NULL, "Don't expect NULL clip objects here");
//we'll go through the glyph list for each of the clipping rectangles
cGlyphOriginal = cGlyph;
pgpOriginal = pgp;
renderBits = __RENDER_TRAPEZOID_PRIMITIVE | __RENDER_SYNC_ON_BIT_MASK;
// since we are clipping, assume that we will need the scissor clip. So
// enable user level scissoring here. We disable it just before returning.
//
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagScissorMode;
pBuffer[1] = USER_SCISSOR_ENABLE | SCREEN_SCISSOR_DEFAULT;
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
if (pco->iDComplexity != DC_COMPLEX)
{
// We could call 'cEnumStart' and 'bEnum' when the clipping is
// DC_RECT, but the last time I checked, those two calls took
// more than 150 instructions to go through GDI. Since
// 'rclBounds' already contains the DC_RECT clip rectangle,
// and since it's such a common case, we'll special case it:
DBG_GDI((7, "bClippedText: Enumerating rectangular clip region"));
bMore = FALSE;
prclClip = &pco->rclBounds;
ce.c = 1;
goto SingleRectangle;
}
DBG_GDI((7, "bClippedText: Enumerating complex clip region"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
{
cGlyph = cGlyphOriginal;
pgp = pgpOriginal;
SingleRectangle:
pgb = pgp->pgdf->pgb;
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
// load Permedia2 scissor clip to trap partially clipped glyphs. We still
// check whether a glyph is completely clipped out as an optimisation.
// I suppose that since we construct the bits to download to Permedia2, with
// a bit more work I could do the clipping while downloading the bits.
// But, in the future we will probably cache the packed bits anyway so
// use the scissor. Wait for the first 5 FIFO entries here as well.
//
DBG_GDI((7, "bClippedText: loading scissor clip (%d,%d):(%d,%d)",
prclClip->left, prclClip->top,
prclClip->right, prclClip->bottom));
InputBufferReserve(ppdev, 4, &pBuffer);
pBuffer[0] = __Permedia2TagScissorMinXY;
pBuffer[1] = (prclClip->top << 16) | (prclClip->left);
pBuffer[2] = __Permedia2TagScissorMaxXY;
pBuffer[3] = (prclClip->bottom << 16) | (prclClip->right);
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
// Loop through all the glyphs for this rectangle:
for(;;)
{
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
// reject completely clipped out glyphs
if ((prclClip->right <= ptlOrigin.x) ||
(prclClip->bottom <= ptlOrigin.y) ||
(prclClip->left >= ptlOrigin.x + cxGlyph) ||
(prclClip->top >= ptlOrigin.y + cyGlyph))
{
DBG_GDI((7, "bClippedText: glyph clipped at (%d,%d):(%d,%d)",
ptlOrigin.x, ptlOrigin.y,
ptlOrigin.x + cxGlyph, ptlOrigin.y + cyGlyph));
goto ContinueGlyphs;
}
pjGlyph = pgb->aj;
cyGlyph = pgb->sizlBitmap.cy;
x = ptlOrigin.x;
unused = 32;
bitWord = 0;
DBG_GDI((7, "bClippedText: glyph clipped at (%d,%d):(%d,%d)",
x, ptlOrigin.y, x + cxGlyph, ptlOrigin.y + cyGlyph));
InputBufferReserve(ppdev, 10, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(x);
pBuffer[2] = __Permedia2TagStartXSub;
pBuffer[3] = INTtoFIXED(x + cxGlyph);
pBuffer[4] = __Permedia2TagStartY;
pBuffer[5] = INTtoFIXED(ptlOrigin.y);
pBuffer[6] = __Permedia2TagCount;
pBuffer[7] = cyGlyph;
pBuffer[8] = __Permedia2TagRender;
pBuffer[9] = renderBits;
pBuffer += 10;
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((7, "bClippedText: downloading %d pel wide glyph",
cxGlyph));
InputBufferStart(ppdev, 100, &pBuffer, &pBufferEnd, &pReservationEnd);
if (cxGlyph <= 8)
{
//-----------------------------------------------------
// 1 to 8 pels in width
BYTE *pSrcB;
pSrcB = pjGlyph;
rShift = 8 - cxGlyph;
for(;;)
{
bits = *pSrcB >> rShift;
unused -= cxGlyph;
if (unused > 0)
bitWord |= bits << unused;
else
{
bitWord |= bits >> -unused;
InputBufferContinue(ppdev, 2, &pBuffer, &pBufferEnd,
&pReservationEnd);
pBuffer[0] = __Permedia2TagBitMaskPattern;
pBuffer[1] = bitWord;
pBuffer += 2;
unused += 32;
bitWord = SHIFT_LEFT(bits, unused);
}
if (--cyGlyph == 0)
break;
++pSrcB;
}
}
else if (cxGlyph <= 16)
{
//-----------------------------------------------------
// 9 to 16 pels in width
USHORT *pSrcW;
pSrcW = (USHORT *)pjGlyph;
rShift = 32 - cxGlyph;
for(;;)
{
bits = *pSrcW;
bits = ((bits << 24) | (bits << 8)) >> rShift;
unused -= cxGlyph;
if (unused > 0)
bitWord |= bits << unused;
else
{
bitWord |= bits >> -unused;
InputBufferContinue(ppdev, 2, &pBuffer, &pBufferEnd,
&pReservationEnd);
pBuffer[0] = __Permedia2TagBitMaskPattern;
pBuffer[1] = bitWord;
pBuffer += 2;
unused += 32;
bitWord = SHIFT_LEFT(bits, unused);
}
if (--cyGlyph == 0)
break;
++pSrcW;
}
}
else
{
//-----------------------------------------------------
// More than 16 pels in width
ULONG *pSrcL;
LONG nRight;
LONG nRemainder;
LONG lDelta;
lDelta = (cxGlyph + 7) >> 3;
for(;;)
{
pSrcL = (ULONG*)((INT_PTR)pjGlyph & ~3);
nRight=(LONG)(32-(((INT_PTR)pjGlyph-(INT_PTR)pSrcL) << 3));
LSWAP_BYTES(bits, pSrcL);
bits &= SHIFT_LEFT(1, nRight) - 1;
nRemainder = cxGlyph - nRight;
if (nRemainder < 0)
{
bits >>= -nRemainder;
nRight = cxGlyph;
nRemainder = 0;
}
unused -= nRight;
if (unused > 0)
bitWord |= bits << unused;
else
{
bitWord |= bits >> -unused;
InputBufferContinue(ppdev, 2, &pBuffer, &pBufferEnd,
&pReservationEnd);
pBuffer[0] = __Permedia2TagBitMaskPattern;
pBuffer[1] = bitWord;
pBuffer += 2;
unused += 32;
bitWord = SHIFT_LEFT(bits, unused);
}
while (nRemainder >= 32)
{
++pSrcL;
LSWAP_BYTES(bits, pSrcL);
bitWord |= bits >> (32 - unused);
InputBufferContinue(ppdev, 2, &pBuffer, &pBufferEnd,
&pReservationEnd);
pBuffer[0] = __Permedia2TagBitMaskPattern;
pBuffer[1] = bitWord;
pBuffer += 2;
bitWord = SHIFT_LEFT(bits, unused);
nRemainder -= 32;
}
if (nRemainder > 0)
{
++pSrcL;
LSWAP_BYTES(bits, pSrcL);
bits >>= (32 - nRemainder);
unused -= nRemainder;
if (unused > 0)
bitWord |= bits << unused;
else
{
bitWord |= bits >> -unused;
InputBufferContinue(ppdev, 2, &pBuffer, &pBufferEnd,
&pReservationEnd);
pBuffer[0] = __Permedia2TagBitMaskPattern;
pBuffer[1] = bitWord;
pBuffer += 2;
unused += 32;
bitWord = SHIFT_LEFT(bits, unused);
}
}
if (--cyGlyph == 0)
break;
/* go onto next scanline */
pjGlyph += lDelta;
}
}
// complete the bit download
if (unused < 32)
{
InputBufferContinue(ppdev, 2, &pBuffer, &pBufferEnd,
&pReservationEnd);
pBuffer[0] = __Permedia2TagBitMaskPattern;
pBuffer[1] = bitWord;
pBuffer += 2;
}
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((7, "bClippedText: download completed"));
ContinueGlyphs:
if (--cGlyph == 0)
break;
DBG_GDI((7, "bClippedText: %d still to render", cGlyph));
// Get ready for next glyph:
pgp++;
pgb = pgp->pgdf->pgb;
if (ulCharInc == 0)
{
ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
}
else
{
ptlOrigin.x += ulCharInc;
}
}
}
} while (bMore);
// reset the scissor. default is the whole of VRAM.
DBG_GDI((20, "bClippedText: resetting scissor clip"));
InputBufferReserve(ppdev, 2, &pBuffer);
pBuffer[0] = __Permedia2TagScissorMode;
pBuffer[1] = SCREEN_SCISSOR_DEFAULT;
pBuffer += 2;
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((7, "bClippedText: exited"));
return(TRUE);
}
//------------------------------------------------------------------------------
// FUNC: bClippedAAText
//
// Renders an array of proportional or monospaced anti-aliassed glyphs within
// a non-trivial clip region
//
// ppdev------pointer to physical device object
// pgp--------array of glyphs to render (all members of the pcf font)
// cGlyph-----number of glyphs to render
// ulCharInc--fixed character spacing increment (0 if proportional font)
// pco--------pointer to the clip region object
//
// Returns TRUE if string object rendered
//------------------------------------------------------------------------------
BOOL
bClippedAAText(PDev* ppdev,
GLYPHPOS* pgp,
LONG cGlyph,
ULONG ulCharInc,
CLIPOBJ* pco)
{
LONG cGlyphOriginal;
GLYPHPOS *pgpOriginal;
GLYPHBITS* pgb;
POINTL ptlOrigin;
BOOL bMore;
ClipEnum ce;
RECTL* prclClip;
LONG cxGlyph;
LONG cyGlyph;
BYTE* pjGlyph;
LONG x;
DWORD renderBits;
LONG unused;
LONG rShift;
ULONG bits;
ULONG bitWord;
ULONG* pBuffer;
ULONG* pBufferEnd;
ULONG* pReservationEnd;
PERMEDIA_DECL;
DBG_GDI((7, "bClippedAAText: entered for %d glyphs", cGlyph));
ASSERTDD(pco != NULL, "Don't expect NULL clip objects here");
//we'll go through the glyph list for each of the clipping rectangles
cGlyphOriginal = cGlyph;
pgpOriginal = pgp;
renderBits = __RENDER_TRAPEZOID_PRIMITIVE |
__RENDER_TEXTURED_PRIMITIVE |
__RENDER_SYNC_ON_HOST_DATA;
// since we are clipping, assume that we will need the scissor clip. So
// enable user level scissoring here. We disable it just before returning.
//
InputBufferReserve(ppdev, 14, &pBuffer);
pBuffer[0] = __Permedia2TagScissorMode;
pBuffer[1] = USER_SCISSOR_ENABLE | SCREEN_SCISSOR_DEFAULT;
pBuffer[2] = __Permedia2TagDitherMode;
pBuffer[3] = (COLOR_MODE << PM_DITHERMODE_COLORORDER) |
(ppdev->ulPermFormat << PM_DITHERMODE_COLORFORMAT) |
(ppdev->ulPermFormatEx << PM_DITHERMODE_COLORFORMATEXTENSION) |
(1 << PM_DITHERMODE_ENABLE);
pBuffer[4] = __Permedia2TagAlphaBlendMode;
pBuffer[5] = (0 << PM_ALPHABLENDMODE_BLENDTYPE) | // RGB
(1 << PM_ALPHABLENDMODE_COLORORDER) | // RGB
(1 << PM_ALPHABLENDMODE_ENABLE) |
(1 << PM_ALPHABLENDMODE_ENABLE) |
(84 << PM_ALPHABLENDMODE_OPERATION) | // PreMult
(ppdev->ulPermFormat << PM_ALPHABLENDMODE_COLORFORMAT) |
(ppdev->ulPermFormatEx << PM_ALPHABLENDMODE_COLORFORMATEXTENSION);
pBuffer[6] = __Permedia2TagLogicalOpMode;
pBuffer[7] = __PERMEDIA_DISABLE;
pBuffer[8] = __Permedia2TagTextureColorMode;
pBuffer[9] = (1 << PM_TEXCOLORMODE_ENABLE) |
(0 << 4) | // RGB
(0 << 1); // Modulate
pBuffer[10] = __Permedia2TagTextureDataFormat;
pBuffer[11] = (ppdev->ulPermFormat << PM_TEXDATAFORMAT_FORMAT) |
(ppdev->ulPermFormatEx << PM_TEXDATAFORMAT_FORMATEXTENSION) |
(COLOR_MODE << PM_TEXDATAFORMAT_COLORORDER);
pBuffer[12] = __Permedia2TagColorDDAMode;
pBuffer[13] = 1;
pBuffer += 14;
InputBufferCommit(ppdev, pBuffer);
if (pco->iDComplexity != DC_COMPLEX)
{
// We could call 'cEnumStart' and 'bEnum' when the clipping is
// DC_RECT, but the last time I checked, those two calls took
// more than 150 instructions to go through GDI. Since
// 'rclBounds' already contains the DC_RECT clip rectangle,
// and since it's such a common case, we'll special case it:
DBG_GDI((7, "bClippedText: Enumerating rectangular clip region"));
bMore = FALSE;
prclClip = &pco->rclBounds;
ce.c = 1;
goto SingleRectangle;
}
DBG_GDI((7, "bClippedAAText: Enumerating complex clip region"));
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do
{
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
for (prclClip = &ce.arcl[0]; ce.c != 0; ce.c--, prclClip++)
{
cGlyph = cGlyphOriginal;
pgp = pgpOriginal;
SingleRectangle:
pgb = pgp->pgdf->pgb;
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
// load Permedia2 scissor clip to trap partially clipped glyphs. We still
// check whether a glyph is completely clipped out as an optimisation.
// I suppose that since we construct the bits to download to Permedia2, with
// a bit more work I could do the clipping while downloading the bits.
// But, in the future we will probably cache the packed bits anyway so
// use the scissor. Wait for the first 5 FIFO entries here as well.
//
DBG_GDI((7, "bClippedAAText: loading scissor clip (%d,%d):(%d,%d)",
prclClip->left, prclClip->top,
prclClip->right, prclClip->bottom));
InputBufferReserve(ppdev, 4, &pBuffer);
pBuffer[0] = __Permedia2TagScissorMinXY;
pBuffer[1] = (prclClip->top << 16) | (prclClip->left);
pBuffer[2] = __Permedia2TagScissorMaxXY;
pBuffer[3] = (prclClip->bottom << 16) | (prclClip->right);
pBuffer += 4;
InputBufferCommit(ppdev, pBuffer);
// Loop through all the glyphs for this rectangle:
for(;;)
{
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
// reject completely clipped out glyphs
if ((prclClip->right <= ptlOrigin.x) ||
(prclClip->bottom <= ptlOrigin.y) ||
(prclClip->left >= ptlOrigin.x + cxGlyph) ||
(prclClip->top >= ptlOrigin.y + cyGlyph))
{
DBG_GDI((7, "bClippedAAText: glyph clipped at (%d,%d):(%d,%d)",
ptlOrigin.x, ptlOrigin.y,
ptlOrigin.x + cxGlyph, ptlOrigin.y + cyGlyph));
goto ContinueGlyphs;
}
pjGlyph = pgb->aj;
cyGlyph = pgb->sizlBitmap.cy;
x = ptlOrigin.x;
unused = 32;
bitWord = 0;
DBG_GDI((7, "bClippedAAText: glyph clipped at (%d,%d):(%d,%d)",
x, ptlOrigin.y, x + cxGlyph, ptlOrigin.y + cyGlyph));
InputBufferReserve(ppdev, 12, &pBuffer);
pBuffer[0] = __Permedia2TagStartXDom;
pBuffer[1] = INTtoFIXED(x);
pBuffer[2] = __Permedia2TagStartXSub;
pBuffer[3] = INTtoFIXED(x + cxGlyph);
pBuffer[4] = __Permedia2TagStartY;
pBuffer[5] = INTtoFIXED(ptlOrigin.y);
pBuffer[6] = __Permedia2TagdY;
pBuffer[7] = 1 << 16;
pBuffer[8] = __Permedia2TagCount;
pBuffer[9] = cyGlyph;
pBuffer[10] = __Permedia2TagRender;
pBuffer[11] = renderBits;
pBuffer += 12;
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((7, "bClippedAAText: downloading %d pel wide glyph",
cxGlyph));
while(cyGlyph--)
{
InputBufferReserve(ppdev, cxGlyph + 1, &pBuffer);
*pBuffer++ = ((cxGlyph - 1) << 16) | __Permedia2TagTexel0;
x = 0;
while (x++ < cxGlyph)
{
ULONG pixels = *pjGlyph++;
ULONG alpha = pixels & 0xf0;
alpha |= alpha >> 4;
ULONG pixel;
pixel = (alpha << 24) | 0xffffff;
*pBuffer++ = pixel;
if(x++ < cxGlyph)
{
alpha = pixels & 0xf;
alpha |= alpha << 4;
pixel = (alpha << 24) | 0xffffff;
*pBuffer++ = pixel;
}
}
InputBufferCommit(ppdev, pBuffer);
}
DBG_GDI((7, "bClippedAAText: download completed"));
ContinueGlyphs:
if (--cGlyph == 0)
break;
DBG_GDI((7, "bClippedAAText: %d still to render", cGlyph));
// Get ready for next glyph:
pgp++;
pgb = pgp->pgdf->pgb;
if (ulCharInc == 0)
{
ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
}
else
{
ptlOrigin.x += ulCharInc;
}
}
}
} while (bMore);
// reset the scissor. default is the whole of VRAM.
DBG_GDI((20, "bClippedAAText: resetting scissor clip"));
InputBufferReserve(ppdev, 10, &pBuffer);
pBuffer[0] = __Permedia2TagScissorMode;
pBuffer[1] = SCREEN_SCISSOR_DEFAULT;
pBuffer[2] = __Permedia2TagDitherMode;
pBuffer[3] = __PERMEDIA_DISABLE;
pBuffer[4] = __Permedia2TagAlphaBlendMode;
pBuffer[5] = __PERMEDIA_DISABLE;
pBuffer[6] = __Permedia2TagTextureColorMode;
pBuffer[7] = __PERMEDIA_DISABLE;
pBuffer[8] = __Permedia2TagColorDDAMode;
pBuffer[9] = __PERMEDIA_DISABLE;
pBuffer += 10;
InputBufferCommit(ppdev, pBuffer);
DBG_GDI((7, "bClippedText: exited"));
return(TRUE);
}