mirror of https://github.com/tongzx/nt5src
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
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;
|
|
}
|
|
}
|