Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

724 lines
23 KiB

/*++
Copyright (c) 1991-1995 Microsoft Corporation
Module Name:
Text.c
Abstract:
This module attempts to cache fonts on the VXL video board and draw glyphs
using hardware acceleration,
If the font cannot be cached the Engine is called to draw the glyphs.
Environment:
Revision History:
--*/
#include "driver.h"
//
// The following macro is the hash function for computing the cache
// index from a Glyph Handle and FontId.
//
#define HASH_FUNCTION(GlyphHandle,FontId,yShift) \
((GlyphHandle & 0x7FF) << yShift) + \
(FontId << 7)
//#define CACHE_STATS
//
// Define string object accelerator masks.
//
#define SO_MASK \
(SO_FLAG_DEFAULT_PLACEMENT | SO_ZERO_BEARINGS | \
SO_CHAR_INC_EQUAL_BM_BASE | SO_MAXEXT_EQUAL_BM_SIDE)
#define SO_LTOR (SO_MASK | SO_HORIZONTAL)
#define SO_RTOL (SO_LTOR | SO_REVERSED)
#define SO_TTOB (SO_MASK | SO_VERTICAL)
#define SO_BTOT (SO_TTOB | SO_REVERSED)
static ULONG TextForegroundColor = 0xFFFFFFFF;
static ULONG TextBackgroundColor = 0xFFFFFFFF;
#ifdef CACHE_STATS
static ULONG CacheUnused = Vxl.CacheSize;
static ULONG CharCount = 0;
static ULONG CacheMisses = 0;
static ULONG CacheReplacement = 0;
static ULONG ReplacementTotal = 0;
static ULONG CharTotal = 0;
static ULONG MissTotal = 0;
static ULONG HigherFontId = 0;
static ULONG HigherGlyphHandle = 0;
#endif
static UCHAR ToBigEndian[256] = {
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
};
BOOL
DrvTextOut
(
IN SURFOBJ *pso,
IN STROBJ *pstro,
IN FONTOBJ *pfo,
IN CLIPOBJ *pco,
IN RECTL *prclExtra,
IN RECTL *prclOpaque,
IN BRUSHOBJ *pboFore,
IN BRUSHOBJ *pboOpaque,
IN POINTL *pptlOrg,
IN MIX mix
)
/*++
Routine Description:
This function will cache fonts on the VXL video board and use accelerator
hardware to draw each glyph. An attemp is made to use opaque mode
text output to draw text and background color at the same time. If this
cannot be done then glyph forground and backgrounds are drawn spearately.
Arguments:
MIX is not checked. Since the GCAPS_ARBMIXTEXT capability bit is not
set, mix mode is always R2_COPYPEN.
Return Value:
--*/
{
BOOL bMoreGlyphs;
ULONG LineIndex;
ULONG ByteIndex;
PGLYPHPOS GlyphPosList;
ULONG GlyphCount;
ULONG GlyphHandle;
ULONG CacheIndex;
ULONG FontId;
GLYPHBITS *FontBitMap;
PBYTE BitMapPtr;
ULONG X,Y;
BOOL Allocate;
PULONG CacheData;
ULONG BitMapData;
ULONG SrcAdr,DstAdr,XYCmd,Cmd;
PGLYPHPOS GlyphEnd;
PGLYPHPOS GlyphStart;
LONG GlyphStride;
RECTL OpaqueRectl;
ULONG GlyphBytesPerScan,ShiftAmount;
ULONG yShift;
//
// Make sure the surface is the screen.
//
if (pso->pvBits != (PVOID)Vxl.ScreenBase) {
goto DevFailTextOut;
}
//
// If the width of the glyph is bigger than what the accelerator supports
// or taller than 2 32 bit cache entries
// The font is non cacheable
// Clipping is not trivial OR
// SolidColor is a brush.
// call GDI to draw the text.
//
yShift = (pstro->rclBkGround.bottom - pstro->rclBkGround.top)/32;
if ((pfo->cxMax > 32) ||
(yShift >= 2) ||
(pfo->flFontType & DEVICE_FONTTYPE) ||
(pco->iDComplexity != DC_TRIVIAL) ||
(pboFore->iSolidColor == 0xFFFFFFFFL)) {
goto DevFailTextOut;
}
//
// Set Jaguar foreground color only if it changed since the
// previous call. Changing Foreground/Background color requires
// synchronization.
//
if (TextForegroundColor != pboFore->iSolidColor) {
TextForegroundColor = pboFore->iSolidColor;
DevSetFgColor(TextForegroundColor);
}
//
// Check that the Background color is solid.
// Set Jaguar Background color if it changed.
//
if (prclOpaque != (PRECTL) NULL) {
if (pboOpaque->iSolidColor == 0xFFFFFFFFL) {
goto DevFailTextOut;
}
if (TextBackgroundColor != pboOpaque->iSolidColor) {
TextBackgroundColor = pboOpaque->iSolidColor;
DevSetBgColor(TextBackgroundColor);
}
}
//
// enumerate the string psto into glyphs (GLYPHPOS), then send a draw
// command for each. Deal with clipping later.
//
FontId = pfo->iUniq;
#ifdef CACHE_STATS
if (FontId > HigherFontId) {
HigherFontId = FontId;
}
#endif
if (((pstro->flAccel == SO_LTOR) || (pstro->flAccel == SO_RTOL) ||
(pstro->flAccel == SO_TTOB) || (pstro->flAccel == SO_BTOT)) &&
(prclOpaque != NULL)) {
//
// If the top of the opaque rectangle is less than the top of the
// background rectangle, then fill the region between the top of
// opaque rectangle and the top of the background rectangle and
// reduce the size of the opaque rectangle.
//
OpaqueRectl = *prclOpaque;
if (OpaqueRectl.top < pstro->rclBkGround.top) {
OpaqueRectl.bottom = pstro->rclBkGround.top;
DrvpFillRectangle(&OpaqueRectl, pboOpaque->iSolidColor);
OpaqueRectl.top = pstro->rclBkGround.top;
OpaqueRectl.bottom = prclOpaque->bottom;
}
//
// If the bottom of the opaque rectangle is greater than the bottom
// of the background rectangle, then fill the region between the
// bottom of the background rectangle and the bottom of the opaque
// rectangle and reduce the size of the opaque rectangle.
//
if (OpaqueRectl.bottom > pstro->rclBkGround.bottom) {
OpaqueRectl.top = pstro->rclBkGround.bottom;
DrvpFillRectangle(&OpaqueRectl, pboOpaque->iSolidColor);
OpaqueRectl.top = pstro->rclBkGround.top;
OpaqueRectl.bottom = pstro->rclBkGround.bottom;
}
//
// If the left of the opaque rectangle is less than the left of
// the background rectangle, then fill the region between the
// left of the opaque rectangle and the left of the background
// rectangle.
//
if (OpaqueRectl.left < pstro->rclBkGround.left) {
OpaqueRectl.right = pstro->rclBkGround.left;
DrvpFillRectangle(&OpaqueRectl, pboOpaque->iSolidColor);
OpaqueRectl.right = prclOpaque->right;
}
//
// If the right of the opaque rectangle is greater than the right
// of the background rectangle, then fill the region between the
// right of the opaque rectangle and the right of the background
// rectangle.
//
if (OpaqueRectl.right > pstro->rclBkGround.right) {
OpaqueRectl.left = pstro->rclBkGround.right;
DrvpFillRectangle(&OpaqueRectl, pboOpaque->iSolidColor);
}
Cmd = JAGUAR_TEXT_OPAQUE << XYCMD_CMD_SHIFT;
} else {
//
// We now have a cacheable font and drawable rectangles, first clip and draw
// all opaque rectangles.
//
if (prclOpaque != (PRECTL)NULL) {
DrvpFillRectangle(prclOpaque,pboOpaque->iSolidColor);
}
Cmd = JAGUAR_TEXT_TRANSPARENT << XYCMD_CMD_SHIFT;
}
//
// If the font is fixed pitch, then optimize the computation of
// x and y coordinate values. Otherwise, compute the x and y values
// for each glyph.
//
if (pstro->ulCharInc != 0) {
//
// The font is fixed pitch. Capture the glyph dimensions and
// compute the starting display address.
//
if (pstro->pgp == NULL) {
bMoreGlyphs = STROBJ_bEnum(pstro, &GlyphCount, &GlyphPosList);
} else {
GlyphCount = pstro->cGlyphs;
GlyphPosList = pstro->pgp;
bMoreGlyphs = FALSE;
}
#ifdef CACHE_STATS
CharCount += GlyphCount;
#endif
FontBitMap = GlyphPosList->pgdf->pgb;
X = FontBitMap->sizlBitmap.cx;
Y = FontBitMap->sizlBitmap.cy;
DstAdr = ((GlyphPosList->ptl.y + FontBitMap->ptlOrigin.y) * Vxl.JaguarScreenX) +
((GlyphPosList->ptl.x + FontBitMap->ptlOrigin.x) << Vxl.ColorModeShift) ;
//
// Compute the glyph stride.
//
GlyphStride = ((pstro->ulCharInc) << Vxl.ColorModeShift);
if ((pstro->flAccel & SO_VERTICAL) != 0) {
GlyphStride *= Vxl.JaguarScreenX;
}
//
// If the direction of drawing is reversed, then the stride is
// negative.
//
if ((pstro->flAccel & SO_REVERSED) != 0) {
GlyphStride = -GlyphStride;
}
//
// Output the set of glyphs.
//
do {
GlyphEnd = &GlyphPosList[GlyphCount];
GlyphStart = GlyphPosList;
do {
GlyphHandle = (ULONG) (GlyphStart->hg);
CacheIndex = HASH_FUNCTION(GlyphHandle,FontId,yShift);
CacheIndex &= Vxl.CacheIndexMask;
//
// Get glyph info
//
FontBitMap = GlyphStart->pgdf->pgb;
//
// If FontId or GlyphHandle don't match, cache this glyph.
//
if (Vxl.CacheTag[CacheIndex].FontId != FontId) {
Allocate = TRUE;
} else {
if (Vxl.CacheTag[CacheIndex].GlyphHandle != GlyphHandle) {
Allocate = TRUE;
} else {
Allocate = FALSE;
}
}
if (Allocate) {
//
// Wait for the accelerator to be idle to ensure
// that the glyph being replaced is not in use.
//
WaitForJaguarIdle();
#ifdef CACHE_STATS
CacheMisses++;
if (Vxl.CacheTag[CacheIndex].FontId == FreeTag) {
CacheUnused--;
} else {
CacheReplacement++;
}
if (Vxl.CacheTag[CacheIndex].FontId == FontId) {
DISPDBG((3, "Replacing same font Glyph %x with glyph %x\n",
Vxl.CacheTag[CacheIndex].FontId,
FontId));
}
if (Vxl.CacheTag[CacheIndex].GlyphHandle == GlyphHandle) {
DISPDBG((3, "Replacing same Glyph %x font %x with font %x\n",
GlyphHandle,
Vxl.CacheTag[CacheIndex].FontId,
FontId));
}
if (GlyphHandle > HigherGlyphHandle) {
HigherGlyphHandle = GlyphHandle;
}
#endif
//
// if the entry that needs to be replaced
// is used as extension for a glyph > 32 lines
// go backwards and clear the Id so that if the
// glyph > 32 is used again it'll miss in the cache
//
//
LineIndex = CacheIndex;
while (Vxl.CacheTag[LineIndex].FontId == GlyphExtended) {
Vxl.CacheTag[LineIndex].FontId = FreeTag;
LineIndex--;
}
//
// Clear the entries used by the big glyph that follows the one
// that needs to be replaced
//
LineIndex = CacheIndex+1;
while ((LineIndex < Vxl.CacheSize) && (Vxl.CacheTag[LineIndex].FontId == GlyphExtended)) {
Vxl.CacheTag[LineIndex].FontId = FreeTag;
LineIndex++;
}
//
// Store the tag for the current glyph.
//
Vxl.CacheTag[CacheIndex].FontId = FontId;
Vxl.CacheTag[CacheIndex].GlyphHandle = GlyphHandle;
CacheData = Vxl.FontCacheBase + (CacheIndex << 5);
//
// Fix the bit ordering and store the bitmap
// in off screen video memory.
//
BitMapPtr = FontBitMap->aj;
GlyphBytesPerScan = (X+7) >> 3;
ShiftAmount = (GlyphBytesPerScan-1) << 3;
//
// this will not overflow the cache because the biggest entries
// we can fill only use 2 slots and a 2-slot entry must start on a
// even allocation block.
//
for (LineIndex=0;LineIndex < Y; LineIndex ++) {
BitMapData = 0;
for (ByteIndex = 0; ByteIndex < GlyphBytesPerScan; ByteIndex++) {
BitMapData >>= 8;
BitMapData |= ToBigEndian[*BitMapPtr++] << ShiftAmount;
}
*CacheData++ = BitMapData;
}
//
// If Y is bigger than 32 lines, the glyph that was just cached
// took more than one entry. Fix the CacheTags.
//
for (ByteIndex = 1; LineIndex > 32 ;ByteIndex++) {
Vxl.CacheTag[CacheIndex+ByteIndex].FontId = GlyphExtended;
LineIndex -=32;
}
}
//
// Find out where to draw the glyph and the glyph's starting address
//
SrcAdr = Vxl.FontCacheOffset + (CacheIndex << 7);
XYCmd = Cmd | (Y << XYCMD_Y_SHIFT) | X;
FifoWrite(DstAdr,SrcAdr,XYCmd);
DstAdr += GlyphStride;
GlyphStart += 1;
} while (GlyphStart != GlyphEnd);
if (bMoreGlyphs) {
bMoreGlyphs = STROBJ_bEnum(pstro, &GlyphCount, &GlyphPosList);
#ifdef CACHE_STATS
CharCount += GlyphCount;
#endif
} else {
break;
}
} while (TRUE);
} else {
//
// The font is not fixed pitch. Compute the x and y values for
// each glyph individually.
//
do {
//
// Get each glyph handle, find the physical address and send the
// draw command to the accelerator. Don't worry about clipping yet.
//
bMoreGlyphs = STROBJ_bEnum(pstro, &GlyphCount,&GlyphPosList);
#ifdef CACHE_STATS
CharCount += GlyphCount;
#endif
GlyphEnd = &GlyphPosList[GlyphCount];
GlyphStart = GlyphPosList;
do {
GlyphHandle = (ULONG) (GlyphStart->hg);
CacheIndex = HASH_FUNCTION(GlyphHandle,FontId,yShift);
CacheIndex &= Vxl.CacheIndexMask;
//
// Get glyph info
//
FontBitMap = GlyphStart->pgdf->pgb;
X = FontBitMap->sizlBitmap.cx;
Y = FontBitMap->sizlBitmap.cy;
//
// If FontId or GlyphHandle don't match, cache this glyph.
//
if (Vxl.CacheTag[CacheIndex].FontId != FontId) {
Allocate = TRUE;
} else {
if (Vxl.CacheTag[CacheIndex].GlyphHandle != GlyphHandle) {
Allocate = TRUE;
} else {
Allocate = FALSE;
}
}
if (Allocate) {
//
// Wait for the accelerator to be idle to ensure
// that the glyph being replaced is not in use.
//
WaitForJaguarIdle();
#ifdef CACHE_STATS
CacheMisses++;
#endif
//
// The Glyph that has to be replaced is from the same font,
// wait for the accelerator to be idle before caching the
// glyph.
//
#ifdef CACHE_STATS
if (Vxl.CacheTag[CacheIndex].FontId == FreeTag) {
CacheUnused--;
} else {
CacheReplacement++;
}
if (Vxl.CacheTag[CacheIndex].FontId == FontId) {
DISPDBG((3, "Replacing same font Glyph %x with glyph %x\n",
Vxl.CacheTag[CacheIndex].FontId,
FontId));
}
if (Vxl.CacheTag[CacheIndex].GlyphHandle == GlyphHandle) {
DISPDBG((3, "Replacing same Glyph %x font %x with font %x\n",
GlyphHandle,
Vxl.CacheTag[CacheIndex].FontId,
FontId));
}
if (GlyphHandle > HigherGlyphHandle) {
HigherGlyphHandle = GlyphHandle;
}
#endif
//
// if the entry that needs to be replaced
// is used as extension for a glyph > 32 lines
// go backwards and clear the Id so that if the
// glyph > 32 is used again it'll miss in the cache
//
LineIndex = CacheIndex;
while (Vxl.CacheTag[LineIndex].FontId == GlyphExtended) {
LineIndex--;
Vxl.CacheTag[LineIndex].FontId = FreeTag;
}
//
// Clear the entries used by the big glyph that follows the one
// that needs to be replaced
//
LineIndex = CacheIndex+1;
while (Vxl.CacheTag[LineIndex].FontId == GlyphExtended) {
Vxl.CacheTag[LineIndex].FontId = FreeTag;
LineIndex++;
}
//
// Store the tag for the current glyph.
//
Vxl.CacheTag[CacheIndex].FontId = FontId;
Vxl.CacheTag[CacheIndex].GlyphHandle = GlyphHandle;
CacheData = Vxl.FontCacheBase + (CacheIndex << 5);
BitMapPtr = FontBitMap->aj;
GlyphBytesPerScan = (X+7) >> 3;
ShiftAmount = (GlyphBytesPerScan-1) << 3;
for (LineIndex=0;LineIndex < Y; LineIndex ++) {
BitMapData = 0;
for (ByteIndex = 0; ByteIndex < GlyphBytesPerScan; ByteIndex++) {
BitMapData >>= 8;
BitMapData |= ToBigEndian[*BitMapPtr++] << ShiftAmount;
}
*CacheData++ = BitMapData;
}
//
// If Y is bigger than 32 lines, the glyph we just cached
// took more than one entry. Fix the CacheTags.
//
for (ByteIndex = 1; LineIndex > 32 ;ByteIndex++) {
Vxl.CacheTag[CacheIndex+ByteIndex].FontId = GlyphExtended;
LineIndex -=32;
}
}
SrcAdr = Vxl.FontCacheOffset + (CacheIndex << 7);
DstAdr = Vxl.JaguarScreenX * (GlyphStart->ptl.y + FontBitMap->ptlOrigin.y) +
((GlyphStart->ptl.x + FontBitMap->ptlOrigin.x) << Vxl.ColorModeShift);
XYCmd = Cmd | (Y << XYCMD_Y_SHIFT) | X;
FifoWrite(DstAdr,SrcAdr,XYCmd);
GlyphStart += 1;
} while (GlyphStart != GlyphEnd);
} while (bMoreGlyphs);
}
//
// Draw extra rectangles using foreground brush
//
if (prclExtra != (PRECTL)NULL) {
DrvpFillRectangle(prclExtra,pboFore->iSolidColor);
}
#ifdef CACHE_STATS
if (CharCount >= 10000) {
ReplacementTotal += CacheReplacement;
CharTotal += CharCount;
MissTotal += CacheMisses;
DISPDBG((3, "Cache Statistics for last %ld chars\n",CharCount));
DISPDBG((3, "Misses = %ld Rate = %ld Replacements %ld\n",
CacheMisses,
(CacheMisses*100)/CharCount,
CacheReplacement));
DISPDBG((3, "Cache Statistics since begining. Total of %ld chars\n",CharTotal));
DISPDBG((3, "Misses = %ld Rate = %ld Replacements %ld Unused entries = %ld\n",
MissTotal,
(MissTotal*100)/CharTotal,
ReplacementTotal,
CacheUnused));
DISPDBG((3, "HigherFontId = %x HigherGlyphHandle = %x\n",HigherFontId,HigherGlyphHandle));
CharCount = 0;
CacheMisses = 0;
CacheReplacement = 0;
}
#endif
//
// Done with call, return
//
return(TRUE);
//
// Could not execute this TextOut call, pass to engine.
// No need to synchronize here since Eng routine will call DrvSynchronize.
//
DevFailTextOut:
return(EngTextOut(pso,
pstro,
pfo,
pco,
prclExtra,
prclOpaque,
pboFore,
pboOpaque,
pptlOrg,
mix));
}