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.
 
 
 
 
 
 

728 lines
21 KiB

/******************************Module*Header*******************************\
* Module Name: text.c
*
* Optimized TextOut for the MIPS. Reduces the total number of memory writes
* required to output a glyph which significantly improves performance when
* using slower video memory.
*
* Copyright (c) 1992 Microsoft Corporation
\**************************************************************************/
#include "driver.h"
//
// 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)
//
// Define enumeration structure.
//
#define BB_RECT_LIMIT 20
typedef struct _ENUMRECTLIST {
ULONG c;
RECTL arcl[BB_RECT_LIMIT];
} ENUMRECTLIST;
//
// Define function prototype for glyph output routines.
//
typedef
VOID
(*PDRVP_GLYPHOUT_ROUTINE) (
IN PBYTE DrawPoint,
IN PULONG GlyphBits,
IN ULONG GlyphWidth,
IN ULONG GlyphHeight
);
VOID
DrvpOutputGlyphTransparent (
IN PBYTE DrawPoint,
IN PBYTE GlyphBitmap,
IN ULONG GlyphWidth,
IN ULONG GlyphHeight
);
//
// Define big endian color mask table conversion table.
//
const ULONG DrvpColorMask[16] = {
0x00000000, // 0000 -> 0000
0xff000000, // 0001 -> 1000
0x00ff0000, // 0010 -> 0100
0xffff0000, // 0011 -> 1100
0x0000ff00, // 0100 -> 0010
0xff00ff00, // 0101 -> 1010
0x00ffff00, // 0110 -> 0110
0xffffff00, // 0111 -> 1110
0x000000ff, // 1000 -> 0001
0xff0000ff, // 1001 -> 1001
0x00ff00ff, // 1010 -> 0101
0xffff00ff, // 1011 -> 1101
0x0000ffff, // 1100 -> 0011
0xff00ffff, // 1101 -> 1011
0x00ffffff, // 1110 -> 0111
0xffffffff}; // 1111 -> 1111
//
// Define draw color table that is generated for text output.
//
ULONG DrvpDrawColorTable[16];
//
// Define foreground color for transparent output.
//
ULONG DrvpForeGroundColor;
//
// Define scanline width value.
//
ULONG DrvpScanLineWidth;
//
// Define global opaque glyph output routine address table.
//
extern PDRVP_GLYPHOUT_ROUTINE DrvpOpaqueTable[8];
/******************************Public*Routine******************************\
* DrvpIntersectRect
*
* This routine checks to see if the two specified retangles intersect.
*
* A value of TRUE is returned if the rectangles intersect. Otherwise,
* a value of FALSE is returned.
*
\**************************************************************************/
BOOL DrvpIntersectRect (
IN PRECTL Rectl1,
IN PRECTL Rectl2,
OUT PRECTL DestRectl)
{
//
// Compute the maximum left edge and the minimum right edge.
//
DestRectl->left = max(Rectl1->left, Rectl2->left);
DestRectl->right = min(Rectl1->right, Rectl2->right);
//
// If the minimum right edge is greater than the maximum left edge,
// then the rectanges may intersect. Otherwise, they do not intersect.
//
if (DestRectl->left < DestRectl->right) {
//
// Compute the maximum top edge and the minimum bottom edge.
//
DestRectl->top = max(Rectl1->top, Rectl2->top);
DestRectl->bottom = min(Rectl1->bottom, Rectl2->bottom);
//
// If the minimum bottom edge is greater than the maximum top
// edge, then the rectanges intersect. Otherwise, they do not
// intersect.
//
if (DestRectl->top < DestRectl->bottom) {
return TRUE;
}
}
return FALSE;
}
/******************************Public*Routine******************************\
* DrvpSolidColorFill
*
* Routine Description:
*
* This routine fills a rectangle with a solid color.
*
* Arguments:
*
* Rectangle - Supplies a pointer to a rectangle.
*
* FillColor - Supplies the fill color.
*
*
* Return Value:
*
* None.
*
\**************************************************************************/
VOID DrvpSolidColorFill (
IN SURFOBJ *pso,
IN PRECTL Rectangle,
IN ULONG FillColor)
{
PUCHAR Destination;
ULONG Index;
ULONG Length;
LONG lDelta = pso->lDelta;
//
// Compute rectangle fill parameters and fill rectangle with solid color.
//
Destination = ((PBYTE) pso->pvScan0) + (Rectangle->top * lDelta) + Rectangle->left;
Length = Rectangle->right - Rectangle->left;
for (Index = 0; Index < (ULONG) (Rectangle->bottom - Rectangle->top); Index += 1) {
RtlFillMemory((PVOID)Destination, Length, FillColor);
Destination += lDelta;
}
return;
}
/******************************Public*Routine******************************\
* DrvpEqualRectangle
*
* This routine compares two rectangles for equality.
*
\**************************************************************************/
BOOL DrvpEqualRectangle (
IN RECTL *prcl1,
IN RECTL *prcl2)
{
if ((prcl1->left == prcl2->left) && (prcl1->right == prcl2->right) &&
(prcl1->bottom == prcl2->bottom) && (prcl1->top == prcl2->top)) {
return TRUE;
} else {
return FALSE;
}
}
/******************************Public*Routine******************************\
* DrvpFillRectangle
*
* This routine fills a rectangle with clipping.
*
\**************************************************************************/
VOID DrvpFillRectangle (
IN SURFOBJ *pso,
IN CLIPOBJ *pco,
IN RECTL *prcl,
IN BRUSHOBJ *pbo)
{
ENUMRECTLIST ClipEnum;
RECTL Region;
ULONG Index;
BOOL More;
ULONG iDComplexity;
if (pco) {
iDComplexity = pco->iDComplexity;
} else {
iDComplexity = DC_TRIVIAL;
}
//
// Clip and fill the rectangle with the specified color.
//
switch(iDComplexity) {
case DC_TRIVIAL:
DrvpSolidColorFill(pso, prcl, pbo->iSolidColor);
return;
case DC_RECT:
More = FALSE;
ClipEnum.c = 1;
ClipEnum.arcl[0] = pco->rclBounds;
break;
case DC_COMPLEX:
More = TRUE;
CLIPOBJ_cEnumStart(pco,
FALSE,
CT_RECTANGLES,
CD_LEFTWARDS,
BB_RECT_LIMIT);
break;
}
//
// Do a solid color fill for each nonclipped region.
//
do {
//
// If more clip regions is TRUE, then get the next batch of
// clipping regions.
//
if (More != FALSE) {
More = CLIPOBJ_bEnum(pco, sizeof(ClipEnum), (PVOID)&ClipEnum);
}
//
// If the clipping is not trival, then do the clipping for the
// next region and do the solid fill. Otherwise, do the solid
// fill with no clipping.
//
for (Index = 0; Index < ClipEnum.c; Index += 1) {
if (DrvpIntersectRect(&ClipEnum.arcl[Index],
prcl,
&Region)) {
DrvpSolidColorFill(pso, &Region, pbo->iSolidColor);
}
}
} while (More);
return;
}
/******************************Public*Routine******************************\
* DrvTextOut
*
* This routine outputs text to the screen.
*
* History:
* 07-Jul-1992 -by- David N. Cutler [davec]
* Wrote it.
\**************************************************************************/
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)
{
ULONG BackGroundColor;
PBYTE DrawPoint;
ULONG ForeGroundColor;
ULONG GlyphCount;
PGLYPHPOS GlyphEnd;
ULONG GlyphHeight;
PGLYPHPOS GlyphList;
PDRVP_GLYPHOUT_ROUTINE GlyphOutputRoutine;
PGLYPHPOS GlyphStart;
ULONG GlyphWidth;
LONG GlyphStride;
ULONG Index;
BOOL More;
RECTL OpaqueRectl;
LONG OriginX;
LONG OriginY;
PBYTE pjScreenBase;
GLYPHBITS *pgb;
//
// DrvTextOut will only get called with solid color brushes and
// the mix mode being the simplest R2_COPYPEN. The driver must
// set a capabilities bit to get called with more complicated
// mix brushes.
//
// ASSERT(pboFore->iSolidColor != 0xffffffff);
// ASSERT(pboOpaque->iSolidColor != 0xffffffff);
// ASSERT(mix == ((R2_COPYPEN << 8) | R2_COPYPEN));
//
// If the complexity of the clipping is not trival, then let GDI
// process the request.
//
if (pco->iDComplexity != DC_TRIVIAL) {
return(EngTextOut(pso,
pstro,
pfo,
pco,
prclExtra,
prclOpaque,
pboFore,
pboOpaque,
pptlOrg,
mix));
}
//
// The foreground color is used for the text and extra rectangle
// if it specified. The background color is used for the opaque
// rectangle. If the foreground color is not a solid color brush
// or the opaque rectangle is specified and is not a solid color
// brush, then let GDI process the request.
//
DrvpScanLineWidth = pso->lDelta;
pjScreenBase = pso->pvScan0;
//
// Check if the background and foreground can be draw at the same time.
//
ForeGroundColor = pboFore->iSolidColor;
ForeGroundColor |= (ForeGroundColor << 8);
ForeGroundColor |= (ForeGroundColor << 16);
if (((pstro->flAccel == SO_LTOR) || (pstro->flAccel == SO_RTOL) ||
(pstro->flAccel == SO_TTOB) || (pstro->flAccel == SO_BTOT)) &&
(prclOpaque != NULL) && (pfo->cxMax <= 32)) {
//
// The background and the foreground can be draw at the same
// time. Generate the drawing color table and draw the text
// opaquely.
//
BackGroundColor = pboOpaque->iSolidColor;
BackGroundColor |= (BackGroundColor << 8);
BackGroundColor |= (BackGroundColor << 16);
for (Index = 0; Index < 16; Index += 1) {
DrvpDrawColorTable[Index] =
(ForeGroundColor & DrvpColorMask[Index]) |
(BackGroundColor & (~DrvpColorMask[Index]));
}
//
// 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(pso,pco, &OpaqueRectl, pboOpaque);
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(pso, pco, &OpaqueRectl, pboOpaque);
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(pso, pco, &OpaqueRectl, pboOpaque);
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(pso, pco, &OpaqueRectl, pboOpaque);
}
//
// 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) {
More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
} else {
GlyphCount = pstro->cGlyphs;
GlyphList = pstro->pgp;
More = FALSE;
}
pgb = GlyphList->pgdf->pgb;
GlyphWidth = pgb->sizlBitmap.cx;
GlyphHeight = pgb->sizlBitmap.cy;
OriginX = GlyphList->ptl.x + pgb->ptlOrigin.x;
OriginY = GlyphList->ptl.y + pgb->ptlOrigin.y;
DrawPoint = pjScreenBase + ((OriginY * DrvpScanLineWidth) + OriginX);
//
// Compute the glyph stride.
//
GlyphStride = pstro->ulCharInc;
if ((pstro->flAccel & SO_VERTICAL) != 0) {
GlyphStride *= DrvpScanLineWidth;
}
//
// If the direction of drawing is reversed, then the stride is
// negative.
//
if ((pstro->flAccel & SO_REVERSED) != 0) {
GlyphStride = - GlyphStride;
}
//
// Output the initial set of glyphs.
//
GlyphOutputRoutine = DrvpOpaqueTable[(GlyphWidth - 1) >> 2];
GlyphEnd = &GlyphList[GlyphCount];
GlyphStart = GlyphList;
do {
pgb = GlyphStart->pgdf->pgb;
(GlyphOutputRoutine)(DrawPoint,
(PULONG)&pgb->aj[0],
GlyphWidth,
GlyphHeight);
DrawPoint += GlyphStride;
GlyphStart += 1;
} while (GlyphStart != GlyphEnd);
//
// Output the subsequent set of glyphs.
//
while (More) {
More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
GlyphEnd = &GlyphList[GlyphCount];
GlyphStart = GlyphList;
do {
pgb = GlyphStart->pgdf->pgb;
(GlyphOutputRoutine)(DrawPoint,
(PULONG)&pgb->aj[0],
GlyphWidth,
GlyphHeight);
DrawPoint += GlyphStride;
GlyphStart += 1;
} while (GlyphStart != GlyphEnd);
}
} else {
//
// The font is not fixed pitch. Compute the x and y values for
// each glyph individually.
//
do {
More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
GlyphEnd = &GlyphList[GlyphCount];
GlyphStart = GlyphList;
do {
pgb = GlyphStart->pgdf->pgb;
OriginX = GlyphStart->ptl.x + pgb->ptlOrigin.x;
OriginY = GlyphStart->ptl.y + pgb->ptlOrigin.y;
DrawPoint = pjScreenBase +
((OriginY * DrvpScanLineWidth) + OriginX);
GlyphWidth = pgb->sizlBitmap.cx;
GlyphOutputRoutine = DrvpOpaqueTable[(GlyphWidth - 1) >> 2];
(GlyphOutputRoutine)(DrawPoint,
(PULONG)&pgb->aj[0],
GlyphWidth,
pgb->sizlBitmap.cy);
GlyphStart += 1;
} while(GlyphStart != GlyphEnd);
} while(More);
}
} else {
//
// The background and the foreground cannot be draw at the same
// time. Set the foreground color and fill the background rectangle,
// if specified, and then draw the text transparently.
//
DrvpForeGroundColor = ForeGroundColor;
if (prclOpaque != NULL) {
DrvpFillRectangle(pso, pco, prclOpaque, pboOpaque);
}
//
// 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) {
More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
} else {
GlyphCount = pstro->cGlyphs;
GlyphList = pstro->pgp;
More = FALSE;
}
pgb = GlyphList->pgdf->pgb;
GlyphWidth = pgb->sizlBitmap.cx;
GlyphHeight = pgb->sizlBitmap.cy;
OriginX = GlyphList->ptl.x + pgb->ptlOrigin.x;
OriginY = GlyphList->ptl.y + pgb->ptlOrigin.y;
DrawPoint = pjScreenBase + ((OriginY * DrvpScanLineWidth) + OriginX);
//
// Compute the glyph stride.
//
GlyphStride = pstro->ulCharInc;
if ((pstro->flAccel & SO_VERTICAL) != 0) {
GlyphStride *= DrvpScanLineWidth;
}
//
// If the direction of drawing is reversed, then the stride is
// negative.
//
if ((pstro->flAccel & SO_REVERSED) != 0) {
GlyphStride = -GlyphStride;
}
//
// Output the initial set of glyphs.
//
GlyphEnd = &GlyphList[GlyphCount];
GlyphStart = GlyphList;
do {
pgb = GlyphStart->pgdf->pgb;
DrvpOutputGlyphTransparent(DrawPoint,
&pgb->aj[0],
GlyphWidth,
GlyphHeight);
DrawPoint += GlyphStride;
GlyphStart += 1;
} while (GlyphStart != GlyphEnd);
//
// Output the subsequent set of glyphs.
//
while (More) {
More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
GlyphEnd = &GlyphList[GlyphCount];
GlyphStart = GlyphList;
do {
pgb = GlyphStart->pgdf->pgb;
DrvpOutputGlyphTransparent(DrawPoint,
&pgb->aj[0],
GlyphWidth,
GlyphHeight);
DrawPoint += GlyphStride;
GlyphStart += 1;
} while (GlyphStart != GlyphEnd);
}
} else {
//
// The font is not fixed pitch. Compute the x and y values for
// each glyph individually.
//
do {
More = STROBJ_bEnum(pstro, &GlyphCount, &GlyphList);
GlyphEnd = &GlyphList[GlyphCount];
GlyphStart = GlyphList;
do {
pgb = GlyphStart->pgdf->pgb;
OriginX = GlyphStart->ptl.x + pgb->ptlOrigin.x;
OriginY = GlyphStart->ptl.y + pgb->ptlOrigin.y;
DrawPoint = pjScreenBase +
((OriginY * DrvpScanLineWidth) + OriginX);
DrvpOutputGlyphTransparent(DrawPoint,
&pgb->aj[0],
pgb->sizlBitmap.cx,
pgb->sizlBitmap.cy);
GlyphStart += 1;
} while(GlyphStart != GlyphEnd);
} while(More);
}
}
//
// Fill the extra rectangles if specified.
//
if (prclExtra != (PRECTL)NULL) {
while (prclExtra->left != prclExtra->right) {
DrvpFillRectangle(pso, pco, prclExtra, pboFore);
prclExtra += 1;
}
}
return(TRUE);
}