Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

4159 lines
118 KiB

/******************************Module*Header*******************************\
* Module Name: textout.c
*
* Copyright (c) 1992-1995 Microsoft Corporation
*
\**************************************************************************/
#include "precomp.h"
BYTE gajBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
// Converts bit index to set bit
/******************************Public*Routine******************************\
* VOID vClipSolid
*
* Fills the specified rectangle with the specified colour, honouring
* the requested clipping.
*
\**************************************************************************/
VOID vClipSolid(
PDEV* ppdev,
RECTL* prcl,
ULONG iColor,
CLIPOBJ* pco)
{
BOOL bMore; // Flag for clip enumeration
CLIPENUM ce; // Clip enumeration object
LONG c; // Count of non-empty rectangles
RBRUSH_COLOR rbc; // For passing colour to vFillSolid
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
// Scan through all the clip rectangles, looking for intersects
// of fill areas with region rectangles:
rbc.iSolidColor = iColor;
do {
// Get a batch of region rectangles:
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*) &ce);
c = cIntersect(prcl, ce.arcl, ce.c);
if (c != 0)
ppdev->pfnFillSolid(ppdev, c, ce.arcl, 0xf0f0, rbc, NULL);
} while (bMore);
}
/******************************Public*Routine******************************\
* CACHEDFONT* pcfAllocateCachedFont()
*
* Initializes our font data structure.
*
\**************************************************************************/
CACHEDFONT* pcfAllocateCachedFont(
PDEV* ppdev)
{
CACHEDFONT* pcf;
CACHEDGLYPH** ppcg;
LONG i;
pcf = AtiAllocMem(LPTR, FL_ZERO_MEMORY, sizeof(CACHEDFONT));
if (pcf != NULL)
{
// Note that we rely on FL_ZERO_MEMORY to zero 'pgaChain' and
// 'cjAlloc':
pcf->cgSentinel.hg = HGLYPH_SENTINEL;
// Initialize the hash table entries to all point to our sentinel:
for (ppcg = &pcf->apcg[0], i = GLYPH_HASH_SIZE; i != 0; i--, ppcg++)
{
*ppcg = &pcf->cgSentinel;
}
}
return(pcf);
}
/******************************Public*Routine******************************\
* VOID vFreeCachedFont()
*
* Frees all memory associated with the cache we kept for this font.
*
\**************************************************************************/
VOID vFreeCachedFont(
CACHEDFONT* pcf)
{
GLYPHALLOC* pga;
GLYPHALLOC* pgaNext;
pga = pcf->pgaChain;
while (pga != NULL)
{
pgaNext = pga->pgaNext;
AtiFreeMem(pga);
pga = pgaNext;
}
AtiFreeMem(pcf);
}
/******************************Public*Routine******************************\
* VOID vTrimAndPackGlyph
*
\**************************************************************************/
// expandto3 - expand one (monochrome) byte to three (24bpp) bytes, while
// flipping the bits backwards.
#define expandto3(a,b) \
{ \
if ((a) & 0x80) *(b) |= 0x07; \
if ((a) & 0x40) *(b) |= 0x38; \
if ((a) & 0x20) {*(b) |= 0xC0; *((b)+1) |= 0x01;} \
if ((a) & 0x10) *((b)+1) |= 0x0E; \
if ((a) & 0x08) *((b)+1) |= 0x70; \
if ((a) & 0x04) {*((b)+1) |= 0x80; *((b)+2) |= 0x03;} \
if ((a) & 0x02) *((b)+2) |= 0x1C; \
if ((a) & 0x01) *((b)+2) |= 0xE0; \
}
VOID vTrimAndPackGlyph(
PDEV* ppdev,
BYTE* pjBuf, // Note: Routine may touch preceding byte!
BYTE* pjGlyph,
LONG* pcxGlyph,
LONG* pcyGlyph,
POINTL* pptlOrigin)
{
LONG cxGlyph;
LONG cyGlyph;
POINTL ptlOrigin;
LONG cAlign;
LONG lDelta;
BYTE* pj;
BYTE jBit;
LONG cjSrcWidth;
LONG lSrcSkip;
LONG lDstSkip;
LONG cRem;
BYTE* pjSrc;
BYTE* pjDst;
LONG i;
LONG j;
BYTE jSrc;
///////////////////////////////////////////////////////////////
// Trim the glyph
cyGlyph = *pcyGlyph;
cxGlyph = *pcxGlyph;
ptlOrigin = *pptlOrigin;
cAlign = 0;
lDelta = (cxGlyph + 7) >> 3;
// Trim off any zero rows at the bottom of the glyph:
pj = pjGlyph + cyGlyph * lDelta; // One past last byte in glyph
while (cyGlyph > 0)
{
i = lDelta;
do {
if (*(--pj) != 0)
goto Done_Bottom_Trim;
} while (--i != 0);
// The entire last row has no lit pixels, so simply skip it:
cyGlyph--;
}
ASSERTDD(cyGlyph == 0, "cyGlyph should only be zero here");
// We found a space character. Set both dimensions to zero, so
// that it's easy to special-case later:
cxGlyph = 0;
Done_Bottom_Trim:
// If cxGlyph != 0, we know that the glyph has at least one non-zero
// row and column. By exploiting this knowledge, we can simplify our
// end-of-loop tests, because we don't have to check to see if we've
// decremented either 'cyGlyph' or 'cxGlyph' to zero:
if (cxGlyph != 0)
{
// Trim off any zero rows at the top of the glyph:
pj = pjGlyph; // First byte in glyph
while (TRUE)
{
i = lDelta;
do {
if (*(pj++) != 0)
goto Done_Top_Trim;
} while (--i != 0);
// The entire first row has no lit pixels, so simply skip it:
cyGlyph--;
ptlOrigin.y++;
pjGlyph = pj;
}
Done_Top_Trim:
// Trim off any zero columns at the right edge of the glyph:
while (TRUE)
{
j = cxGlyph - 1;
pj = pjGlyph + (j >> 3); // Last byte in first row of glyph
jBit = gajBit[j & 0x7];
i = cyGlyph;
do {
if ((*pj & jBit) != 0)
goto Done_Right_Trim;
pj += lDelta;
} while (--i != 0);
// The entire last column has no lit pixels, so simply skip it:
cxGlyph--;
}
Done_Right_Trim:
// Trim off any zero columns at the left edge of the glyph:
while (TRUE)
{
pj = pjGlyph; // First byte in first row of glyph
jBit = gajBit[cAlign];
i = cyGlyph;
do {
if ((*pj & jBit) != 0)
goto Done_Left_Trim;
pj += lDelta;
} while (--i != 0);
// The entire first column has no lit pixels, so simply skip it:
ptlOrigin.x++;
cxGlyph--;
cAlign++;
if (cAlign >= 8)
{
cAlign = 0;
pjGlyph++;
}
}
}
Done_Left_Trim:
///////////////////////////////////////////////////////////////
// Pack the glyph
//
// N.B.: The glyph bits are packed in pjBuf backwards.
// Failure to understand this cost me nearly a week's effort,
// and gave me a whopping migraine. (This was for 24bpp.)
if (ppdev->iBitmapFormat != BMF_24BPP)
{
cjSrcWidth = (cxGlyph + cAlign + 7) >> 3;
lSrcSkip = lDelta - cjSrcWidth;
lDstSkip = ((cxGlyph + 7) >> 3) - cjSrcWidth - 1;
cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
pjSrc = pjGlyph;
pjDst = pjBuf;
// Zero the buffer, because we're going to 'or' stuff into it:
memset(pjBuf, 0, (cxGlyph * cyGlyph + 7) >> 3);
// cAlign used to indicate which bit in the first byte of the unpacked
// glyph was the first non-zero pixel column. Now, we flip it to
// indicate which bit in the packed byte will receive the next non-zero
// glyph bit:
cAlign = (-cAlign) & 0x7;
if (cAlign > 0)
{
// It would be bad if our trimming calculations were wrong, because
// we assume any bits to the left of the 'cAlign' bit will be zero.
// As a result of this decrement, we will 'or' those zero bits into
// whatever byte precedes the glyph bits array:
pjDst--;
ASSERTDD((*pjSrc >> cAlign) == 0, "Trimmed off too many bits");
}
for (i = cyGlyph; i != 0; i--)
{
for (j = cjSrcWidth; j != 0; j--)
{
// Note that we may modify a byte past the end of our
// destination buffer, which is why we reserved an
// extra byte:
jSrc = *pjSrc;
*(pjDst) |= (jSrc >> (cAlign));
*(pjDst + 1) |= (jSrc << (8 - cAlign));
pjSrc++;
pjDst++;
}
pjSrc += lSrcSkip;
pjDst += lDstSkip;
cAlign += cRem;
if (cAlign >= 8)
{
cAlign -= 8;
pjDst++;
}
}
}
else
{
BYTE cur_byte, last_byte, last_byte2, next_byte;
cjSrcWidth = (cxGlyph + cAlign + 7) >> 3;
lSrcSkip = lDelta - cjSrcWidth;
lDstSkip = (((cxGlyph + 7) >> 3) - cjSrcWidth - 1) * 3;
cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
pjSrc = pjGlyph;
pjDst = pjBuf;
// Zero the buffer, because we're going to 'or' stuff into it:
memset(pjBuf, 0, (3 * cxGlyph * cyGlyph + 7) >> 3);
// cAlign used to indicate which bit in the first byte of the unpacked
// glyph was the first non-zero pixel column. Now, we flip it to
// indicate which bit in the packed byte will receive the next non-zero
// glyph bit:
cAlign = (-cAlign) & 0x7;
if (cAlign > 0)
{
// It would be bad if our trimming calculations were wrong, because
// we assume any bits to the left of the 'cAlign' bit will be zero.
// As a result of this decrement, we will 'or' those zero bits into
// whatever bytes precedes the glyph bits array:
pjDst -= 3;
ASSERTDD((*pjSrc >> cAlign) == 0, "Trimmed off too many bits");
}
cur_byte = last_byte = 0;
for (i = cyGlyph; i != 0; i--)
{
for (j = cjSrcWidth; j != 0; j--)
{
// Note that we may modify a byte past the end of our
// destination buffer, which is why we reserved an
// extra three bytes:
jSrc = *pjSrc;
cur_byte |= (jSrc >> (cAlign));
expandto3(cur_byte, pjDst);
next_byte = (jSrc << (8 - cAlign));
expandto3(next_byte, pjDst+3);
pjSrc++;
pjDst += 3;
last_byte2 = last_byte;
last_byte = cur_byte;
cur_byte = next_byte;
}
pjSrc += lSrcSkip;
pjDst += lDstSkip; // can be -3 or -6 (if cAlign is big enough) !!
cAlign += cRem;
cur_byte = (lDstSkip != -3)? last_byte2:last_byte;
if (cAlign >= 8)
{
cAlign -= 8;
pjDst += 3;
cur_byte = (lDstSkip != -3)? last_byte:next_byte;
}
}
cxGlyph *= 3;
}
///////////////////////////////////////////////////////////////
// Return results
*pcxGlyph = cxGlyph;
*pcyGlyph = cyGlyph;
*pptlOrigin = ptlOrigin;
}
/******************************Public*Routine******************************\
* VOID vPutGlyphInCache
*
* Figures out where to be a glyph in off-screen memory, copies it
* there, and fills in any other data we'll need to display the glyph.
*
* This routine is rather device-specific, and will have to be extensively
* modified for other display adapters.
*
* Returns TRUE if successful; FALSE if there wasn't enough room in
* off-screen memory.
*
\**************************************************************************/
VOID vPutGlyphInCache(
PDEV* ppdev,
CACHEDGLYPH* pcg,
GLYPHBITS* pgb)
{
BYTE* pjGlyph;
LONG cxGlyph;
LONG cyGlyph;
POINTL ptlOrigin;
pjGlyph = pgb->aj;
cyGlyph = pgb->sizlBitmap.cy;
cxGlyph = pgb->sizlBitmap.cx;
ptlOrigin = pgb->ptlOrigin;
vTrimAndPackGlyph(ppdev, (BYTE*) &pcg->ad, pjGlyph, &cxGlyph, &cyGlyph, &ptlOrigin);
///////////////////////////////////////////////////////////////
// Initialize the glyph fields
pcg->ptlOrigin = ptlOrigin;
pcg->cx = cxGlyph;
pcg->cy = cyGlyph;
pcg->cxy = pcg->cy | (pcg->cx << 16);
pcg->cw = (cxGlyph * cyGlyph + 15) >> 4;
pcg->cd = (pcg->cw + 1) >> 1;
}
/******************************Public*Routine******************************\
* CACHEDGLYPH* pcgNew()
*
* Creates a new CACHEDGLYPH structure for keeping track of the glyph in
* off-screen memory. bPutGlyphInCache is called to actually put the glyph
* in off-screen memory.
*
* This routine should be reasonably device-independent, as bPutGlyphInCache
* will contain most of the code that will have to be modified for other
* display adapters.
*
\**************************************************************************/
CACHEDGLYPH* pcgNew(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp)
{
GLYPHBITS* pgb;
GLYPHALLOC* pga;
CACHEDGLYPH* pcg;
LONG cjCachedGlyph;
HGLYPH hg;
LONG iHash;
CACHEDGLYPH* pcgFind;
// First, calculate the amount of storage we'll need for this glyph:
pgb = pgp->pgdf->pgb;
if (ppdev->iBitmapFormat != BMF_24BPP)
{
cjCachedGlyph = sizeof(CACHEDGLYPH)
+ ((pgb->sizlBitmap.cx * pgb->sizlBitmap.cy + 7) >> 3);
// Reserve an extra byte at the end for temporary usage by our pack
// routine:
cjCachedGlyph++;
}
else
{
cjCachedGlyph = sizeof(CACHEDGLYPH)
+ ((3 * pgb->sizlBitmap.cx * pgb->sizlBitmap.cy + 7) >> 3);
// Reserve 3 extra bytes at the end for temporary usage by our pack
// routine:
cjCachedGlyph += 3;
}
// We need to dword align it too:
cjCachedGlyph = (cjCachedGlyph + 3) & ~3L;
if (cjCachedGlyph > pcf->cjAlloc)
{
// Have to allocate a new glyph allocation structure:
pga = AtiAllocMem(LPTR, FL_ZERO_MEMORY, GLYPH_ALLOC_SIZE);
if (pga == NULL)
{
// It's safe to return at this time because we haven't
// fatally altered any of our data structures:
return(NULL);
}
// Add this allocation to the front of the allocation linked list,
// so that we can free it later:
pga->pgaNext = pcf->pgaChain;
pcf->pgaChain = pga;
// Now we've got a chunk of memory where we can store our cached
// glyphs:
pcf->pcgNew = &pga->acg[0];
pcf->cjAlloc = GLYPH_ALLOC_SIZE - (sizeof(*pga) - sizeof(pga->acg[0]));
// It would be bad if we let in any glyphs that would be bigger
// than our basic allocation size:
ASSERTDD(cjCachedGlyph <= GLYPH_ALLOC_SIZE, "Woah, this is one big glyph!");
}
pcg = pcf->pcgNew;
// We only need to ensure 'dword' alignment of the next structure:
pcf->pcgNew = (CACHEDGLYPH*) ((BYTE*) pcg + cjCachedGlyph);
pcf->cjAlloc -= cjCachedGlyph;
///////////////////////////////////////////////////////////////
// Insert the glyph, in-order, into the list hanging off our hash
// bucket:
hg = pgp->hg;
pcg->hg = hg;
iHash = GLYPH_HASH_FUNC(hg);
pcgFind = pcf->apcg[iHash];
if (pcgFind->hg > hg)
{
pcf->apcg[iHash] = pcg;
pcg->pcgNext = pcgFind;
}
else
{
// The sentinel will ensure that we never fall off the end of
// this list:
while (pcgFind->pcgNext->hg < hg)
pcgFind = pcgFind->pcgNext;
// 'pcgFind' now points to the entry to the entry after which
// we want to insert our new node:
pcg->pcgNext = pcgFind->pcgNext;
pcgFind->pcgNext = pcg;
}
vPutGlyphInCache(ppdev, pcg, pgp->pgdf->pgb);
return(pcg);
}
/******************************Public*Routine******************************\
* BOOL bI32CachedProportionalText
*
* Draws proportionally spaced glyphs via glyph caching.
*
\**************************************************************************/
BOOL bI32CachedProportionalText(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph)
{
BYTE* pjIoBase;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG xOffset;
LONG yOffset;
LONG x;
LONG y;
LONG cw;
WORD* pw;
pjIoBase = ppdev->pjIoBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
// The glyph's origin y-coordinate may often be negative, so we
// can't compute this as follows:
//
// x = pgp->ptl.x + pcg->ptlOrigin.x;
// y = pgp->ptl.y + pcg->ptlOrigin.y;
ASSERTDD((pgp->ptl.y + pcg->ptlOrigin.y) >= 0,
"Can't have negative 'y' coordinates here");
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 5);
x = xOffset + pgp->ptl.x + pcg->ptlOrigin.x;
I32_OW(pjIoBase, CUR_X, x);
I32_OW(pjIoBase, DEST_X_START, x);
I32_OW(pjIoBase, DEST_X_END, x + pcg->cx);
y = yOffset + pgp->ptl.y + pcg->ptlOrigin.y;
I32_OW(pjIoBase, CUR_Y, y);
I32_OW(pjIoBase, DEST_Y_END, y + pcg->cy);
// Take advantage of wait-stated I/O:
pw = (WORD*) &pcg->ad[0];
cw = pcg->cw;
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 10);
do {
I32_OW_DIRECT(pjIoBase, PIX_TRANS, *pw);
} while (pw++, --cw != 0);
}
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bI32CachedFixedText
*
* Draws fixed spaced glyphs via glyph caching.
*
\*************************************************************************/
BOOL bI32CachedFixedText(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph,
ULONG ulCharInc)
{
BYTE* pjIoBase;
LONG xGlyph;
LONG yGlyph;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG x;
LONG y;
WORD* pw;
LONG cw;
pjIoBase = ppdev->pjIoBase;
// Convert to absolute coordinates:
xGlyph = pgp->ptl.x + ppdev->xOffset;
yGlyph = pgp->ptl.y + ppdev->yOffset;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
x = xGlyph + pcg->ptlOrigin.x;
y = yGlyph + pcg->ptlOrigin.y;
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 5);
I32_OW(pjIoBase, CUR_X, x);
I32_OW(pjIoBase, DEST_X_START, x);
I32_OW(pjIoBase, DEST_X_END, x + pcg->cx);
I32_OW(pjIoBase, CUR_Y, y);
I32_OW(pjIoBase, DEST_Y_END, y + pcg->cy);
// Take advantage of wait-stated I/O:
pw = (WORD*) &pcg->ad[0];
cw = pcg->cw;
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 10);
do {
I32_OW_DIRECT(pjIoBase, PIX_TRANS, *pw);
} while (pw++, --cw != 0);
}
xGlyph += ulCharInc;
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bI32CachedClippedText
*
* Draws clipped text via glyph caching.
*
\**************************************************************************/
BOOL bI32CachedClippedText(
PDEV* ppdev,
CACHEDFONT* pcf,
STROBJ* pstro,
CLIPOBJ* pco)
{
BOOL bRet;
BYTE* pjIoBase;
LONG xOffset;
LONG yOffset;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
BOOL bClippingSet;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
LONG xGlyph;
LONG yGlyph;
LONG x;
LONG y;
LONG xRight;
LONG yBottom;
LONG cy;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
HGLYPH hg;
CACHEDGLYPH* pcg;
WORD* pw;
LONG cw;
ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
"Don't expect trivial clipping in this function");
bRet = TRUE;
pjIoBase = ppdev->pjIoBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
ulCharInc = pstro->ulCharInc;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
if (pco->iDComplexity == DC_RECT)
{
// 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:
bMore = FALSE;
ce.c = 1;
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
// We don't always simply set the clipping rectangle here
// because it may actually end up that no text intersects
// this clip rectangle, so it would be for naught. This
// actually happens a lot when using NT's analog clock set
// to always-on-top, with a round shape:
bClippingSet = FALSE;
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
// We can't yet convert to absolute coordinates by adding
// in 'xOffset' or 'yOffset' here because we have yet to
// compare the coordinates to 'prclClip':
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg)
pcg = pcg->pcgNext;
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
{
bRet = FALSE;
goto AllDone;
}
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
cy = pcg->cy;
if (cy != 0)
{
y = pcg->ptlOrigin.y + yGlyph;
x = pcg->ptlOrigin.x + xGlyph;
xRight = pcg->cx + x;
yBottom = pcg->cy + y;
// Do trivial rejection:
if ((prclClip->right > x) &&
(prclClip->bottom > y) &&
(prclClip->left < xRight) &&
(prclClip->top < yBottom))
{
// Lazily set the hardware clipping:
if (!bClippingSet)
{
bClippingSet = TRUE;
vSetClipping(ppdev, prclClip);
}
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 5);
I32_OW(pjIoBase, CUR_X, xOffset + x);
I32_OW(pjIoBase, DEST_X_START, xOffset + x);
I32_OW(pjIoBase, DEST_X_END, xOffset + xRight);
I32_OW(pjIoBase, CUR_Y, yOffset + y);
I32_OW(pjIoBase, DEST_Y_END, yOffset + yBottom);
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 10);
pw = (WORD*) &pcg->ad[0];
cw = pcg->cw;
do {
I32_OW_DIRECT(pjIoBase, PIX_TRANS, *pw);
} while (pw++, --cw != 0);
}
}
if (--cGlyph == 0)
break;
// Get ready for next glyph:
pgp++;
if (ulCharInc == 0)
{
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
}
else
{
xGlyph += ulCharInc;
}
}
}
} while (bMore);
}
} while (bMoreGlyphs);
AllDone:
vResetClipping(ppdev);
return(bRet);
}
VOID vI32DataPortOutB(PDEV *ppdev, PBYTE pb, UINT count)
{
BYTE *pjIoBase = ppdev->pjIoBase;
UINT i;
for (i=0; i < count; i++)
{
if (i % 8 == 0)
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 10);
I32_OB(pjIoBase, PIX_TRANS + 1, *((PUCHAR)pb)++);
}
}
/******************************Public*Routine******************************\
* BOOL bI32GeneralText
*
\**************************************************************************/
BOOL bI32GeneralText(
PDEV* ppdev,
STROBJ* pstro,
CLIPOBJ* pco)
{
BYTE* pjIoBase;
BYTE iDComplexity;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
GLYPHBITS* pgb;
POINTL ptlOrigin;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
LONG cxGlyph;
LONG cyGlyph;
LONG xBiasL = 0;
LONG xBiasR = 0;
LONG yBiasT = 0;
LONG cy = 0;
LONG cx = 0;
BYTE* pjGlyph;
LONG xLeft;
LONG yTop;
LONG xRight;
LONG yBottom;
RECTL NoClip;
LONG x;
LONG y;
pjIoBase = ppdev->pjIoBase;
/* Define Default Clipping area to be full video ram */
NoClip.top = 0;
NoClip.left = 0;
NoClip.right = ppdev->cxScreen;
NoClip.bottom = ppdev->cyScreen;
if (pco == NULL)
iDComplexity = DC_TRIVIAL;
else
iDComplexity = pco->iDComplexity;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
ulCharInc = pstro->ulCharInc;
if (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:
bMore = FALSE;
ce.c = 1;
if (iDComplexity == DC_TRIVIAL)
prclClip = &NoClip;
else
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
pgb = pgp->pgdf->pgb;
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
vSetClipping(ppdev, prclClip);
//ppdev->lRightScissor = rclRealClip.right; ???
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
pjGlyph = (BYTE*) pgb->aj;
if ((prclClip->left <= ptlOrigin.x) &&
(prclClip->top <= ptlOrigin.y) &&
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
{
//-----------------------------------------------------
// Unclipped glyph
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 6);
x = ppdev->xOffset + ptlOrigin.x;
I32_OW(pjIoBase, CUR_X, LOWORD(x));
I32_OW(pjIoBase, DEST_X_START, LOWORD(x));
I32_OW(pjIoBase, DEST_X_END, LOWORD(x) + ROUND8(cxGlyph) );
I32_OW(pjIoBase, SCISSOR_R, LOWORD(x) + cxGlyph-1);
y = ppdev->yOffset + ptlOrigin.y;
I32_OW(pjIoBase, CUR_Y, LOWORD(y));
I32_OW(pjIoBase, DEST_Y_END, (LOWORD(y) + cyGlyph));
vI32DataPortOutB(ppdev, pjGlyph, (ROUND8(cxGlyph) * cyGlyph) >> 3);
/*
_vBlit_DSC_SH1UP(ppdev,ptlOrigin.x, ptlOrigin.y,
cxGlyph, cyGlyph, pjGlyph,
(ROUND8(cxGlyph) * cyGlyph) >> 3);
*/
}
else
{
//-----------------------------------------------------
// Clipped glyph
// Find the intersection of the glyph rectangle
// and the clip rectangle:
xLeft = max(prclClip->left, ptlOrigin.x);
yTop = max(prclClip->top, ptlOrigin.y);
xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
// Check for trivial rejection:
if ( ( ptlOrigin.x <= prclClip->left ) &&
(ppdev->pModeInfo->ModeFlags & AMI_TEXTBAND) )
{
vResetClipping(ppdev);
return FALSE;
}
if (((cx = xRight - xLeft) > 0) &&
((cy = yBottom - yTop) > 0))
{
/* Do software clipping */
/* Calculated the Bias in pixels */
yBiasT = (yTop - ptlOrigin.y);
/* change address of pjGlyph to point +yBiasT
scan lines into the Glyph */
pjGlyph += (yBiasT * (ROUND8(cxGlyph) >> 3));
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 6);
x = ppdev->xOffset + ptlOrigin.x;
I32_OW(pjIoBase, CUR_X, LOWORD(x));
I32_OW(pjIoBase, DEST_X_START, LOWORD(x));
I32_OW(pjIoBase, DEST_X_END, LOWORD(x) + ROUND8(cxGlyph) );
I32_OW(pjIoBase, SCISSOR_R, LOWORD(x) + cxGlyph-1);
y = ppdev->yOffset + ptlOrigin.y;
I32_OW(pjIoBase, CUR_Y, LOWORD(y+yBiasT));
I32_OW(pjIoBase, DEST_Y_END, (LOWORD(y+yBiasT) + cy));
vI32DataPortOutB(ppdev, pjGlyph, (ROUND8(cxGlyph) >> 3) * cy);
/*
_vBlit_DSC_SH1UP(ppdev,ptlOrigin.x,ptlOrigin.y+yBiasT,
cxGlyph, cy, pjGlyph,
(ROUND8(cxGlyph) >>3) * cy);
*/
} /*if*/
}
if (--cGlyph == 0)
break;
// 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);
}
} while (bMoreGlyphs);
vResetClipping(ppdev);
return TRUE;
}
/******************************Public*Routine******************************\
* BOOL bI32TextOut
*
\**************************************************************************/
BOOL bI32TextOut(
PDEV* ppdev,
STROBJ* pstro,
FONTOBJ* pfo,
CLIPOBJ* pco,
RECTL* prclOpaque,
BRUSHOBJ* pboFore,
BRUSHOBJ* pboOpaque)
{
BYTE* pjIoBase;
LONG xOffset;
LONG yOffset;
ULONG cGlyph;
BOOL bMoreGlyphs;
GLYPHPOS* pgp;
BYTE iDComplexity;
CACHEDFONT* pcf;
RECTL rclOpaque;
BOOL bTextPerfectFit;
pjIoBase = ppdev->pjIoBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (prclOpaque != NULL)
{
////////////////////////////////////////////////////////////
// Opaque Initialization
////////////////////////////////////////////////////////////
if (iDComplexity == DC_TRIVIAL)
{
DrawOpaqueRect:
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 8);
I32_OW(pjIoBase, FRGD_COLOR, pboOpaque->iSolidColor);
I32_OW(pjIoBase, ALU_FG_FN, OVERPAINT);
I32_OW(pjIoBase, DP_CONFIG, FG_COLOR_SRC_FG | WRITE | DRAW);
I32_OW(pjIoBase, CUR_X, xOffset + prclOpaque->left);
I32_OW(pjIoBase, DEST_X_START, xOffset + prclOpaque->left);
I32_OW(pjIoBase, DEST_X_END, xOffset + prclOpaque->right);
I32_OW(pjIoBase, CUR_Y, yOffset + prclOpaque->top);
vI32QuietDown(ppdev, pjIoBase);
I32_OW(pjIoBase, DEST_Y_END, yOffset + prclOpaque->bottom);
}
else if (iDComplexity == DC_RECT)
{
if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
{
prclOpaque = &rclOpaque;
goto DrawOpaqueRect;
}
}
else
{
vClipSolid(ppdev, prclOpaque, pboOpaque->iSolidColor, pco);
}
bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
SO_CHAR_INC_EQUAL_BM_BASE)) ==
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
if (bTextPerfectFit)
{
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 5);
I32_OW(pjIoBase, ALU_BG_FN, OVERPAINT);
I32_OW(pjIoBase, BKGD_COLOR, pboOpaque->iSolidColor);
goto SkipTransparentInitialization;
}
}
////////////////////////////////////////////////////////////
// Transparent Initialization
////////////////////////////////////////////////////////////
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 4);
I32_OW(pjIoBase, ALU_BG_FN, LEAVE_ALONE);
SkipTransparentInitialization:
I32_OW(pjIoBase, DP_CONFIG, EXT_MONO_SRC_HOST | DRAW | WRITE |
FG_COLOR_SRC_FG | BG_COLOR_SRC_BG |
LSB_FIRST | BIT16);
I32_OW(pjIoBase, ALU_FG_FN, OVERPAINT);
I32_OW(pjIoBase, FRGD_COLOR, pboFore->iSolidColor);
if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY))
{
pcf = (CACHEDFONT*) pfo->pvConsumer;
if (pcf == NULL)
{
pcf = pcfAllocateCachedFont(ppdev);
if (pcf == NULL)
return(FALSE);
pfo->pvConsumer = pcf;
}
// Use our glyph cache:
if (iDComplexity == DC_TRIVIAL)
{
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgp = pstro->pgp;
cGlyph = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
}
if (cGlyph > 0)
{
if (pstro->ulCharInc == 0)
{
if (!bI32CachedProportionalText(ppdev, pcf, pgp, cGlyph))
return(FALSE);
}
else
{
if (!bI32CachedFixedText(ppdev, pcf, pgp, cGlyph, pstro->ulCharInc))
return(FALSE);
}
}
} while (bMoreGlyphs);
}
else
{
if (!bI32CachedClippedText(ppdev, pcf, pstro, pco))
return(FALSE);
}
}
else
{
DISPDBG((4, "Text too big to cache: %li x %li",
pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
I32_CHECK_FIFO_SPACE(ppdev, pjIoBase, 1);
I32_OW(pjIoBase, DP_CONFIG, EXT_MONO_SRC_HOST | DRAW | WRITE |
FG_COLOR_SRC_FG | BG_COLOR_SRC_BG);
return bI32GeneralText(ppdev, pstro, pco);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bM32CachedProportionalText
*
* Draws proportionally spaced glyphs via glyph caching.
*
\**************************************************************************/
BOOL bM32CachedProportionalText(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph)
{
BYTE* pjMmBase;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG xOffset;
LONG yOffset;
LONG x;
LONG y;
LONG cw;
WORD* pw;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
// The glyph's origin y-coordinate may often be negative, so we
// can't compute this as follows:
//
// x = pgp->ptl.x + pcg->ptlOrigin.x;
// y = pgp->ptl.y + pcg->ptlOrigin.y;
ASSERTDD((pgp->ptl.y + pcg->ptlOrigin.y) >= 0,
"Can't have negative 'y' coordinates here");
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
x = xOffset + pgp->ptl.x + pcg->ptlOrigin.x;
M32_OW(pjMmBase, CUR_X, x);
M32_OW(pjMmBase, DEST_X_START, x);
M32_OW(pjMmBase, DEST_X_END, x + pcg->cx);
y = yOffset + pgp->ptl.y + pcg->ptlOrigin.y;
M32_OW(pjMmBase, CUR_Y, y);
M32_OW(pjMmBase, DEST_Y_END, y + pcg->cy);
// Take advantage of wait-stated I/O:
pw = (WORD*) &pcg->ad[0];
cw = pcg->cw;
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 10);
do {
M32_OW_DIRECT(pjMmBase, PIX_TRANS, *pw);
} while (pw++, --cw != 0);
}
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bM32CachedFixedText
*
* Draws fixed spaced glyphs via glyph caching.
*
\*************************************************************************/
BOOL bM32CachedFixedText(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph,
ULONG ulCharInc)
{
BYTE* pjMmBase;
LONG xGlyph;
LONG yGlyph;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG x;
LONG y;
WORD* pw;
LONG cw;
pjMmBase = ppdev->pjMmBase;
// Convert to absolute coordinates:
xGlyph = pgp->ptl.x + ppdev->xOffset;
yGlyph = pgp->ptl.y + ppdev->yOffset;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
x = xGlyph + pcg->ptlOrigin.x;
y = yGlyph + pcg->ptlOrigin.y;
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
M32_OW(pjMmBase, CUR_X, x);
M32_OW(pjMmBase, DEST_X_START, x);
M32_OW(pjMmBase, DEST_X_END, x + pcg->cx);
M32_OW(pjMmBase, CUR_Y, y);
M32_OW(pjMmBase, DEST_Y_END, y + pcg->cy);
// Take advantage of wait-stated I/O:
pw = (WORD*) &pcg->ad[0];
cw = pcg->cw;
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 10);
do {
M32_OW_DIRECT(pjMmBase, PIX_TRANS, *pw);
} while (pw++, --cw != 0);
}
xGlyph += ulCharInc;
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bM32CachedClippedText
*
* Draws clipped text via glyph caching.
*
\**************************************************************************/
BOOL bM32CachedClippedText(
PDEV* ppdev,
CACHEDFONT* pcf,
STROBJ* pstro,
CLIPOBJ* pco)
{
BOOL bRet;
BYTE* pjMmBase;
LONG xOffset;
LONG yOffset;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
BOOL bClippingSet;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
LONG xGlyph;
LONG yGlyph;
LONG x;
LONG y;
LONG xRight;
LONG yBottom;
LONG cy;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
HGLYPH hg;
CACHEDGLYPH* pcg;
WORD* pw;
LONG cw;
ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
"Don't expect trivial clipping in this function");
bRet = TRUE;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
ulCharInc = pstro->ulCharInc;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
if (pco->iDComplexity == DC_RECT)
{
// 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:
bMore = FALSE;
ce.c = 1;
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
// We don't always simply set the clipping rectangle here
// because it may actually end up that no text intersects
// this clip rectangle, so it would be for naught. This
// actually happens a lot when using NT's analog clock set
// to always-on-top, with a round shape:
bClippingSet = FALSE;
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
// We can't yet convert to absolute coordinates by adding
// in 'xOffset' or 'yOffset' here because we have yet to
// compare the coordinates to 'prclClip':
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg)
pcg = pcg->pcgNext;
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
{
bRet = FALSE;
goto AllDone;
}
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
cy = pcg->cy;
if (cy != 0)
{
y = pcg->ptlOrigin.y + yGlyph;
x = pcg->ptlOrigin.x + xGlyph;
xRight = pcg->cx + x;
yBottom = pcg->cy + y;
// Do trivial rejection:
if ((prclClip->right > x) &&
(prclClip->bottom > y) &&
(prclClip->left < xRight) &&
(prclClip->top < yBottom))
{
// Lazily set the hardware clipping:
if (!bClippingSet)
{
bClippingSet = TRUE;
vSetClipping(ppdev, prclClip);
}
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
M32_OW(pjMmBase, CUR_X, xOffset + x);
M32_OW(pjMmBase, DEST_X_START, xOffset + x);
M32_OW(pjMmBase, DEST_X_END, xOffset + xRight);
M32_OW(pjMmBase, CUR_Y, yOffset + y);
M32_OW(pjMmBase, DEST_Y_END, yOffset + yBottom);
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 10);
pw = (WORD*) &pcg->ad[0];
cw = pcg->cw;
do {
M32_OW_DIRECT(pjMmBase, PIX_TRANS, *pw);
} while (pw++, --cw != 0);
}
}
if (--cGlyph == 0)
break;
// Get ready for next glyph:
pgp++;
if (ulCharInc == 0)
{
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
}
else
{
xGlyph += ulCharInc;
}
}
}
} while (bMore);
}
} while (bMoreGlyphs);
AllDone:
vResetClipping(ppdev);
return(bRet);
}
VOID vM32DataPortOutB(PDEV *ppdev, PBYTE pb, UINT count)
{
BYTE *pjMmBase = ppdev->pjMmBase;
UINT i;
for (i=0; i < count; i++)
{
if (i % 8 == 0)
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 10);
M32_OB(pjMmBase, PIX_TRANS + 1, *((PUCHAR)pb)++);
}
}
/******************************Public*Routine******************************\
* BOOL bM32GeneralText
*
\**************************************************************************/
BOOL bM32GeneralText(
PDEV* ppdev,
STROBJ* pstro,
CLIPOBJ* pco)
{
BYTE* pjMmBase;
BYTE iDComplexity;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
GLYPHBITS* pgb;
POINTL ptlOrigin;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
LONG cxGlyph;
LONG cyGlyph;
LONG xBiasL = 0;
LONG xBiasR = 0;
LONG yBiasT = 0;
LONG cy = 0;
LONG cx = 0;
BYTE* pjGlyph;
LONG xLeft;
LONG yTop;
LONG xRight;
LONG yBottom;
RECTL NoClip;
LONG x;
LONG y;
pjMmBase = ppdev->pjMmBase;
/* Define Default Clipping area to be full video ram */
NoClip.top = 0;
NoClip.left = 0;
NoClip.right = ppdev->cxScreen;
NoClip.bottom = ppdev->cyScreen;
if (pco == NULL)
iDComplexity = DC_TRIVIAL;
else
iDComplexity = pco->iDComplexity;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
ulCharInc = pstro->ulCharInc;
if (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:
bMore = FALSE;
ce.c = 1;
if (iDComplexity == DC_TRIVIAL)
prclClip = &NoClip;
else
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
pgb = pgp->pgdf->pgb;
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
vSetClipping(ppdev, prclClip);
//ppdev->lRightScissor = rclRealClip.right; ???
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
pjGlyph = (BYTE*) pgb->aj;
if ((prclClip->left <= ptlOrigin.x) &&
(prclClip->top <= ptlOrigin.y) &&
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
{
//-----------------------------------------------------
// Unclipped glyph
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 6);
x = ppdev->xOffset + ptlOrigin.x;
M32_OW(pjMmBase, CUR_X, LOWORD(x));
M32_OW(pjMmBase, DEST_X_START, LOWORD(x));
M32_OW(pjMmBase, DEST_X_END, LOWORD(x) + ROUND8(cxGlyph) );
M32_OW(pjMmBase, SCISSOR_R, LOWORD(x) + cxGlyph-1);
y = ppdev->yOffset + ptlOrigin.y;
M32_OW(pjMmBase, CUR_Y, LOWORD(y));
M32_OW(pjMmBase, DEST_Y_END, (LOWORD(y) + cyGlyph));
vM32DataPortOutB(ppdev, pjGlyph, (ROUND8(cxGlyph) * cyGlyph) >> 3);
/*
_vBlit_DSC_SH1UP(ppdev,ptlOrigin.x, ptlOrigin.y,
cxGlyph, cyGlyph, pjGlyph,
(ROUND8(cxGlyph) * cyGlyph) >> 3);
*/
}
else
{
//-----------------------------------------------------
// Clipped glyph
// Find the intersection of the glyph rectangle
// and the clip rectangle:
xLeft = max(prclClip->left, ptlOrigin.x);
yTop = max(prclClip->top, ptlOrigin.y);
xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
// Check for trivial rejection:
if ( ( ptlOrigin.x <= prclClip->left ) &&
(ppdev->pModeInfo->ModeFlags & AMI_TEXTBAND) )
{
vResetClipping(ppdev);
return FALSE;
}
if (((cx = xRight - xLeft) > 0) &&
((cy = yBottom - yTop) > 0))
{
/* Do software clipping */
/* Calculated the Bias in pixels */
yBiasT = (yTop - ptlOrigin.y);
/* change address of pjGlyph to point +yBiasT
scan lines into the Glyph */
pjGlyph += (yBiasT * (ROUND8(cxGlyph) >> 3));
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 6);
x = ppdev->xOffset + ptlOrigin.x;
M32_OW(pjMmBase, CUR_X, LOWORD(x));
M32_OW(pjMmBase, DEST_X_START, LOWORD(x));
M32_OW(pjMmBase, DEST_X_END, LOWORD(x) + ROUND8(cxGlyph) );
M32_OW(pjMmBase, SCISSOR_R, LOWORD(x) + cxGlyph-1);
y = ppdev->yOffset + ptlOrigin.y;
M32_OW(pjMmBase, CUR_Y, LOWORD(y+yBiasT));
M32_OW(pjMmBase, DEST_Y_END, (LOWORD(y+yBiasT) + cy));
vM32DataPortOutB(ppdev, pjGlyph, (ROUND8(cxGlyph) >> 3) * cy);
/*
_vBlit_DSC_SH1UP(ppdev,ptlOrigin.x,ptlOrigin.y+yBiasT,
cxGlyph, cy, pjGlyph,
(ROUND8(cxGlyph) >>3) * cy);
*/
} /*if*/
}
if (--cGlyph == 0)
break;
// 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);
}
} while (bMoreGlyphs);
vResetClipping(ppdev);
return TRUE;
}
/******************************Public*Routine******************************\
* BOOL bM32TextOut
*
\**************************************************************************/
BOOL bM32TextOut(
PDEV* ppdev,
STROBJ* pstro,
FONTOBJ* pfo,
CLIPOBJ* pco,
RECTL* prclOpaque,
BRUSHOBJ* pboFore,
BRUSHOBJ* pboOpaque)
{
BYTE* pjMmBase;
LONG xOffset;
LONG yOffset;
ULONG cGlyph;
BOOL bMoreGlyphs;
GLYPHPOS* pgp;
BYTE iDComplexity;
CACHEDFONT* pcf;
RECTL rclOpaque;
BOOL bTextPerfectFit;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (prclOpaque != NULL)
{
////////////////////////////////////////////////////////////
// Opaque Initialization
////////////////////////////////////////////////////////////
if (iDComplexity == DC_TRIVIAL)
{
DrawOpaqueRect:
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 8);
M32_OW(pjMmBase, FRGD_COLOR, pboOpaque->iSolidColor);
M32_OW(pjMmBase, ALU_FG_FN, OVERPAINT);
M32_OW(pjMmBase, DP_CONFIG, FG_COLOR_SRC_FG | WRITE | DRAW);
M32_OW(pjMmBase, CUR_X, xOffset + prclOpaque->left);
M32_OW(pjMmBase, DEST_X_START, xOffset + prclOpaque->left);
M32_OW(pjMmBase, DEST_X_END, xOffset + prclOpaque->right);
M32_OW(pjMmBase, CUR_Y, yOffset + prclOpaque->top);
vM32QuietDown(ppdev, pjMmBase);
M32_OW(pjMmBase, DEST_Y_END, yOffset + prclOpaque->bottom);
}
else if (iDComplexity == DC_RECT)
{
if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
{
prclOpaque = &rclOpaque;
goto DrawOpaqueRect;
}
}
else
{
vClipSolid(ppdev, prclOpaque, pboOpaque->iSolidColor, pco);
}
bTextPerfectFit = (pstro->flAccel & (SO_ZERO_BEARINGS |
SO_FLAG_DEFAULT_PLACEMENT | SO_MAXEXT_EQUAL_BM_SIDE |
SO_CHAR_INC_EQUAL_BM_BASE)) ==
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
SO_MAXEXT_EQUAL_BM_SIDE | SO_CHAR_INC_EQUAL_BM_BASE);
if (bTextPerfectFit)
{
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
M32_OW(pjMmBase, ALU_BG_FN, OVERPAINT);
M32_OW(pjMmBase, BKGD_COLOR, pboOpaque->iSolidColor);
goto SkipTransparentInitialization;
}
}
////////////////////////////////////////////////////////////
// Transparent Initialization
////////////////////////////////////////////////////////////
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 4);
M32_OW(pjMmBase, ALU_BG_FN, LEAVE_ALONE);
SkipTransparentInitialization:
M32_OW(pjMmBase, DP_CONFIG, EXT_MONO_SRC_HOST | DRAW | WRITE |
FG_COLOR_SRC_FG | BG_COLOR_SRC_BG |
LSB_FIRST | BIT16);
M32_OW(pjMmBase, ALU_FG_FN, OVERPAINT);
M32_OW(pjMmBase, FRGD_COLOR, pboFore->iSolidColor);
if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY))
{
pcf = (CACHEDFONT*) pfo->pvConsumer;
if (pcf == NULL)
{
pcf = pcfAllocateCachedFont(ppdev);
if (pcf == NULL)
return(FALSE);
pfo->pvConsumer = pcf;
}
// Use our glyph cache:
if (iDComplexity == DC_TRIVIAL)
{
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgp = pstro->pgp;
cGlyph = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
}
if (cGlyph > 0)
{
if (pstro->ulCharInc == 0)
{
if (!bM32CachedProportionalText(ppdev, pcf, pgp, cGlyph))
return(FALSE);
}
else
{
if (!bM32CachedFixedText(ppdev, pcf, pgp, cGlyph, pstro->ulCharInc))
return(FALSE);
}
}
} while (bMoreGlyphs);
}
else
{
if (!bM32CachedClippedText(ppdev, pcf, pstro, pco))
return(FALSE);
}
}
else
{
DISPDBG((4, "Text too big to cache: %li x %li",
pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
M32_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
M32_OW(pjMmBase, DP_CONFIG, EXT_MONO_SRC_HOST | DRAW | WRITE |
FG_COLOR_SRC_FG | BG_COLOR_SRC_BG);
return bM32GeneralText(ppdev, pstro, pco);
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bM64CachedProportionalText
*
* Draws proportionally spaced glyphs via glyph caching.
*
\**************************************************************************/
BOOL bM64CachedProportionalText(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph)
{
BYTE* pjMmBase;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG xOffset;
LONG yOffset;
LONG x;
LONG y;
LONG cd;
DWORD* pd;
LONG cFifo;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
cFifo = 0;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
// The glyph's origin y-coordinate may often be negative, so we
// can't compute this as follows:
//
// x = pgp->ptl.x + pcg->ptlOrigin.x;
// y = pgp->ptl.y + pcg->ptlOrigin.y;
ASSERTDD((pgp->ptl.y + pcg->ptlOrigin.y) >= 0,
"Can't have negative 'y' coordinates here");
cFifo -= 2;
if (cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 14;
}
x = xOffset + pgp->ptl.x + pcg->ptlOrigin.x;
y = yOffset + pgp->ptl.y + pcg->ptlOrigin.y;
M64_OD(pjMmBase, DST_Y_X, PACKXY_FAST(x, y));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, pcg->cxy);
pd = (DWORD*) &pcg->ad[0];
cd = pcg->cd;
do {
if (--cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 15;
}
M64_OD(pjMmBase, HOST_DATA0, *pd);
} while (pd++, --cd != 0);
}
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
BOOL bM64CachedProportionalText24(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph)
{
BYTE* pjMmBase;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG xOffset;
LONG yOffset;
LONG x;
LONG y;
LONG cd;
DWORD* pd;
LONG cFifo;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
cFifo = 0;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
// The glyph's origin y-coordinate may often be negative, so we
// can't compute this as follows:
//
// x = pgp->ptl.x + pcg->ptlOrigin.x;
// y = pgp->ptl.y + pcg->ptlOrigin.y;
ASSERTDD((pgp->ptl.y + pcg->ptlOrigin.y) >= 0,
"Can't have negative 'y' coordinates here");
cFifo -= 3;
if (cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 13;
}
x = (xOffset + pgp->ptl.x + pcg->ptlOrigin.x) * 3;
y = yOffset + pgp->ptl.y + pcg->ptlOrigin.y;
M64_OD(pjMmBase, DST_CNTL, 0x83 | (((x + MAX_NEGX*3)/4 % 6) << 8));
M64_OD(pjMmBase, DST_Y_X, PACKXY_FAST(x, y));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, pcg->cxy);
pd = (DWORD*) &pcg->ad[0];
cd = pcg->cd;
do {
if (--cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 15;
}
M64_OD(pjMmBase, HOST_DATA0, *pd);
} while (pd++, --cd != 0);
}
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bM64CachedFixedText
*
* Draws fixed spaced glyphs via glyph caching.
*
\*************************************************************************/
BOOL bM64CachedFixedText(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph,
ULONG ulCharInc)
{
BYTE* pjMmBase;
LONG xGlyph;
LONG yGlyph;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG x;
LONG y;
DWORD* pd;
LONG cd;
LONG cFifo;
pjMmBase = ppdev->pjMmBase;
cFifo = 0;
// Convert to absolute coordinates:
xGlyph = pgp->ptl.x + ppdev->xOffset;
yGlyph = pgp->ptl.y + ppdev->yOffset;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
x = xGlyph + pcg->ptlOrigin.x;
y = yGlyph + pcg->ptlOrigin.y;
cFifo -= 2;
if (cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 14;
}
M64_OD(pjMmBase, DST_Y_X, PACKXY_FAST(x, y));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, pcg->cxy);
pd = (DWORD*) &pcg->ad[0];
cd = pcg->cd;
do {
if (--cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 15;
}
M64_OD(pjMmBase, HOST_DATA0, *pd);
} while (pd++, --cd != 0);
}
xGlyph += ulCharInc;
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
BOOL bM64CachedFixedText24(
PDEV* ppdev,
CACHEDFONT* pcf,
GLYPHPOS* pgp,
LONG cGlyph,
ULONG ulCharInc)
{
BYTE* pjMmBase;
LONG xGlyph;
LONG yGlyph;
HGLYPH hg;
CACHEDGLYPH* pcg;
LONG x;
LONG y;
DWORD* pd;
LONG cd;
LONG cFifo;
pjMmBase = ppdev->pjMmBase;
cFifo = 0;
// Convert to absolute coordinates:
xGlyph = pgp->ptl.x + ppdev->xOffset;
yGlyph = pgp->ptl.y + ppdev->yOffset;
do {
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg) {
pcg = pcg->pcgNext;
}
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
return(FALSE);
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
if (pcg->cx != 0)
{
x = (xGlyph + pcg->ptlOrigin.x) * 3;
y = yGlyph + pcg->ptlOrigin.y;
cFifo -= 3;
if (cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 13;
}
M64_OD(pjMmBase, DST_CNTL, 0x83 | (((x + MAX_NEGX*3)/4 % 6) << 8));
M64_OD(pjMmBase, DST_Y_X, PACKXY_FAST(x, y));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, pcg->cxy);
pd = (DWORD*) &pcg->ad[0];
cd = pcg->cd;
do {
if (--cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 15;
}
M64_OD(pjMmBase, HOST_DATA0, *pd);
} while (pd++, --cd != 0);
}
xGlyph += ulCharInc;
} while (pgp++, --cGlyph != 0);
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bM64CachedClippedText
*
* Draws clipped text via glyph caching.
*
\**************************************************************************/
BOOL bM64CachedClippedText(
PDEV* ppdev,
CACHEDFONT* pcf,
STROBJ* pstro,
CLIPOBJ* pco)
{
BOOL bRet;
BYTE* pjMmBase;
LONG xOffset;
LONG yOffset;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
BOOL bClippingSet;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
LONG xGlyph;
LONG yGlyph;
LONG x;
LONG y;
LONG xRight;
LONG yBottom;
LONG cy;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
HGLYPH hg;
CACHEDGLYPH* pcg;
DWORD* pd;
LONG cd;
LONG cFifo;
ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
"Don't expect trivial clipping in this function");
bRet = TRUE;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
ulCharInc = pstro->ulCharInc;
cFifo = 0;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
if (pco->iDComplexity == DC_RECT)
{
// 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:
bMore = FALSE;
ce.c = 1;
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
// We don't always simply set the clipping rectangle here
// because it may actually end up that no text intersects
// this clip rectangle, so it would be for naught. This
// actually happens a lot when using NT's analog clock set
// to always-on-top, with a round shape:
bClippingSet = FALSE;
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
// We can't yet convert to absolute coordinates by adding
// in 'xOffset' or 'yOffset' here because we have yet to
// compare the coordinates to 'prclClip':
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg)
pcg = pcg->pcgNext;
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
{
bRet = FALSE;
goto AllDone;
}
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
cy = pcg->cy;
if (cy != 0)
{
y = pcg->ptlOrigin.y + yGlyph;
x = pcg->ptlOrigin.x + xGlyph;
xRight = pcg->cx + x;
yBottom = pcg->cy + y;
// Do trivial rejection:
if ((prclClip->right > x) &&
(prclClip->bottom > y) &&
(prclClip->left < xRight) &&
(prclClip->top < yBottom))
{
// Lazily set the hardware clipping:
if (!bClippingSet)
{
bClippingSet = TRUE;
vSetClipping(ppdev, prclClip);
cFifo = 0; // Have to initialize count
}
cFifo -= 2;
if (cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 14;
}
M64_OD(pjMmBase, DST_Y_X, PACKXY(xOffset + x, yOffset + y));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, pcg->cxy);
pd = (DWORD*) &pcg->ad[0];
cd = pcg->cd;
do {
if (--cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 15;
}
M64_OD(pjMmBase, HOST_DATA0, *pd);
} while (pd++, --cd != 0);
}
}
if (--cGlyph == 0)
break;
// Get ready for next glyph:
pgp++;
if (ulCharInc == 0)
{
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
}
else
{
xGlyph += ulCharInc;
}
}
}
} while (bMore);
}
} while (bMoreGlyphs);
AllDone:
vResetClipping(ppdev);
return(bRet);
}
BOOL bM64CachedClippedText24(
PDEV* ppdev,
CACHEDFONT* pcf,
STROBJ* pstro,
CLIPOBJ* pco)
{
BOOL bRet;
BYTE* pjMmBase;
LONG xOffset;
LONG yOffset;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
BOOL bClippingSet;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
LONG xGlyph;
LONG yGlyph;
LONG x;
LONG y;
LONG xRight;
LONG yBottom;
LONG cy;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
HGLYPH hg;
CACHEDGLYPH* pcg;
DWORD* pd;
LONG cd;
LONG cFifo;
LONG xTmp;
ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
"Don't expect trivial clipping in this function");
bRet = TRUE;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
ulCharInc = pstro->ulCharInc;
cFifo = 0;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
if (pco->iDComplexity == DC_RECT)
{
// 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:
bMore = FALSE;
ce.c = 1;
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
// We don't always simply set the clipping rectangle here
// because it may actually end up that no text intersects
// this clip rectangle, so it would be for naught. This
// actually happens a lot when using NT's analog clock set
// to always-on-top, with a round shape:
bClippingSet = FALSE;
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
// We can't yet convert to absolute coordinates by adding
// in 'xOffset' or 'yOffset' here because we have yet to
// compare the coordinates to 'prclClip':
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
hg = pgp->hg;
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
while (pcg->hg < hg)
pcg = pcg->pcgNext;
if (pcg->hg > hg)
{
// This will hopefully not be the common case (that is,
// we will have a high cache hit rate), so if I were
// writing this in Asm I would have this out-of-line
// to avoid the jump around for the common case.
// But the Pentium has branch prediction, so what the
// heck.
pcg = pcgNew(ppdev, pcf, pgp);
if (pcg == NULL)
{
bRet = FALSE;
goto AllDone;
}
}
// Space glyphs are trimmed to a height of zero, and we don't
// even have to touch the hardware for them:
cy = pcg->cy;
if (cy != 0)
{
y = pcg->ptlOrigin.y + yGlyph;
x = pcg->ptlOrigin.x + xGlyph;
xRight = pcg->cx + x;
yBottom = pcg->cy + y;
// Do trivial rejection:
if ((prclClip->right > x) &&
(prclClip->bottom > y) &&
(prclClip->left < xRight) &&
(prclClip->top < yBottom))
{
// Lazily set the hardware clipping:
if (!bClippingSet)
{
bClippingSet = TRUE;
vSetClipping(ppdev, prclClip);
cFifo = 0; // Have to initialize count
}
cFifo -= 3;
if (cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 13;
}
xTmp = (xOffset + x) * 3;
M64_OD(pjMmBase, DST_CNTL, 0x83 | (((xTmp + MAX_NEGX*3)/4 % 6) << 8));
M64_OD(pjMmBase, DST_Y_X, PACKXY(xTmp, yOffset + y));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, pcg->cxy);
pd = (DWORD*) &pcg->ad[0];
cd = pcg->cd;
do {
if (--cFifo < 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
cFifo = 15;
}
M64_OD(pjMmBase, HOST_DATA0, *pd);
} while (pd++, --cd != 0);
}
}
if (--cGlyph == 0)
break;
// Get ready for next glyph:
pgp++;
if (ulCharInc == 0)
{
xGlyph = pgp->ptl.x;
yGlyph = pgp->ptl.y;
}
else
{
xGlyph += ulCharInc;
}
}
}
} while (bMore);
}
} while (bMoreGlyphs);
AllDone:
vResetClipping(ppdev);
return(bRet);
}
/******************************Public*Routine******************************\
* BOOL bM64GeneralText
*
\**************************************************************************/
BOOL bM64GeneralText(
PDEV* ppdev,
STROBJ* pstro,
CLIPOBJ* pco)
{
BYTE* pjMmBase;
BYTE iDComplexity;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
GLYPHBITS* pgb;
POINTL ptlOrigin;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
LONG cxGlyph;
LONG cyGlyph;
LONG xBiasL = 0;
LONG xBiasR = 0;
LONG yBiasT = 0;
LONG cy = 0;
LONG cx = 0;
BYTE* pjGlyph;
LONG xLeft;
LONG yTop;
LONG xRight;
LONG yBottom;
RECTL NoClip;
pjMmBase = ppdev->pjMmBase;
/* Define Default Clipping area to be full video ram */
NoClip.top = 0;
NoClip.left = 0;
NoClip.right = ppdev->cxScreen;
NoClip.bottom = ppdev->cyScreen;
if (pco == NULL)
iDComplexity = DC_TRIVIAL;
else
iDComplexity = pco->iDComplexity;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
ulCharInc = pstro->ulCharInc;
if (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:
bMore = FALSE;
ce.c = 1;
if (iDComplexity == DC_TRIVIAL)
prclClip = &NoClip;
else
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
pgb = pgp->pgdf->pgb;
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
vSetClipping(ppdev, prclClip);
//ppdev->lRightScissor = rclRealClip.right; ???
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
pjGlyph = (BYTE*) pgb->aj;
if ((prclClip->left <= ptlOrigin.x) &&
(prclClip->top <= ptlOrigin.y) &&
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
{
//-----------------------------------------------------
// Unclipped glyph
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 3);
M64_OD(pjMmBase, HOST_CNTL, 1);
M64_OD(pjMmBase, DST_Y_X, ((ppdev->yOffset+ptlOrigin.y) & 0xffff) |
((ppdev->xOffset+ptlOrigin.x) << 16));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, cyGlyph | cxGlyph << 16);
vM64DataPortOutB(ppdev, pjGlyph, (ROUND8(cxGlyph) * cyGlyph) >> 3);
/*
_vBlit_DSC_SH1UP(ppdev,ptlOrigin.x, ptlOrigin.y,
cxGlyph, cyGlyph, pjGlyph,
(ROUND8(cxGlyph) * cyGlyph) >> 3);
*/
}
else
{
//-----------------------------------------------------
// Clipped glyph
// Find the intersection of the glyph rectangle
// and the clip rectangle:
xLeft = max(prclClip->left, ptlOrigin.x);
yTop = max(prclClip->top, ptlOrigin.y);
xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
// Check for trivial rejection:
if ( ( ptlOrigin.x <= prclClip->left ) &&
(ppdev->pModeInfo->ModeFlags & AMI_TEXTBAND) )
{
vResetClipping(ppdev);
return FALSE;
}
if (((cx = xRight - xLeft) > 0) &&
((cy = yBottom - yTop) > 0))
{
/* Do software clipping */
/* Calculated the Bias in pixels */
yBiasT = (yTop - ptlOrigin.y);
/* change address of pjGlyph to point +yBiasT
scan lines into the Glyph */
pjGlyph += (yBiasT * (ROUND8(cxGlyph) >> 3));
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 3);
M64_OD(pjMmBase, HOST_CNTL, 1);
M64_OD(pjMmBase, DST_Y_X, ((ppdev->yOffset+ptlOrigin.y+yBiasT) & 0xffff) |
((ppdev->xOffset+ptlOrigin.x) << 16));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, cy | cxGlyph << 16);
vM64DataPortOutB(ppdev, pjGlyph, (ROUND8(cxGlyph) >> 3) * cy);
/*
_vBlit_DSC_SH1UP(ppdev,ptlOrigin.x,ptlOrigin.y+yBiasT,
cxGlyph, cy, pjGlyph,
(ROUND8(cxGlyph) >>3) * cy);
*/
} /*if*/
}
if (--cGlyph == 0)
break;
// 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);
}
} while (bMoreGlyphs);
vResetClipping(ppdev);
// We must reset the HOST_CNTL register, or else BAD things happen when
// rendering text in the OTHER functions.
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
M64_OD(pjMmBase, HOST_CNTL, 0);
return TRUE;
}
VOID vM64DataPortOutD_24bppmono(PDEV* ppdev, PBYTE pb, UINT count, LONG pitch)
{
BYTE* pjMmBase = ppdev->pjMmBase;
UINT i,j;
DWORD hostdata, remainder;
UINT l;
LONG data24;
unsigned char data8;
hostdata = 0;
l = 0;
for (i = 0; i < count; i++)
{
switch (l)
{
case 0:
// expand 8 to 24bpp
data24 = 0;
data8 = *pb++;
for (j = 0; j < 8; j++)
{
data24 <<= 3;
if ((data8 >> j) & 1)
{
data24 |= 7;
}
}
hostdata = data24;
// expand 8 to 24bpp
data24 = 0;
data8 = *pb++;
for (j = 0; j < 8; j++)
{
data24 <<= 3;
if ((data8 >> j) & 1)
{
data24 |= 7;
}
}
remainder = data24;
hostdata = hostdata | (remainder << 24);
break;
case 1:
data24 = 0;
data8 = *pb++;
for (j = 0; j < 8; j++)
{
data24 <<= 3;
if ((data8 >> j) & 1)
{
data24 |= 7;
}
}
remainder = data24;
hostdata = (hostdata >> 8) | (remainder << 16);
break;
case 2:
data24 = 0;
data8 = *pb++;
for (j = 0; j < 8; j++)
{
data24 <<= 3;
if ((data8 >> j) & 1)
{
data24 |= 7;
}
}
remainder = data24;
hostdata = (hostdata >> 16) | (remainder << 8);
break;
}
if ((i % 14) == 0)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 16);
}
M64_OD(pjMmBase, HOST_DATA0, hostdata);
hostdata = remainder;
// 24 bpp alignment variable handling
l = (l+1) % 3;
}
}
BOOL bM64GeneralText24(
PDEV* ppdev,
STROBJ* pstro,
CLIPOBJ* pco)
{
BYTE* pjMmBase;
BYTE iDComplexity;
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
GLYPHBITS* pgb;
POINTL ptlOrigin;
BOOL bMore;
CLIPENUM ce;
RECTL* prclClip;
ULONG ulCharInc;
LONG cxGlyph;
LONG cyGlyph;
LONG xBiasL = 0;
LONG xBiasR = 0;
LONG yBiasT = 0;
LONG cy = 0;
LONG cx = 0;
BYTE* pjGlyph;
LONG xLeft;
LONG yTop;
LONG xRight;
LONG yBottom;
RECTL NoClip;
BOOLEAN resetScissor;
LONG x;
DWORD dwCount;
pjMmBase = ppdev->pjMmBase;
/* Define Default Clipping area to be full video ram */
NoClip.top = 0;
NoClip.left = 0;
NoClip.right = ppdev->cxScreen;
NoClip.bottom = ppdev->cyScreen;
if (pco == NULL)
iDComplexity = DC_TRIVIAL;
else
iDComplexity = pco->iDComplexity;
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgpOriginal = pstro->pgp;
cGlyphOriginal = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyphOriginal, &pgpOriginal);
}
if (cGlyphOriginal > 0)
{
ulCharInc = pstro->ulCharInc;
if (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:
bMore = FALSE;
ce.c = 1;
if (iDComplexity == DC_TRIVIAL)
prclClip = &NoClip;
else
prclClip = &pco->rclBounds;
goto SingleRectangle;
}
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++)
{
SingleRectangle:
pgp = pgpOriginal;
cGlyph = cGlyphOriginal;
pgb = pgp->pgdf->pgb;
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
vSetClipping(ppdev, prclClip);
//ppdev->lRightScissor = rclRealClip.right; ???
// Loop through all the glyphs for this rectangle:
while (TRUE)
{
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
pjGlyph = (BYTE*) pgb->aj;
if ((prclClip->left <= ptlOrigin.x) &&
(prclClip->top <= ptlOrigin.y) &&
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
{
//-----------------------------------------------------
// Unclipped glyph
x = ppdev->xOffset+ptlOrigin.x;
resetScissor = FALSE;
if ((prclClip->right * 3) - 1 > (x - ppdev->xOffset + cxGlyph) * 3 - 1)
{
resetScissor = TRUE;
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 4);
M64_OD(pjMmBase, SC_RIGHT, (x + cxGlyph) * 3 - 1);
}
else
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 3);
}
M64_OD(pjMmBase, DST_CNTL, 0x83 | (((x + MAX_NEGX)*3/4 % 6) << 8));
M64_OD(pjMmBase, DST_Y_X, ((ppdev->yOffset+ptlOrigin.y) & 0xffff) |
(x*3 << 16));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, cyGlyph | (ROUND8(cxGlyph) * 3) << 16);
dwCount = (ROUND8(cxGlyph) * 3 * cyGlyph + 31) / 32;
vM64DataPortOutD_24bppmono(ppdev, pjGlyph, dwCount, cxGlyph);
if (resetScissor)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
M64_OD(pjMmBase, SC_RIGHT, (ppdev->xOffset + prclClip->right) * 3 - 1);
}
}
else
{
//-----------------------------------------------------
// Clipped glyph
// Find the intersection of the glyph rectangle
// and the clip rectangle:
xLeft = max(prclClip->left, ptlOrigin.x);
yTop = max(prclClip->top, ptlOrigin.y);
xRight = min(prclClip->right, ptlOrigin.x + cxGlyph);
yBottom = min(prclClip->bottom, ptlOrigin.y + cyGlyph);
// Check for trivial rejection:
if ( ( ptlOrigin.x <= prclClip->left ) &&
(ppdev->pModeInfo->ModeFlags & AMI_TEXTBAND) )
{
vResetClipping(ppdev);
return FALSE;
}
if (((cx = xRight - xLeft) > 0) &&
((cy = yBottom - yTop) > 0))
{
/* Do software clipping */
/* Calculated the Bias in pixels */
yBiasT = (yTop - ptlOrigin.y);
/* change address of pjGlyph to point +yBiasT
scan lines into the Glyph */
pjGlyph += (yBiasT * (ROUND8(cxGlyph) >> 3));
x = ppdev->xOffset+ptlOrigin.x;
resetScissor = FALSE;
if ((prclClip->right * 3) - 1 > (x - ppdev->xOffset + cxGlyph) * 3 - 1)
{
resetScissor = TRUE;
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 4);
M64_OD(pjMmBase, SC_RIGHT, (x + cxGlyph) * 3 - 1);
}
else
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 3);
}
M64_OD(pjMmBase, DST_CNTL, 0x83 | (((x + MAX_NEGX)*3/4 % 6) << 8));
M64_OD(pjMmBase, DST_Y_X, ((ppdev->yOffset+ptlOrigin.y+yBiasT) & 0xffff) |
(x*3 << 16));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH, cy | (ROUND8(cxGlyph) * 3) << 16);
dwCount = (ROUND8(cxGlyph) * 3 * cy + 31) / 32;
vM64DataPortOutD_24bppmono(ppdev, pjGlyph, dwCount, cxGlyph);
if (resetScissor)
{
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
M64_OD(pjMmBase, SC_RIGHT, (ppdev->xOffset + prclClip->right) * 3 - 1);
}
} /*if*/
}
if (--cGlyph == 0)
break;
// 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);
}
} while (bMoreGlyphs);
vResetClipping(ppdev);
return TRUE;
}
/******************************Public*Routine******************************\
* BOOL bM64TextOut
*
\**************************************************************************/
BOOL bM64TextOut(
PDEV* ppdev,
STROBJ* pstro,
FONTOBJ* pfo,
CLIPOBJ* pco,
RECTL* prclOpaque,
BRUSHOBJ* pboFore,
BRUSHOBJ* pboOpaque)
{
BYTE* pjMmBase;
LONG xOffset;
LONG yOffset;
ULONG cGlyph;
BOOL bMoreGlyphs;
GLYPHPOS* pgp;
BYTE iDComplexity;
CACHEDFONT* pcf;
RECTL rclOpaque;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (prclOpaque != NULL)
{
////////////////////////////////////////////////////////////
// Opaque Initialization
////////////////////////////////////////////////////////////
if (iDComplexity == DC_TRIVIAL)
{
DrawOpaqueRect:
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
M64_OD(pjMmBase, DP_MIX, (OVERPAINT << 16));
M64_OD(pjMmBase, DP_FRGD_CLR, pboOpaque->iSolidColor);
M64_OD(pjMmBase, DP_SRC, DP_SRC_FrgdClr << 8);
M64_OD(pjMmBase, DST_Y_X, PACKXY_FAST(xOffset + prclOpaque->left,
yOffset + prclOpaque->top));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH,
PACKXY_FAST(prclOpaque->right - prclOpaque->left,
prclOpaque->bottom - prclOpaque->top));
}
else if (iDComplexity == DC_RECT)
{
if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
{
prclOpaque = &rclOpaque;
goto DrawOpaqueRect;
}
}
else
{
vClipSolid(ppdev, prclOpaque, pboOpaque->iSolidColor, pco);
}
// I didn't observe any performance difference between setting
// the ATI to opaque or transparent mode (when the font allowed
// it -- some don't).
}
////////////////////////////////////////////////////////////
// Transparent Initialization
////////////////////////////////////////////////////////////
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
M64_OD(pjMmBase, CONTEXT_LOAD_CNTL, CONTEXT_LOAD_CmdLoad | ppdev->iDefContext );
M64_OD(pjMmBase, DP_MIX, (OVERPAINT << 16) | LEAVE_ALONE);
M64_OD(pjMmBase, DP_FRGD_CLR, pboFore->iSolidColor);
M64_OD(pjMmBase, DP_SRC, (DP_SRC_Host << 16) | (DP_SRC_FrgdClr << 8) |
(DP_SRC_BkgdClr));
// For some reason, the SRC color depth must be monochrome.
// Otherwise, it will cause wait-for-idle to hang.
M64_OD(pjMmBase, DP_PIX_WIDTH, ppdev->ulMonoPixelWidth & 0xFFFF00FF);
if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY))
{
pcf = (CACHEDFONT*) pfo->pvConsumer;
if (pcf == NULL)
{
pcf = pcfAllocateCachedFont(ppdev);
if (pcf == NULL)
goto ReturnFalse;
pfo->pvConsumer = pcf;
}
// Use our glyph cache:
if (iDComplexity == DC_TRIVIAL)
{
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgp = pstro->pgp;
cGlyph = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
}
if (cGlyph > 0)
{
if (pstro->ulCharInc == 0)
{
if (!bM64CachedProportionalText(ppdev, pcf, pgp, cGlyph))
goto ReturnFalse;
}
else
{
if (!bM64CachedFixedText(ppdev, pcf, pgp, cGlyph, pstro->ulCharInc))
goto ReturnFalse;
}
}
} while (bMoreGlyphs);
}
else
{
if (!bM64CachedClippedText(ppdev, pcf, pstro, pco))
goto ReturnFalse;
}
}
else
{
DISPDBG((4, "Text too big to cache: %li x %li",
pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
if (!bM64GeneralText(ppdev, pstro, pco))
goto ReturnFalse;
}
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
M64_OD(pjMmBase, DP_PIX_WIDTH, ppdev->ulMonoPixelWidth);
return(TRUE);
ReturnFalse:
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 1);
M64_OD(pjMmBase, DP_PIX_WIDTH, ppdev->ulMonoPixelWidth);
return(FALSE);
}
BOOL bM64TextOut24(
PDEV* ppdev,
STROBJ* pstro,
FONTOBJ* pfo,
CLIPOBJ* pco,
RECTL* prclOpaque,
BRUSHOBJ* pboFore,
BRUSHOBJ* pboOpaque)
{
BYTE* pjMmBase;
LONG xOffset;
LONG yOffset;
ULONG cGlyph;
BOOL bMoreGlyphs;
GLYPHPOS* pgp;
BYTE iDComplexity;
CACHEDFONT* pcf;
RECTL rclOpaque;
LONG x;
pjMmBase = ppdev->pjMmBase;
xOffset = ppdev->xOffset;
yOffset = ppdev->yOffset;
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
if (prclOpaque != NULL)
{
////////////////////////////////////////////////////////////
// Opaque Initialization
////////////////////////////////////////////////////////////
if (iDComplexity == DC_TRIVIAL)
{
DrawOpaqueRect:
x = (xOffset + prclOpaque->left) * 3;
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 6);
M64_OD(pjMmBase, DST_CNTL, 0x83 | ((x/4 % 6) << 8));
M64_OD(pjMmBase, DP_MIX, (OVERPAINT << 16));
M64_OD(pjMmBase, DP_FRGD_CLR, pboOpaque->iSolidColor);
M64_OD(pjMmBase, DP_SRC, DP_SRC_FrgdClr << 8);
M64_OD(pjMmBase, DST_Y_X, PACKXY_FAST(x,
yOffset + prclOpaque->top));
M64_OD(pjMmBase, DST_HEIGHT_WIDTH,
PACKXY_FAST((prclOpaque->right - prclOpaque->left) * 3,
prclOpaque->bottom - prclOpaque->top));
}
else if (iDComplexity == DC_RECT)
{
if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
{
prclOpaque = &rclOpaque;
goto DrawOpaqueRect;
}
}
else
{
vClipSolid(ppdev, prclOpaque, pboOpaque->iSolidColor, pco);
}
// I didn't observe any performance difference between setting
// the ATI to opaque or transparent mode (when the font allowed
// it -- some don't).
}
////////////////////////////////////////////////////////////
// Transparent Initialization
////////////////////////////////////////////////////////////
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 5);
M64_OD(pjMmBase, CONTEXT_LOAD_CNTL, CONTEXT_LOAD_CmdLoad | ppdev->iDefContext );
M64_OD(pjMmBase, DP_MIX, (OVERPAINT << 16) | LEAVE_ALONE);
M64_OD(pjMmBase, DP_FRGD_CLR, pboFore->iSolidColor);
M64_OD(pjMmBase, DP_SRC, (DP_SRC_Host << 16) | (DP_SRC_FrgdClr << 8) |
(DP_SRC_BkgdClr));
// For some reason, the SRC color depth must be monochrome.
// Otherwise, it will cause wait-for-idle to hang.
M64_OD(pjMmBase, DP_PIX_WIDTH, ppdev->ulMonoPixelWidth & 0xFFFF00FF);
if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY))
{
pcf = (CACHEDFONT*) pfo->pvConsumer;
if (pcf == NULL)
{
pcf = pcfAllocateCachedFont(ppdev);
if (pcf == NULL)
goto ReturnFalse;
pfo->pvConsumer = pcf;
}
// Use our glyph cache:
if (iDComplexity == DC_TRIVIAL)
{
do {
if (pstro->pgp != NULL)
{
// There's only the one batch of glyphs, so save ourselves
// a call:
pgp = pstro->pgp;
cGlyph = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
}
if (cGlyph > 0)
{
if (pstro->ulCharInc == 0)
{
if (!bM64CachedProportionalText24(ppdev, pcf, pgp, cGlyph))
goto ReturnFalse;
}
else
{
if (!bM64CachedFixedText24(ppdev, pcf, pgp, cGlyph, pstro->ulCharInc))
goto ReturnFalse;
}
}
} while (bMoreGlyphs);
}
else
{
if (!bM64CachedClippedText24(ppdev, pcf, pstro, pco))
goto ReturnFalse;
}
}
else
{
DISPDBG((4, "Text too big to cache: %li x %li",
pfo->cxMax, pstro->rclBkGround.bottom - pstro->rclBkGround.top));
if (!bM64GeneralText24(ppdev, pstro, pco))
goto ReturnFalse;
}
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 2);
M64_OD(pjMmBase, DST_CNTL, DST_CNTL_XDir | DST_CNTL_YDir);
M64_OD(pjMmBase, DP_PIX_WIDTH, ppdev->ulMonoPixelWidth);
return(TRUE);
ReturnFalse:
M64_CHECK_FIFO_SPACE(ppdev, pjMmBase, 2);
M64_OD(pjMmBase, DST_CNTL, DST_CNTL_XDir | DST_CNTL_YDir);
M64_OD(pjMmBase, DP_PIX_WIDTH, ppdev->ulMonoPixelWidth);
return(FALSE);
}
/******************************Public*Routine******************************\
* BOOL DrvTextOut
*
\**************************************************************************/
BOOL DrvTextOut(
SURFOBJ* pso,
STROBJ* pstro,
FONTOBJ* pfo,
CLIPOBJ* pco,
RECTL* prclExtra, // If we had set GCAPS_HORIZSTRIKE, we would have
// to fill these extra rectangles (it is used
// largely for underlines). It's not a big
// performance win (GDI will call our DrvBitBlt
// to draw the extra rectangles).
RECTL* prclOpaque,
BRUSHOBJ* pboFore,
BRUSHOBJ* pboOpaque,
POINTL* pptlBrush, // Always unused, unless GCAPS_ARBRUSHOPAQUE set
MIX mix) // Always a copy mix (0x0d0d)
{
PDEV* ppdev;
DSURF* pdsurf;
OH* poh;
// The DDI spec says we'll only ever get foreground and background
// mixes of R2_COPYPEN:
ASSERTDD(mix == 0x0d0d, "GDI should only give us a copy mix");
pdsurf = (DSURF*) pso->dhsurf;
if (pdsurf->dt != DT_DIB)
{
poh = pdsurf->poh;
ppdev = (PDEV*) pso->dhpdev;
ppdev->xOffset = poh->x;
ppdev->yOffset = poh->y;
if (!ppdev->pfnTextOut(ppdev, pstro, pfo, pco, prclOpaque, pboFore,
pboOpaque))
{
if (DIRECT_ACCESS(ppdev))
{
BANK bnk;
vBankStart(ppdev,
(prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround,
pco,
&bnk);
do {
EngTextOut(bnk.pso, pstro, pfo, bnk.pco, prclExtra, prclOpaque,
pboFore, pboOpaque, pptlBrush, mix);
} while (bBankEnum(&bnk));
}
else
{
BOOL b;
BYTE* pjBits;
BYTE* pjScan0;
HSURF hsurfDst;
LONG lDelta;
RECTL rclDst;
RECTL rclScreen;
SIZEL sizl;
SURFOBJ* psoTmp;
b = FALSE; // For error cases, assume we'll fail
/*
rclDst.left = 0;
rclDst.top = 0;
rclDst.right = pdsurf->sizl.cx;
rclDst.bottom = pdsurf->sizl.cy;
*/
rclDst = (prclOpaque != NULL) ? *prclOpaque : pstro->rclBkGround;
if ((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL))
{
rclDst.left = max(rclDst.left, pco->rclBounds.left);
rclDst.top = max(rclDst.top, pco->rclBounds.top);
rclDst.right = min(rclDst.right, pco->rclBounds.right);
rclDst.bottom = min(rclDst.bottom, pco->rclBounds.bottom);
}
sizl.cx = rclDst.right - rclDst.left;
sizl.cy = rclDst.bottom - rclDst.top;
{
// We need to create a temporary work buffer. We have to do
// some fudging with the offsets so that the upper-left corner
// of the (relative coordinates) clip object bounds passed to
// GDI will be transformed to the upper-left corner of our
// temporary bitmap.
// The alignment doesn't have to be as tight as this at 16bpp
// and 32bpp, but it won't hurt:
lDelta = (((rclDst.right + 3) & ~3L) - (rclDst.left & ~3L))
* ppdev->cjPelSize;
// We're actually only allocating a bitmap that is 'sizl.cx' x
// 'sizl.cy' in size:
pjBits = AtiAllocMem(LMEM_FIXED, 0, lDelta * sizl.cy);
if (pjBits == NULL)
goto Error_2;
// We now adjust the surface's 'pvScan0' so that when GDI thinks
// it's writing to pixel (rclDst.top, rclDst.left), it will
// actually be writing to the upper-left pixel of our temporary
// bitmap:
pjScan0 = pjBits - (rclDst.top * lDelta)
- ((rclDst.left & ~3L) * ppdev->cjPelSize);
ASSERTDD((((ULONG_PTR) pjScan0) & 3) == 0,
"pvScan0 must be dword aligned!");
hsurfDst = (HSURF) EngCreateBitmap(
sizl, // Bitmap covers rectangle
lDelta, // Use this delta
ppdev->iBitmapFormat, // Same colour depth
BMF_TOPDOWN, // Must have a positive delta
pjScan0); // Where (0, 0) would be
if ((hsurfDst == 0) ||
(!EngAssociateSurface(hsurfDst, ppdev->hdevEng, 0)))
goto Error_3;
psoTmp = EngLockSurface(hsurfDst);
if (psoTmp == NULL)
goto Error_4;
// Make sure that the rectangle we Get/Put from/to the screen
// is in absolute coordinates:
rclScreen.left = rclDst.left + ppdev->xOffset;
rclScreen.right = rclDst.right + ppdev->xOffset;
rclScreen.top = rclDst.top + ppdev->yOffset;
rclScreen.bottom = rclDst.bottom + ppdev->yOffset;
ppdev->pfnGetBits(ppdev, psoTmp, &rclDst, (POINTL*) &rclScreen);
b = EngTextOut(psoTmp, pstro, pfo, pco, prclExtra, prclOpaque,
pboFore, pboOpaque, pptlBrush, mix);
ppdev->pfnPutBits(ppdev, psoTmp, &rclScreen, (POINTL*) &rclDst);
EngUnlockSurface(psoTmp);
Error_4:
EngDeleteSurface(hsurfDst);
Error_3:
AtiFreeMem(pjBits);
}
Error_2:
return(b);
}
}
}
else
{
// We're drawing to a DFB we've converted to a DIB, so just call GDI
// to handle it:
return(EngTextOut(pdsurf->pso, pstro, pfo, pco, prclExtra, prclOpaque,
pboFore, pboOpaque, pptlBrush, mix));
}
return(TRUE);
}
/******************************Public*Routine******************************\
* BOOL bEnableText
*
* Performs the necessary setup for the text drawing subcomponent.
*
\**************************************************************************/
BOOL bEnableText(
PDEV* ppdev)
{
return(TRUE);
}
/******************************Public*Routine******************************\
* VOID vDisableText
*
* Performs the necessary clean-up for the text drawing subcomponent.
*
\**************************************************************************/
VOID vDisableText(PDEV* ppdev)
{
}
/******************************Public*Routine******************************\
* VOID vAssertModeText
*
* Disables or re-enables the text drawing subcomponent in preparation for
* full-screen entry/exit.
*
\**************************************************************************/
VOID vAssertModeText(
PDEV* ppdev,
BOOL bEnable)
{
// If we were to do off-screen glyph caching, we would probably want
// to invalidate our cache here, because it will get destroyed when
// we switch to full-screen.
}
/******************************Public*Routine******************************\
* VOID DrvDestroyFont
*
* We're being notified that the given font is being deallocated; clean up
* anything we've stashed in the 'pvConsumer' field of the 'pfo'.
*
\**************************************************************************/
VOID DrvDestroyFont(
FONTOBJ* pfo)
{
CACHEDFONT* pcf;
pcf = pfo->pvConsumer;
if (pcf != NULL)
{
vFreeCachedFont(pcf);
pfo->pvConsumer = NULL;
}
}