|
|
/******************************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); }
|