2217 lines
64 KiB
C
2217 lines
64 KiB
C
/******************************Module*Header*******************************\
|
|
* Module Name: textout.c
|
|
*
|
|
* We cache off-screen glyphs linearly in off-screen memory.
|
|
*
|
|
* Copyright (c) 1992-1996 Microsoft Corporation
|
|
* Copyright (c) 1993-1996 Matrox Electronic Systems, Ltd.
|
|
\**************************************************************************/
|
|
|
|
#include "precomp.h"
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
BYTE gajBit[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
|
|
// Converts bit index to set bit
|
|
|
|
RECTL grclMax = { 0, 0, 0x10000, 0x10000 };
|
|
// Maximal clip rectangle for trivial clipping
|
|
|
|
// Array used for getting the mirror image of bytes:
|
|
|
|
BYTE gajFlip[] =
|
|
{
|
|
0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0,
|
|
0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0,
|
|
0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8,
|
|
0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,
|
|
0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4,
|
|
0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4,
|
|
0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC,
|
|
0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,
|
|
0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2,
|
|
0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2,
|
|
0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
|
|
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,
|
|
0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6,
|
|
0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6,
|
|
0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE,
|
|
0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,
|
|
0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1,
|
|
0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1,
|
|
0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9,
|
|
0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9,
|
|
0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5,
|
|
0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
|
|
0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED,
|
|
0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD,
|
|
0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3,
|
|
0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,
|
|
0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB,
|
|
0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB,
|
|
0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7,
|
|
0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,
|
|
0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF,
|
|
0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF,
|
|
};
|
|
|
|
/******************************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******************************\
|
|
* VOID vExpandGlyph
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vExpandGlyph(
|
|
PDEV* ppdev,
|
|
BYTE* pj, // Can be unaligned
|
|
LONG lSkip,
|
|
LONG cj,
|
|
LONG cy,
|
|
BOOL bHwBug)
|
|
{
|
|
BYTE* pjBase;
|
|
ULONG* pulDma;
|
|
LONG cFifo;
|
|
LONG cd;
|
|
ULONG UNALIGNED* pulSrc;
|
|
LONG cEdgeCases;
|
|
LONG i;
|
|
ULONG ul;
|
|
|
|
ASSERTDD((bHwBug == 1) || (bHwBug == 0), "Expect binary bHwBug");
|
|
|
|
pjBase = ppdev->pjBase;
|
|
pulDma = (ULONG*) (pjBase + DMAWND);
|
|
cd = cj >> 2;
|
|
pulSrc = (ULONG UNALIGNED*) pj;
|
|
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
BLT_WRITE_ON(ppdev, pjBase);
|
|
|
|
// Make sure we have room for very first write that accounts for
|
|
// the hardware bug:
|
|
|
|
cFifo = FIFOSIZE - 1;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
|
|
// If we have to work around the hardware bug, we usually have to have
|
|
// two FIFO entries open for the work-around write, and for the last
|
|
// edge write:
|
|
|
|
cEdgeCases = 1 + bHwBug;
|
|
|
|
switch (cj & 3)
|
|
{
|
|
case 0:
|
|
cEdgeCases = bHwBug; // No last edge write
|
|
|
|
do {
|
|
if (bHwBug)
|
|
CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
|
|
|
|
for (i = cd; i != 0; i--)
|
|
{
|
|
if (--cFifo < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 1;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
|
|
}
|
|
|
|
if ((cFifo -= cEdgeCases) < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 1;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip);
|
|
|
|
} while (--cy != 0);
|
|
break;
|
|
|
|
case 1:
|
|
do {
|
|
if (bHwBug)
|
|
CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
|
|
|
|
for (i = cd; i != 0; i--)
|
|
{
|
|
if (--cFifo < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 1;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
|
|
}
|
|
|
|
if ((cFifo -= cEdgeCases) < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 2;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
CP_WRITE_DMA(ppdev, pulDma, *((BYTE*) pulSrc));
|
|
pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip + 1);
|
|
|
|
} while (--cy != 0);
|
|
break;
|
|
|
|
case 2:
|
|
do {
|
|
if (bHwBug)
|
|
CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
|
|
|
|
for (i = cd; i != 0; i--)
|
|
{
|
|
if (--cFifo < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 1;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
|
|
}
|
|
|
|
if ((cFifo -= cEdgeCases) < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 2;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
CP_WRITE_DMA(ppdev, pulDma, *((WORD UNALIGNED *) pulSrc));
|
|
pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip + 2);
|
|
|
|
} while (--cy != 0);
|
|
break;
|
|
|
|
case 3:
|
|
do {
|
|
if (bHwBug)
|
|
CP_WRITE_DMA(ppdev, pulDma, 0); // Account for hardware bug
|
|
|
|
for (i = cd; i != 0; i--)
|
|
{
|
|
if (--cFifo < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 1;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
CP_WRITE_DMA(ppdev, pulDma, *pulSrc++);
|
|
}
|
|
|
|
if ((cFifo -= cEdgeCases) < 0)
|
|
{
|
|
cFifo = FIFOSIZE - 2;
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
}
|
|
ul = *((WORD UNALIGNED *) pulSrc) | (*(((BYTE*) pulSrc) + 2) << 16);
|
|
CP_WRITE_DMA(ppdev, pulDma, ul);
|
|
pulSrc = (ULONG UNALIGNED*) ((BYTE*) pulSrc + lSkip + 3);
|
|
|
|
} while (--cy != 0);
|
|
break;
|
|
}
|
|
|
|
BLT_WRITE_OFF(ppdev, pjBase);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMgaGeneralText
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMgaGeneralText(
|
|
PDEV* ppdev,
|
|
STROBJ* pstro,
|
|
CLIPOBJ* pco)
|
|
{
|
|
BYTE* pjBase;
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
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 cx;
|
|
LONG cy;
|
|
LONG xLeft;
|
|
LONG yTop;
|
|
LONG xRight;
|
|
LONG yBottom;
|
|
LONG lDelta;
|
|
LONG cj;
|
|
BYTE* pjGlyph;
|
|
BOOL bHwBug;
|
|
LONG xAlign;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
xOffset = ppdev->xOffset;
|
|
yOffset = ppdev->yOffset;
|
|
iDComplexity = (pco == NULL) ? DC_TRIVIAL : 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 = &grclMax;
|
|
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;
|
|
|
|
// Loop through all the glyphs for this rectangle:
|
|
|
|
while (TRUE)
|
|
{
|
|
cxGlyph = pgb->sizlBitmap.cx;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
pjGlyph = pgb->aj;
|
|
|
|
if ((prclClip->left <= ptlOrigin.x) &&
|
|
(prclClip->top <= ptlOrigin.y) &&
|
|
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
|
|
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
|
|
{
|
|
//-----------------------------------------------------
|
|
// Unclipped glyph
|
|
|
|
CHECK_FIFO_SPACE(pjBase, 7);
|
|
CP_WRITE(pjBase, DWG_LEN, cyGlyph);
|
|
CP_WRITE(pjBase, DWG_YDST, yOffset + ptlOrigin.y);
|
|
CP_WRITE(pjBase, DWG_FXLEFT, xOffset + ptlOrigin.x);
|
|
CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + ptlOrigin.x + cxGlyph - 1);
|
|
|
|
bHwBug = (cxGlyph >= 128);
|
|
|
|
if (!bHwBug)
|
|
{
|
|
CP_WRITE(pjBase, DWG_SHIFT, 0);
|
|
CP_WRITE(pjBase, DWG_AR3, 0);
|
|
CP_START(pjBase, DWG_AR0, cxGlyph - 1);
|
|
}
|
|
else
|
|
{
|
|
CP_WRITE(pjBase, DWG_AR3, 8);
|
|
CP_WRITE(pjBase, DWG_AR0, cxGlyph + 31);
|
|
CP_START(pjBase, DWG_SHIFT, (24 << 16));
|
|
}
|
|
|
|
vExpandGlyph(ppdev, pjGlyph, 0, (cxGlyph + 7) >> 3, cyGlyph, bHwBug);
|
|
}
|
|
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 (((cx = xRight - xLeft) > 0) &&
|
|
((cy = yBottom - yTop) > 0))
|
|
{
|
|
CHECK_FIFO_SPACE(pjBase, 7);
|
|
CP_WRITE(pjBase, DWG_LEN, cy);
|
|
CP_WRITE(pjBase, DWG_YDST, yOffset + yTop);
|
|
CP_WRITE(pjBase, DWG_FXLEFT, xOffset + xLeft);
|
|
CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + xRight - 1);
|
|
|
|
xAlign = (xLeft - ptlOrigin.x) & 31;
|
|
|
|
bHwBug = (cx >= 128) && (xAlign <= 15);
|
|
|
|
if (!bHwBug)
|
|
{
|
|
CP_WRITE(pjBase, DWG_SHIFT, 0);
|
|
CP_WRITE(pjBase, DWG_AR3, xAlign);
|
|
CP_START(pjBase, DWG_AR0, xAlign + cx - 1);
|
|
}
|
|
else
|
|
{
|
|
CP_WRITE(pjBase, DWG_AR3, xAlign + 8);
|
|
CP_WRITE(pjBase, DWG_AR0, xAlign + cx + 31);
|
|
CP_START(pjBase, DWG_SHIFT, (24 << 16));
|
|
}
|
|
|
|
lDelta = (cxGlyph + 7) >> 3;
|
|
pjGlyph += (yTop - ptlOrigin.y) * lDelta
|
|
+ (((xLeft - ptlOrigin.x) >> 3) & ~3);
|
|
cj = (xAlign + cx + 7) >> 3;
|
|
|
|
vExpandGlyph(ppdev, pjGlyph, lDelta - cj, cj, cy, bHwBug);
|
|
}
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vMilGeneralText
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vMilGeneralText(
|
|
PDEV* ppdev,
|
|
STROBJ* pstro,
|
|
CLIPOBJ* pco)
|
|
{
|
|
BYTE* pjBase;
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
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 cx;
|
|
LONG cy;
|
|
LONG xLeft;
|
|
LONG yTop;
|
|
LONG xRight;
|
|
LONG yBottom;
|
|
LONG lDelta;
|
|
LONG cj;
|
|
BYTE* pjGlyph;
|
|
BOOL bHwBug;
|
|
LONG xAlign;
|
|
BOOL bClipSet;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
xOffset = ppdev->xOffset;
|
|
yOffset = ppdev->yOffset;
|
|
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
|
|
bClipSet = FALSE;
|
|
|
|
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 = &grclMax;
|
|
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;
|
|
|
|
// Loop through all the glyphs for this rectangle:
|
|
|
|
while (TRUE)
|
|
{
|
|
cxGlyph = pgb->sizlBitmap.cx;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
pjGlyph = pgb->aj;
|
|
|
|
if ((prclClip->left <= ptlOrigin.x) &&
|
|
(prclClip->top <= ptlOrigin.y) &&
|
|
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
|
|
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
|
|
{
|
|
//-----------------------------------------------------
|
|
// Unclipped glyph
|
|
|
|
if (bClipSet)
|
|
{
|
|
// A clipped glyph was just drawn.
|
|
CHECK_FIFO_SPACE(pjBase, 2);
|
|
CP_WRITE(pjBase, DWG_CXLEFT, 0);
|
|
CP_WRITE(pjBase, DWG_CXRIGHT, (ppdev->cxMemory - 1));
|
|
bClipSet = FALSE;
|
|
}
|
|
|
|
CHECK_FIFO_SPACE(pjBase, 4);
|
|
|
|
CP_WRITE(pjBase, DWG_FXBNDRY,
|
|
((xOffset + ptlOrigin.x + cxGlyph - 1) << bfxright_SHIFT) |
|
|
((xOffset + ptlOrigin.x) & bfxleft_MASK));
|
|
|
|
// ylength_MASK not is needed since coordinates are within range
|
|
|
|
CP_WRITE(pjBase, DWG_YDSTLEN,
|
|
((yOffset + ptlOrigin.y) << yval_SHIFT) |
|
|
(cyGlyph));
|
|
CP_WRITE(pjBase, DWG_AR3, 0);
|
|
CP_START(pjBase, DWG_AR0, (cxGlyph - 1));
|
|
|
|
vExpandGlyph(ppdev, pjGlyph, 0, (cxGlyph + 7) >> 3, cyGlyph, FALSE);
|
|
}
|
|
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 (((cx = xRight - xLeft) > 0) &&
|
|
((cy = yBottom - yTop) > 0))
|
|
{
|
|
// We have to set the clipping rectangle.
|
|
CHECK_FIFO_SPACE(pjBase, 6);
|
|
CP_WRITE(pjBase, DWG_CXLEFT, (xOffset + xLeft));
|
|
CP_WRITE(pjBase, DWG_CXRIGHT, (xOffset + xRight - 1));
|
|
bClipSet = TRUE;
|
|
|
|
xAlign = (xLeft - ptlOrigin.x) & 0x7;
|
|
xLeft -= xAlign;
|
|
cx += xAlign;
|
|
|
|
CP_WRITE(pjBase, DWG_FXBNDRY,
|
|
((xOffset + xRight - 1) << bfxright_SHIFT) |
|
|
((xOffset + xLeft) & bfxleft_MASK));
|
|
|
|
// ylength_MASK not is needed since coordinates are within range
|
|
|
|
CP_WRITE(pjBase, DWG_YDSTLEN,
|
|
((yOffset + yTop) << yval_SHIFT) |
|
|
(cy));
|
|
|
|
CP_WRITE(pjBase, DWG_AR3, 0);
|
|
CP_START(pjBase, DWG_AR0, (cx - 1));
|
|
|
|
// Send the bits to the DMA window.
|
|
lDelta = (cxGlyph + 7) >> 3;
|
|
pjGlyph += (yTop - ptlOrigin.y) * lDelta
|
|
+ ((xLeft - ptlOrigin.x) >> 3);
|
|
cj = (cx + 7) >> 3;
|
|
|
|
vExpandGlyph(ppdev, pjGlyph, lDelta - cj, cj, cy, FALSE);
|
|
}
|
|
}
|
|
|
|
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);
|
|
|
|
if (bClipSet)
|
|
{
|
|
// Clear the clipping registers.
|
|
CHECK_FIFO_SPACE(pjBase, 2);
|
|
CP_WRITE(pjBase, DWG_CXLEFT, 0);
|
|
CP_WRITE(pjBase, DWG_CXRIGHT, (ppdev->cxMemory - 1));
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* CACHEDFONT* pcfAllocateCachedFont()
|
|
*
|
|
* Initializes our font data structure.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
CACHEDFONT* pcfAllocateCachedFont(
|
|
PDEV* ppdev)
|
|
{
|
|
CACHEDFONT* pcf;
|
|
CACHEDGLYPH** ppcg;
|
|
LONG i;
|
|
|
|
pcf = EngAllocMem(FL_ZERO_MEMORY, sizeof(CACHEDFONT), ALLOC_TAG);
|
|
|
|
if (pcf != NULL)
|
|
{
|
|
// Insert this node into the doubly-linked cached-font list hanging
|
|
// off the PDEV:
|
|
|
|
pcf->pcfNext = ppdev->cfSentinel.pcfNext;
|
|
pcf->pcfPrev = &ppdev->cfSentinel;
|
|
ppdev->cfSentinel.pcfNext = pcf;
|
|
pcf->pcfNext->pcfPrev = pcf;
|
|
|
|
// 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;
|
|
|
|
// Remove this node from our cached-font linked-list:
|
|
|
|
pcf->pcfPrev->pcfNext = pcf->pcfNext;
|
|
pcf->pcfNext->pcfPrev = pcf->pcfPrev;
|
|
|
|
// Free all glyph position allocations associated with this font:
|
|
|
|
pga = pcf->pgaChain;
|
|
while (pga != NULL)
|
|
{
|
|
pgaNext = pga->pgaNext;
|
|
EngFreeMem(pga);
|
|
pga = pgaNext;
|
|
}
|
|
|
|
EngFreeMem(pcf);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vBlowGlyphCache()
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vBlowGlyphCache(
|
|
PDEV* ppdev)
|
|
{
|
|
CACHEDFONT* pcfSentinel;
|
|
CACHEDFONT* pcf;
|
|
GLYPHALLOC* pga;
|
|
GLYPHALLOC* pgaNext;
|
|
CACHEDGLYPH** ppcg;
|
|
LONG i;
|
|
|
|
ASSERTDD(ppdev->flStatus & STAT_GLYPH_CACHE, "No glyph cache to be blown");
|
|
|
|
// Reset our current glyph variables:
|
|
|
|
ppdev->ulGlyphCurrent = ppdev->ulGlyphStart;
|
|
|
|
///////////////////////////////////////////////////////////////////
|
|
|
|
// Now invalidate all active cached fonts:
|
|
|
|
pcfSentinel = &ppdev->cfSentinel;
|
|
for (pcf = pcfSentinel->pcfNext; pcf != pcfSentinel; pcf = pcf->pcfNext)
|
|
{
|
|
// Reset all the hash table entries to point to the cached-font
|
|
// sentinel. This effectively resets the cache for this font:
|
|
|
|
for (ppcg = &pcf->apcg[0], i = GLYPH_HASH_SIZE; i != 0; i--, ppcg++)
|
|
{
|
|
*ppcg = &pcf->cgSentinel;
|
|
}
|
|
|
|
// We may as well free all glyph position allocations for this font:
|
|
|
|
pga = pcf->pgaChain;
|
|
while (pga != NULL)
|
|
{
|
|
pgaNext = pga->pgaNext;
|
|
EngFreeMem(pga);
|
|
pga = pgaNext;
|
|
}
|
|
|
|
pcf->pgaChain = NULL;
|
|
pcf->cjAlloc = 0;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vTrimAndPackGlyph
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vTrimAndPackGlyph(
|
|
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
|
|
|
|
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++;
|
|
}
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Return results
|
|
|
|
*pcxGlyph = cxGlyph;
|
|
*pcyGlyph = cyGlyph;
|
|
*pptlOrigin = ptlOrigin;
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vPackGlyph
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vPackGlyph(
|
|
BYTE* pjBuf,
|
|
BYTE* pjGlyph,
|
|
LONG cxGlyph,
|
|
LONG cyGlyph)
|
|
{
|
|
LONG cjSrcWidth;
|
|
BYTE jSrc;
|
|
BYTE* pjSrc;
|
|
BYTE* pjDst;
|
|
LONG cAlign;
|
|
LONG i;
|
|
LONG j;
|
|
LONG cRem;
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Pack the glyph:
|
|
|
|
cjSrcWidth = (cxGlyph + 7) >> 3;
|
|
cRem = ((cxGlyph - 1) & 7) + 1; // 0 -> 8
|
|
cAlign = 0;
|
|
|
|
pjSrc = pjGlyph;
|
|
pjDst = pjBuf;
|
|
*pjDst = 0; // Have to zero very first byte
|
|
|
|
i = cyGlyph;
|
|
do {
|
|
j = cjSrcWidth;
|
|
do {
|
|
jSrc = *pjSrc;
|
|
|
|
*(pjDst) |= (jSrc >> (cAlign));
|
|
|
|
// Note that we may modify a byte past the end of our
|
|
// destination buffer, which is why we reserved an
|
|
// extra byte:
|
|
|
|
*(pjDst + 1) = (jSrc << (8 - cAlign));
|
|
|
|
pjSrc++;
|
|
pjDst++;
|
|
|
|
} while (--j != 0);
|
|
|
|
pjDst--;
|
|
cAlign += cRem;
|
|
if (cAlign >= 8)
|
|
{
|
|
cAlign -= 8;
|
|
pjDst++;
|
|
}
|
|
|
|
} while (--i != 0);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bPutGlyphInCache
|
|
*
|
|
* 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.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bPutGlyphInCache(
|
|
PDEV* ppdev,
|
|
CACHEDGLYPH* pcg,
|
|
GLYPHBITS* pgb)
|
|
{
|
|
BYTE* pjBase;
|
|
BYTE* pjGlyph;
|
|
LONG cxGlyph;
|
|
LONG cyGlyph;
|
|
POINTL ptlOrigin;
|
|
BYTE* pjSrc;
|
|
ULONG* pulSrc;
|
|
ULONG* pulDst;
|
|
LONG i;
|
|
LONG cPels;
|
|
ULONG ulGlyphThis;
|
|
ULONG ulGlyphNext;
|
|
ULONG ul;
|
|
ULONG ulStart;
|
|
BYTE ajBuf[MAX_GLYPH_SIZE + 4]; // Leave room at end for scratch space
|
|
|
|
pjBase = ppdev->pjBase;
|
|
|
|
pjGlyph = pgb->aj;
|
|
cyGlyph = pgb->sizlBitmap.cy;
|
|
cxGlyph = pgb->sizlBitmap.cx;
|
|
ptlOrigin = pgb->ptlOrigin;
|
|
|
|
vTrimAndPackGlyph(&ajBuf[0], pjGlyph, &cxGlyph, &cyGlyph, &ptlOrigin);
|
|
|
|
ASSERTDD(((cyGlyph * cxGlyph + 7) / 8 + 1) <= sizeof(ajBuf),
|
|
"Overran end of temporary glyph storage");
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Find spot for glyph in off-screen memory
|
|
|
|
cPels = cyGlyph * cxGlyph; // Note that this may be zero
|
|
ulGlyphThis = ppdev->ulGlyphCurrent;
|
|
ulGlyphNext = ulGlyphThis + ((cPels + 31) & ~31); // Dword aligned
|
|
|
|
if (ulGlyphNext >= ppdev->ulGlyphEnd)
|
|
{
|
|
// There's isn't enough free room in the off-screen cache for another
|
|
// glyph. Let the caller know that it should call 'vBlowGlyphCache'
|
|
// to free up space.
|
|
//
|
|
// First, make sure that this glyph will fit in the cache when it's
|
|
// empty, too:
|
|
|
|
ASSERTDD(ppdev->ulGlyphStart + cPels < ppdev->ulGlyphEnd,
|
|
"Glyph can't fit in empty cache -- where's the higher-level check?");
|
|
|
|
return(FALSE);
|
|
}
|
|
|
|
// Remember where the next glyph goes:
|
|
|
|
ppdev->ulGlyphCurrent = ulGlyphNext;
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Initialize the glyph fields
|
|
|
|
// Note that cxLessOne and ulLinearEnd will be invalid for a
|
|
// 'space' character, so the rendering routine had better watch
|
|
// for a height of zero:
|
|
|
|
pcg->ptlOrigin = ptlOrigin;
|
|
pcg->cy = cyGlyph;
|
|
pcg->cxLessOne = cxGlyph - 1;
|
|
pcg->ulLinearStart = ulGlyphThis;
|
|
pcg->ulLinearEnd = ulGlyphThis + cPels - 1;
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Download the glyph
|
|
|
|
ulStart = ulGlyphThis >> 3;
|
|
|
|
// Copy the bit flipped glyph to off-screen:
|
|
|
|
if (ppdev->ulBoardId == MGA_STORM)
|
|
{
|
|
pulSrc = (ULONG*) ajBuf;
|
|
pulDst = (ULONG*) (ppdev->pjScreen + ulStart);
|
|
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
|
|
START_DIRECT_ACCESS_STORM(ppdev, pjBase);
|
|
|
|
for (i = (cPels + 31) >> 5; i != 0; i--)
|
|
{
|
|
*pulDst++ = *pulSrc++;
|
|
}
|
|
|
|
END_DIRECT_ACCESS_STORM(ppdev, pjBase);
|
|
}
|
|
else
|
|
{
|
|
pjSrc = ajBuf;
|
|
pulDst = (ULONG*) (ppdev->pjBase + SRCWND + (ulStart & 31));
|
|
|
|
if (ppdev->iBitmapFormat != BMF_8BPP)
|
|
{
|
|
// We have to set the plane write mask even when using direct
|
|
// access. It doesn't matter at 8bpp:
|
|
|
|
CHECK_FIFO_SPACE(pjBase, 1);
|
|
CP_WRITE(pjBase, DWG_PLNWT, plnwt_ALL);
|
|
}
|
|
|
|
CHECK_FIFO_SPACE(pjBase, FIFOSIZE);
|
|
|
|
WAIT_NOT_BUSY(pjBase);
|
|
|
|
CP_WRITE(pjBase, HST_DSTPAGE, ulStart);
|
|
|
|
START_DIRECT_ACCESS_MGA_NO_WAIT(ppdev, pjBase);
|
|
|
|
for (i = (cPels + 31) >> 5; i != 0; i--)
|
|
{
|
|
ul = gajFlip[*pjSrc++];
|
|
ul |= gajFlip[*pjSrc++] << 8;
|
|
ul |= gajFlip[*pjSrc++] << 16;
|
|
ul |= gajFlip[*pjSrc++] << 24;
|
|
|
|
// The '0' specifies a zero offset from pointer 'pulDst':
|
|
|
|
CP_WRITE_DIRECT(pulDst, 0, ul);
|
|
|
|
pulDst++;
|
|
}
|
|
|
|
END_DIRECT_ACCESS_MGA(ppdev, pjBase);
|
|
|
|
if (ppdev->iBitmapFormat != BMF_8BPP)
|
|
{
|
|
// Restore the plane write mask:
|
|
|
|
CHECK_FIFO_SPACE(pjBase, 1);
|
|
CP_WRITE(pjBase, DWG_PLNWT, ppdev->ulPlnWt);
|
|
}
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************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)
|
|
{
|
|
GLYPHALLOC* pga;
|
|
CACHEDGLYPH* pcg;
|
|
LONG cjCachedGlyph;
|
|
HGLYPH hg;
|
|
LONG iHash;
|
|
CACHEDGLYPH* pcgFind;
|
|
|
|
Restart:
|
|
|
|
// First, calculate the amount of storage we'll need for this glyph:
|
|
|
|
cjCachedGlyph = sizeof(CACHEDGLYPH);
|
|
|
|
if (cjCachedGlyph > pcf->cjAlloc)
|
|
{
|
|
// Have to allocate a new glyph allocation structure:
|
|
|
|
pga = EngAllocMem(FL_ZERO_MEMORY, GLYPH_ALLOC_SIZE, ALLOC_TAG);
|
|
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]));
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////
|
|
// Download the glyph into off-screen memory:
|
|
|
|
if (!bPutGlyphInCache(ppdev, pcg, pgp->pgdf->pgb))
|
|
{
|
|
// If there was no more room in off-screen memory, blow the
|
|
// glyph cache and start over. Note that this assumes that
|
|
// the glyph will fit in the cache when the cache is completely
|
|
// empty.
|
|
|
|
vBlowGlyphCache(ppdev);
|
|
goto Restart;
|
|
}
|
|
|
|
return(pcg);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bMgaCachedProportionalText
|
|
*
|
|
* Draws proportionally spaced glyphs via glyph caching for the MGA.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bMgaCachedProportionalText(
|
|
PDEV* ppdev,
|
|
CACHEDFONT* pcf,
|
|
GLYPHPOS* pgp,
|
|
LONG cGlyph)
|
|
{
|
|
BYTE* pjBase;
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
CHAR cFifo;
|
|
HGLYPH hg;
|
|
CACHEDGLYPH* pcg;
|
|
LONG cy;
|
|
LONG x;
|
|
LONG y;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
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; // Traverse collision list, if any
|
|
|
|
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);
|
|
|
|
cFifo = 0; // Have to reset count
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
x = pgp->ptl.x + pcg->ptlOrigin.x + xOffset;
|
|
y = pgp->ptl.y + pcg->ptlOrigin.y + yOffset;
|
|
|
|
// We get a little tricky here and try to amortize the cost of
|
|
// the read for checking the FIFO count on the MGA. Doing so
|
|
// gave us a 6% and 14% win on 21pt and 16pt text, respectively,
|
|
// on a P90:
|
|
|
|
cFifo -= 6;
|
|
if (cFifo < 0)
|
|
{
|
|
do {
|
|
cFifo = GET_FIFO_SPACE(pjBase) - 6;
|
|
} while (cFifo < 0);
|
|
}
|
|
|
|
CP_WRITE(pjBase, DWG_LEN, cy);
|
|
CP_WRITE(pjBase, DWG_YDST, y);
|
|
CP_WRITE(pjBase, DWG_FXLEFT, x);
|
|
CP_WRITE(pjBase, DWG_FXRIGHT, x + pcg->cxLessOne);
|
|
CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
|
|
CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
|
|
}
|
|
} while (pgp++, --cGlyph != 0);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bMilCachedProportionalText
|
|
*
|
|
* Draws proportionally spaced glyphs via glyph caching for the Millennium.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bMilCachedProportionalText(
|
|
PDEV* ppdev,
|
|
CACHEDFONT* pcf,
|
|
GLYPHPOS* pgp,
|
|
LONG cGlyph)
|
|
{
|
|
BYTE* pjBase;
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
CHAR cFifo;
|
|
HGLYPH hg;
|
|
CACHEDGLYPH* pcg;
|
|
LONG cy;
|
|
LONG x;
|
|
LONG y;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
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; // Traverse collision list, if any
|
|
|
|
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);
|
|
|
|
cFifo = 0; // Have to reset count
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
x = pgp->ptl.x + pcg->ptlOrigin.x + xOffset;
|
|
y = pgp->ptl.y + pcg->ptlOrigin.y + yOffset;
|
|
|
|
cFifo -= 4;
|
|
if (cFifo < 0)
|
|
{
|
|
do {
|
|
cFifo = GET_FIFO_SPACE(pjBase) - 4;
|
|
} while (cFifo < 0);
|
|
}
|
|
|
|
CP_WRITE(pjBase, DWG_YDSTLEN, (y << yval_SHIFT) | cy);
|
|
CP_WRITE(pjBase, DWG_FXBNDRY, ((x + pcg->cxLessOne) << bfxright_SHIFT) |
|
|
x);
|
|
CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
|
|
CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
|
|
}
|
|
} while (pgp++, --cGlyph != 0);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bCachedFixedText
|
|
*
|
|
* Draws fixed spaced glyphs via glyph caching.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bCachedFixedText(
|
|
PDEV* ppdev,
|
|
CACHEDFONT* pcf,
|
|
GLYPHPOS* pgp,
|
|
LONG cGlyph,
|
|
ULONG ulCharInc)
|
|
{
|
|
BYTE* pjBase;
|
|
LONG xGlyph;
|
|
LONG yGlyph;
|
|
CHAR cFifo;
|
|
HGLYPH hg;
|
|
CACHEDGLYPH* pcg;
|
|
LONG cy;
|
|
LONG x;
|
|
LONG y;
|
|
|
|
pjBase = ppdev->pjBase;
|
|
xGlyph = ppdev->xOffset + pgp->ptl.x;
|
|
yGlyph = ppdev->yOffset + pgp->ptl.y;
|
|
cFifo = 0;
|
|
|
|
do {
|
|
hg = pgp->hg;
|
|
pcg = pcf->apcg[GLYPH_HASH_FUNC(hg)];
|
|
|
|
while (pcg->hg < hg)
|
|
pcg = pcg->pcgNext; // Traverse collision list, if any
|
|
|
|
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);
|
|
|
|
cFifo = 0; // Have to reset count
|
|
}
|
|
|
|
// 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)
|
|
{
|
|
x = xGlyph + pcg->ptlOrigin.x;
|
|
y = yGlyph + pcg->ptlOrigin.y;
|
|
|
|
cFifo -= 6;
|
|
if (cFifo < 0)
|
|
{
|
|
do {
|
|
cFifo = GET_FIFO_SPACE(pjBase) - 6;
|
|
} while (cFifo < 0);
|
|
}
|
|
|
|
CP_WRITE(pjBase, DWG_LEN, cy);
|
|
CP_WRITE(pjBase, DWG_YDST, y);
|
|
CP_WRITE(pjBase, DWG_FXLEFT, x);
|
|
CP_WRITE(pjBase, DWG_FXRIGHT, x + pcg->cxLessOne);
|
|
CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
|
|
CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
|
|
}
|
|
|
|
xGlyph += ulCharInc;
|
|
|
|
} while (pgp++, --cGlyph != 0);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bCachedClippedText
|
|
*
|
|
* Draws clipped text via glyph caching.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bCachedClippedText(
|
|
PDEV* ppdev,
|
|
CACHEDFONT* pcf,
|
|
STROBJ* pstro,
|
|
CLIPOBJ* pco)
|
|
{
|
|
BOOL bRet;
|
|
BYTE* pjBase;
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
CHAR cFifo;
|
|
BOOL bMoreGlyphs;
|
|
ULONG cGlyphOriginal;
|
|
ULONG cGlyph;
|
|
BOOL bClipSet;
|
|
GLYPHPOS* pgpOriginal;
|
|
GLYPHPOS* pgp;
|
|
LONG xGlyph;
|
|
LONG yGlyph;
|
|
LONG x;
|
|
LONG y;
|
|
LONG xRight;
|
|
LONG cy;
|
|
BOOL bMore;
|
|
CLIPENUM ce;
|
|
RECTL* prclClip;
|
|
ULONG ulCharInc;
|
|
HGLYPH hg;
|
|
CACHEDGLYPH* pcg;
|
|
|
|
ASSERTDD((pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
|
|
"Don't expect trivial clipping in this function");
|
|
|
|
bRet = TRUE;
|
|
pjBase = ppdev->pjBase;
|
|
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:
|
|
|
|
bClipSet = 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;
|
|
}
|
|
cFifo = 0; // Have to reset count
|
|
}
|
|
|
|
// 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->cxLessOne + x;
|
|
|
|
// Do trivial rejection:
|
|
|
|
if ((prclClip->right > x) &&
|
|
(prclClip->bottom > y) &&
|
|
(prclClip->left <= xRight) &&
|
|
(prclClip->top < y + cy))
|
|
{
|
|
// Lazily set the hardware clipping:
|
|
|
|
if (!bClipSet)
|
|
{
|
|
bClipSet = TRUE;
|
|
vSetClipping(ppdev, prclClip);
|
|
cFifo = 0; // Have to initialize count
|
|
}
|
|
|
|
cFifo -= 6;
|
|
if (cFifo < 0)
|
|
{
|
|
do {
|
|
cFifo = GET_FIFO_SPACE(pjBase) - 6;
|
|
} while (cFifo < 0);
|
|
}
|
|
|
|
CP_WRITE(pjBase, DWG_LEN, cy);
|
|
CP_WRITE(pjBase, DWG_YDST, yOffset + y);
|
|
CP_WRITE(pjBase, DWG_FXLEFT, xOffset + x);
|
|
CP_WRITE(pjBase, DWG_FXRIGHT, xOffset + xRight);
|
|
CP_WRITE(pjBase, DWG_AR3, pcg->ulLinearStart);
|
|
CP_START(pjBase, DWG_AR0, pcg->ulLinearEnd);
|
|
}
|
|
}
|
|
|
|
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 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;
|
|
LONG xOffset;
|
|
LONG yOffset;
|
|
DSURF* pdsurf;
|
|
OH* poh;
|
|
BYTE* pjBase;
|
|
ULONG cGlyph;
|
|
BOOL bMoreGlyphs;
|
|
GLYPHPOS* pgp;
|
|
BYTE iDComplexity;
|
|
CACHEDFONT* pcf;
|
|
RECTL rclOpaque;
|
|
|
|
pdsurf = (DSURF*) pso->dhsurf;
|
|
if (pdsurf->dt != DT_DIB)
|
|
{
|
|
poh = pdsurf->poh;
|
|
ppdev = (PDEV*) pso->dhpdev;
|
|
xOffset = poh->x;
|
|
yOffset = poh->y;
|
|
ppdev->xOffset = xOffset;
|
|
ppdev->yOffset = yOffset;
|
|
|
|
// 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");
|
|
|
|
pjBase = ppdev->pjBase;
|
|
|
|
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
|
|
|
|
if (prclOpaque != NULL)
|
|
{
|
|
////////////////////////////////////////////////////////////
|
|
// Opaque Initialization
|
|
////////////////////////////////////////////////////////////
|
|
|
|
if (iDComplexity == DC_TRIVIAL)
|
|
{
|
|
|
|
DrawOpaqueRect:
|
|
|
|
if (ppdev->ulBoardId == MGA_STORM)
|
|
{
|
|
CHECK_FIFO_SPACE(pjBase, 4);
|
|
if (ppdev->iBitmapFormat == BMF_24BPP)
|
|
{
|
|
CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + atype_RPL + blockm_OFF +
|
|
pattern_OFF + transc_BG_OPAQUE +
|
|
arzero_ZERO + sgnzero_ZERO + shftzero_ZERO +
|
|
solid_SOLID + bop_SRCCOPY);
|
|
}
|
|
else
|
|
{
|
|
CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + atype_RPL + blockm_ON +
|
|
pattern_OFF + transc_BG_OPAQUE +
|
|
arzero_ZERO + sgnzero_ZERO + shftzero_ZERO +
|
|
solid_SOLID + bop_SRCCOPY);
|
|
}
|
|
CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, pboOpaque->iSolidColor));
|
|
ppdev->HopeFlags = (SIGN_CACHE | ARX_CACHE | PATTERN_CACHE);
|
|
|
|
CP_WRITE(pjBase, DWG_FXBNDRY,
|
|
(((prclOpaque->right + xOffset) << bfxright_SHIFT) |
|
|
((prclOpaque->left + xOffset) & bfxleft_MASK)));
|
|
|
|
// ylength_MASK not is needed since coordinates are within range
|
|
|
|
CP_START(pjBase, DWG_YDSTLEN,
|
|
(((prclOpaque->top + yOffset ) << yval_SHIFT) |
|
|
((prclOpaque->bottom - prclOpaque->top))));
|
|
}
|
|
else
|
|
{
|
|
CHECK_FIFO_SPACE(pjBase, 15);
|
|
|
|
CP_WRITE(pjBase, DWG_DWGCTL, opcode_TRAP + atype_RPL + blockm_ON +
|
|
pattern_OFF + transc_BG_OPAQUE +
|
|
bop_SRCCOPY);
|
|
|
|
CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, pboOpaque->iSolidColor));
|
|
|
|
if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
|
|
{
|
|
CP_WRITE(pjBase, DWG_SGN, 0);
|
|
}
|
|
|
|
if (!(GET_CACHE_FLAGS(ppdev, ARX_CACHE)))
|
|
{
|
|
CP_WRITE(pjBase, DWG_AR1, 0);
|
|
CP_WRITE(pjBase, DWG_AR2, 0);
|
|
CP_WRITE(pjBase, DWG_AR4, 0);
|
|
CP_WRITE(pjBase, DWG_AR5, 0);
|
|
}
|
|
|
|
if (!(GET_CACHE_FLAGS(ppdev, PATTERN_CACHE)))
|
|
{
|
|
CP_WRITE(pjBase, DWG_SRC0, 0xFFFFFFFF);
|
|
CP_WRITE(pjBase, DWG_SRC1, 0xFFFFFFFF);
|
|
CP_WRITE(pjBase, DWG_SRC2, 0xFFFFFFFF);
|
|
CP_WRITE(pjBase, DWG_SRC3, 0xFFFFFFFF);
|
|
}
|
|
|
|
ppdev->HopeFlags = (SIGN_CACHE | ARX_CACHE | PATTERN_CACHE);
|
|
|
|
CP_WRITE(pjBase, DWG_FXLEFT, prclOpaque->left + xOffset);
|
|
CP_WRITE(pjBase, DWG_FXRIGHT, prclOpaque->right + xOffset);
|
|
CP_WRITE(pjBase, DWG_LEN, prclOpaque->bottom - prclOpaque->top);
|
|
CP_START(pjBase, DWG_YDST, prclOpaque->top + yOffset);
|
|
}
|
|
}
|
|
else if (iDComplexity == DC_RECT)
|
|
{
|
|
if (bIntersect(prclOpaque, &pco->rclBounds, &rclOpaque))
|
|
{
|
|
prclOpaque = &rclOpaque;
|
|
goto DrawOpaqueRect;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
vClipSolid(ppdev, prclOpaque, pboOpaque->iSolidColor, pco);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////
|
|
// Transparent Initialization
|
|
////////////////////////////////////////////////////////////
|
|
|
|
// Initialize the hardware for transparent text:
|
|
|
|
CHECK_FIFO_SPACE(pjBase, 4);
|
|
|
|
CP_WRITE(pjBase, DWG_FCOL, COLOR_REPLICATE(ppdev, pboFore->iSolidColor));
|
|
|
|
if (!(GET_CACHE_FLAGS(ppdev, SIGN_CACHE)))
|
|
{
|
|
CP_WRITE(pjBase, DWG_SGN, 0);
|
|
}
|
|
|
|
if ((pfo->cxMax <= GLYPH_CACHE_CX) &&
|
|
((pstro->rclBkGround.bottom - pstro->rclBkGround.top) <= GLYPH_CACHE_CY) &&
|
|
(ppdev->flStatus & STAT_GLYPH_CACHE))
|
|
{
|
|
// Complete setup for transparent monochrome expansions from
|
|
// off-screen memory, using block mode if possible:
|
|
|
|
CP_WRITE(pjBase, DWG_DWGCTL, ppdev->ulTextControl);
|
|
CP_WRITE(pjBase, DWG_SHIFT, 0);
|
|
|
|
ppdev->HopeFlags = SIGN_CACHE;
|
|
|
|
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 (ppdev->ulBoardId == MGA_STORM)
|
|
{
|
|
if (!bMilCachedProportionalText(ppdev, pcf, pgp, cGlyph))
|
|
return(FALSE);
|
|
}
|
|
else
|
|
{
|
|
if (!bMgaCachedProportionalText(ppdev, pcf, pgp, cGlyph))
|
|
return(FALSE);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!bCachedFixedText(ppdev, pcf, pgp, cGlyph, pstro->ulCharInc))
|
|
return(FALSE);
|
|
}
|
|
}
|
|
} while (bMoreGlyphs);
|
|
}
|
|
else
|
|
{
|
|
if (!bCachedClippedText(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));
|
|
|
|
// Complete setup for transparent monochrome expansions from the CPU:
|
|
|
|
CP_WRITE(pjBase, DWG_DWGCTL, (opcode_ILOAD + atype_RPL + blockm_OFF +
|
|
bop_SRCCOPY + trans_0 + bltmod_BMONO +
|
|
pattern_OFF + hbgr_SRC_WINDOWS +
|
|
transc_BG_TRANSP));
|
|
|
|
if (!(GET_CACHE_FLAGS(ppdev, ARX_CACHE)))
|
|
{
|
|
CP_WRITE(pjBase, DWG_AR5, 0);
|
|
}
|
|
|
|
ppdev->HopeFlags = SIGN_CACHE;
|
|
|
|
if (ppdev->ulBoardId == MGA_STORM)
|
|
{
|
|
vMilGeneralText(ppdev, pstro, pco);
|
|
}
|
|
else
|
|
{
|
|
vMgaGeneralText(ppdev, pstro, pco);
|
|
}
|
|
}
|
|
}
|
|
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******************************\
|
|
* VOID DrvDestroyFont
|
|
*
|
|
* Note: Don't forget to export this call in 'enable.c', otherwise you'll
|
|
* get some pretty big memory leaks!
|
|
*
|
|
* 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;
|
|
}
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* BOOL bEnableText
|
|
*
|
|
* Performs the necessary setup for the text drawing subcomponent.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
BOOL bEnableText(
|
|
PDEV* ppdev)
|
|
{
|
|
OH* poh;
|
|
CACHEDFONT* pcfSentinel;
|
|
LONG cShift;
|
|
LONG cFactor;
|
|
|
|
if (ppdev->ulBoardId == MGA_STORM)
|
|
{
|
|
if (ppdev->iBitmapFormat == BMF_24BPP)
|
|
{
|
|
ppdev->ulTextControl = opcode_BITBLT + atype_RPL + blockm_OFF +
|
|
bop_SRCCOPY + trans_0 + bltmod_BMONOWF +
|
|
pattern_OFF + hbgr_SRC_EG3 +
|
|
transc_BG_TRANSP + linear_LINEAR_BITBLT;
|
|
}
|
|
else
|
|
{
|
|
ppdev->ulTextControl = opcode_BITBLT + atype_RPL + blockm_ON +
|
|
bop_SRCCOPY + trans_0 + bltmod_BMONOWF +
|
|
pattern_OFF + hbgr_SRC_EG3 +
|
|
transc_BG_TRANSP + linear_LINEAR_BITBLT;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ppdev->ulTextControl = opcode_BITBLT + atype_RPL + blockm_ON +
|
|
bop_SRCCOPY + trans_0 + bltmod_BMONO +
|
|
pattern_OFF + hbgr_SRC_EG3 +
|
|
transc_BG_TRANSP + linear_LINEAR_BITBLT;
|
|
}
|
|
|
|
poh = pohAllocate(ppdev,
|
|
NULL,
|
|
ppdev->cxMemory,
|
|
GLYPH_CACHE_HEIGHT / ppdev->cjPelSize,
|
|
FLOH_MAKE_PERMANENT);
|
|
if (poh != NULL)
|
|
{
|
|
ppdev->flStatus |= STAT_GLYPH_CACHE;
|
|
|
|
// Initialize our doubly-linked cached font list:
|
|
|
|
pcfSentinel = &ppdev->cfSentinel;
|
|
pcfSentinel->pcfNext = pcfSentinel;
|
|
pcfSentinel->pcfPrev = pcfSentinel;
|
|
|
|
// Setup the display adapter specific glyph data.
|
|
//
|
|
// The linear addresses are computed as bit addresses:
|
|
|
|
cFactor = ppdev->cjHwPel * 8;
|
|
|
|
ppdev->ulGlyphStart
|
|
= (ppdev->ulYDstOrg + poh->y * ppdev->cxMemory) * cFactor;
|
|
|
|
ppdev->ulGlyphCurrent = ppdev->ulGlyphStart;
|
|
|
|
ppdev->ulGlyphEnd
|
|
= (ppdev->ulYDstOrg + (poh->y + poh->cy) * ppdev->cxMemory) * cFactor;
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
/******************************Public*Routine******************************\
|
|
* VOID vDisableText
|
|
*
|
|
* Performs the necessary clean-up for the text drawing subcomponent.
|
|
*
|
|
\**************************************************************************/
|
|
|
|
VOID vDisableText(PDEV* ppdev)
|
|
{
|
|
// Here we free any stuff allocated in 'bEnableText'.
|
|
}
|
|
|
|
/******************************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)
|
|
{
|
|
// Our off-screen glyph cache will get destroyed when we switch to
|
|
// full-screen:
|
|
|
|
if (!bEnable)
|
|
{
|
|
if (ppdev->flStatus & STAT_GLYPH_CACHE)
|
|
{
|
|
vBlowGlyphCache(ppdev);
|
|
}
|
|
}
|
|
}
|