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.
400 lines
14 KiB
400 lines
14 KiB
/******************************Module*Header*******************************\
|
|
* Module Name: TextOut.c
|
|
*
|
|
* Text
|
|
*
|
|
* Copyright (c) 1992 Microsoft Corporation
|
|
*
|
|
\**************************************************************************/
|
|
|
|
#include "driver.h"
|
|
|
|
BOOL vFastText(PDEV *, GLYPHPOS *, ULONG, PBYTE, ULONG, ULONG, RECTL *,
|
|
RECTL *, INT, INT, ULONG);
|
|
VOID lclFillRect(CLIPOBJ *, ULONG, PRECTL, PPDEV, INT);
|
|
|
|
|
|
#define FIFTEEN_BITS ((1 << 15)-1)
|
|
|
|
#define TAKING_ALLOC_STATS 0
|
|
|
|
#if TAKING_ALLOC_STATS
|
|
ULONG BufferHitInText = 0;
|
|
ULONG BufferMissInText = 0;
|
|
#endif
|
|
|
|
/****************************************************************************
|
|
* DrvTextOut
|
|
***************************************************************************/
|
|
|
|
BOOL DrvTextOut(
|
|
SURFOBJ* pso,
|
|
STROBJ* pstro,
|
|
FONTOBJ* pfo,
|
|
CLIPOBJ* pco,
|
|
RECTL* prclExtra,
|
|
RECTL* prclOpaque,
|
|
BRUSHOBJ* pboFore,
|
|
BRUSHOBJ* pboOpaque,
|
|
POINTL* pptlOrg,
|
|
MIX mix)
|
|
{
|
|
BOOL b;
|
|
PPDEV ppdev;
|
|
INT iClip; // clip object's complexity
|
|
ULONG iSolidForeColor; // Solid foreground color
|
|
ULONG iSolidBkColor; // Solid background color
|
|
RECTL arclTmp[4]; // Temp storage for portions of opaquing rect
|
|
ULONG culRcl; // Temp rectangle count
|
|
PVOID pvBuf; // pointer to buffer we'll use
|
|
|
|
ULONG ulBufferWidthInBytes;
|
|
ULONG ulBufferHeight;
|
|
ULONG ulBufferBytes;
|
|
BOOL bTextPerfectFit;
|
|
ULONG fDrawFlags;
|
|
|
|
|
|
ppdev = (PPDEV) pso->dhpdev;
|
|
|
|
|
|
//---------------------------------------------------------------------
|
|
// Get information about clip object.
|
|
//---------------------------------------------------------------------
|
|
|
|
iClip = DC_TRIVIAL;
|
|
|
|
if (pco != NULL) {
|
|
iClip = pco->iDComplexity;
|
|
}
|
|
|
|
//---------------------------------------------------------------------
|
|
// Get text color.
|
|
//---------------------------------------------------------------------
|
|
|
|
iSolidForeColor = pboFore->iSolidColor;
|
|
|
|
//---------------------------------------------------------------------
|
|
// See if this is text we can handle faster with special-case code.
|
|
//---------------------------------------------------------------------
|
|
|
|
if (((ppdev->fl & DRIVER_PLANAR_CAPABLE) ||
|
|
(prclOpaque == (PRECTL) NULL)) && // opaque only if planar for now
|
|
// LATER implement fast non-planar
|
|
// opaque
|
|
(iClip == DC_TRIVIAL) && // no clipping for now
|
|
((pstro->rclBkGround.right & ~0x03) >
|
|
((pstro->rclBkGround.left + 3) & ~0x03)) &&
|
|
// not if no full nibbles spanned
|
|
// for now @@@
|
|
(pstro->pgp != NULL) && // no glyph enumeration for now
|
|
(prclExtra == NULL) && // no extra rects for now
|
|
((pstro->flAccel & (SO_HORIZONTAL | SO_VERTICAL | SO_REVERSED)) ==
|
|
SO_HORIZONTAL)) { // only left-to-right text for now
|
|
|
|
// It's the type of text we can special-case; see if the temp buffer is
|
|
// big enough for the text.
|
|
|
|
ulBufferWidthInBytes = ((((pstro->rclBkGround.right + 7) & ~0x07) -
|
|
(pstro->rclBkGround.left & ~0x07)) >> 3);
|
|
|
|
ulBufferHeight = pstro->rclBkGround.bottom - pstro->rclBkGround.top;
|
|
|
|
ulBufferBytes = ulBufferWidthInBytes * ulBufferHeight;
|
|
|
|
if ((ulBufferWidthInBytes > FIFTEEN_BITS) ||
|
|
(ulBufferHeight > FIFTEEN_BITS))
|
|
{
|
|
// the math will have overflowed
|
|
return(FALSE);
|
|
}
|
|
|
|
if (ulBufferBytes <= GLOBAL_BUFFER_SIZE)
|
|
{
|
|
#if TAKING_ALLOC_STATS
|
|
BufferHitInText++;
|
|
#endif
|
|
pvBuf = ppdev->pvTmpBuf;
|
|
}
|
|
else
|
|
{
|
|
#if TAKING_ALLOC_STATS
|
|
BufferMissInText++;
|
|
#endif
|
|
pvBuf = EngAllocUserMem(ulBufferBytes, ALLOC_TAG);
|
|
if (!pvBuf)
|
|
{
|
|
goto no_special_case;
|
|
}
|
|
}
|
|
|
|
// It's big enough; set up for the accelerator
|
|
|
|
// Set fixed pitch, overlap, and top & bottom Y alignment flags
|
|
fDrawFlags = ((pstro->ulCharInc != 0) ? 0x01 : 0) |
|
|
(((pstro->flAccel & (SO_ZERO_BEARINGS |
|
|
SO_FLAG_DEFAULT_PLACEMENT)) !=
|
|
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT))
|
|
? 0x02 : 0) |
|
|
(((pstro->flAccel & (SO_ZERO_BEARINGS |
|
|
SO_FLAG_DEFAULT_PLACEMENT |
|
|
SO_MAXEXT_EQUAL_BM_SIDE)) ==
|
|
(SO_ZERO_BEARINGS | SO_FLAG_DEFAULT_PLACEMENT |
|
|
SO_MAXEXT_EQUAL_BM_SIDE)) ? 0x04 : 0);
|
|
|
|
// If there's an opaque rectangle, we'll do as much opaquing as
|
|
// possible as we do the text. If the opaque rectangle is larger
|
|
// than the text rectangle, then we'll do the fringe areas right
|
|
// now, and the text and associated background areas together,
|
|
// later.
|
|
if (prclOpaque != (PRECTL) NULL) {
|
|
|
|
// This driver only handles solid brushes
|
|
iSolidBkColor = pboOpaque->iSolidColor;
|
|
|
|
// See if we have fringe areas to do. If so, build a list of
|
|
// rectangles to fill, in rightdown order
|
|
|
|
culRcl = 0;
|
|
|
|
// Top fragment
|
|
if (pstro->rclBkGround.top > prclOpaque->top) {
|
|
arclTmp[culRcl].top = prclOpaque->top;
|
|
arclTmp[culRcl].left = prclOpaque->left;
|
|
arclTmp[culRcl].right = prclOpaque->right;
|
|
arclTmp[culRcl++].bottom = pstro->rclBkGround.top;
|
|
}
|
|
|
|
// Left fragment
|
|
if (pstro->rclBkGround.left > prclOpaque->left) {
|
|
arclTmp[culRcl].top = pstro->rclBkGround.top;
|
|
arclTmp[culRcl].left = prclOpaque->left;
|
|
arclTmp[culRcl].right = pstro->rclBkGround.left;
|
|
arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom;
|
|
}
|
|
|
|
// Right fragment
|
|
if (pstro->rclBkGround.right < prclOpaque->right) {
|
|
arclTmp[culRcl].top = pstro->rclBkGround.top;
|
|
arclTmp[culRcl].right = prclOpaque->right;
|
|
arclTmp[culRcl].left = pstro->rclBkGround.right;
|
|
arclTmp[culRcl++].bottom = pstro->rclBkGround.bottom;
|
|
}
|
|
|
|
// Bottom fragment
|
|
if (pstro->rclBkGround.bottom < prclOpaque->bottom) {
|
|
arclTmp[culRcl].bottom = prclOpaque->bottom;
|
|
arclTmp[culRcl].left = prclOpaque->left;
|
|
arclTmp[culRcl].right = prclOpaque->right;
|
|
arclTmp[culRcl++].top = pstro->rclBkGround.bottom;
|
|
}
|
|
|
|
if (culRcl != 0) {
|
|
if (iClip == DC_TRIVIAL) {
|
|
vTrgBlt(ppdev, culRcl, arclTmp, R2_COPYPEN,
|
|
*((RBRUSH_COLOR*) &iSolidBkColor), NULL);
|
|
} else {
|
|
lclFillRect(pco, culRcl, arclTmp, ppdev,
|
|
iSolidBkColor);
|
|
}
|
|
}
|
|
}
|
|
|
|
// We're done with separate opaquing; any further opaquing will
|
|
// happen as part of the text drawing
|
|
|
|
// Clear the buffer if the text isn't going to set every bit
|
|
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) {
|
|
vClearMemDword(pvBuf, (ulBufferBytes + 3) >> 2);
|
|
}
|
|
|
|
// Draw the text into the temp buffer, and thence to the screen
|
|
vFastText(ppdev,
|
|
pstro->pgp,
|
|
pstro->cGlyphs,
|
|
pvBuf,
|
|
ulBufferWidthInBytes,
|
|
pstro->ulCharInc,
|
|
&pstro->rclBkGround,
|
|
prclOpaque,
|
|
iSolidForeColor,
|
|
iSolidBkColor,
|
|
fDrawFlags);
|
|
|
|
// free any memory that was allocated
|
|
if (ulBufferBytes > GLOBAL_BUFFER_SIZE)
|
|
{
|
|
// we had to have allocated memory
|
|
EngFreeUserMem (pvBuf);
|
|
}
|
|
|
|
return(TRUE);
|
|
}
|
|
no_special_case:
|
|
|
|
// Can't special-case; let the engine draw the text
|
|
|
|
pso = ppdev->pSurfObj;
|
|
|
|
// It may be that the opaquing rectangle is larger than the text rectangle,
|
|
// so we'll want to use that to tell the bank manager which banks to
|
|
// enumerate:
|
|
|
|
pco = pcoBankStart(ppdev,
|
|
(prclOpaque != NULL) ? prclOpaque : &pstro->rclBkGround,
|
|
pso,
|
|
pco);
|
|
|
|
do {
|
|
b = EngTextOut(pso,
|
|
pstro,
|
|
pfo,
|
|
pco,
|
|
prclExtra,
|
|
prclOpaque,
|
|
pboFore,
|
|
pboOpaque,
|
|
pptlOrg,
|
|
mix);
|
|
|
|
} while (b && bBankEnum(ppdev, pso, pco));
|
|
|
|
return(b);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
// Fills the specified rectangles on the specified surface with the
|
|
// specified color, honoring the requested clipping. No more than four
|
|
// rectangles should be passed in. Intended for drawing the areas of the
|
|
// opaquing rectangle that extended beyond the text box. The rectangles must
|
|
// be in left to right, top to bottom order. Assumes there is at least one
|
|
// rectangle in the list.
|
|
//--------------------------------------------------------------------------
|
|
|
|
VOID lclFillRect(
|
|
CLIPOBJ *pco,
|
|
ULONG culRcl,
|
|
PRECTL prcl,
|
|
PPDEV ppdev,
|
|
INT iColor)
|
|
{
|
|
BOOL bMore; // Flag for clip enumeration
|
|
TEXTENUM txen; // Clip enumeration object
|
|
ULONG i, j;
|
|
RECTL arclTmp[4];
|
|
ULONG culRclTmp;
|
|
RECTL *prclTmp, *prclClipTmp;
|
|
INT iLastBottom;
|
|
RECTL *pClipRcl;
|
|
INT iClip;
|
|
|
|
iClip = DC_TRIVIAL;
|
|
|
|
if (pco != NULL) {
|
|
iClip = pco->iDComplexity;
|
|
}
|
|
|
|
switch ( iClip ) {
|
|
|
|
case DC_TRIVIAL:
|
|
|
|
vTrgBlt(ppdev, culRcl, prcl, R2_COPYPEN,
|
|
*((RBRUSH_COLOR*) &iColor), NULL);
|
|
|
|
break;
|
|
|
|
case DC_RECT:
|
|
|
|
prclTmp = &pco->rclBounds;
|
|
|
|
// Generate a list of clipped rects
|
|
for (culRclTmp=0, i=0; i<culRcl; i++, prcl++) {
|
|
|
|
// Intersect fill and clip rectangles
|
|
if (bIntersectRect(&arclTmp[culRclTmp], prcl, prclTmp)) {
|
|
|
|
// Add to list if anything's left to draw
|
|
culRclTmp++;
|
|
}
|
|
}
|
|
|
|
// Draw the clipped rects
|
|
if (culRclTmp != 0) {
|
|
vTrgBlt(ppdev, culRclTmp, arclTmp, R2_COPYPEN,
|
|
*((RBRUSH_COLOR*) &iColor), NULL);
|
|
}
|
|
|
|
break;
|
|
|
|
case DC_COMPLEX:
|
|
|
|
// Bottom of last rectangle to fill
|
|
iLastBottom = prcl[culRcl-1].bottom;
|
|
|
|
// Initialize the clip rectangle enumeration to rightdown so we can
|
|
// take advantage of the rectangle list being rightdown
|
|
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN,
|
|
TO_RECT_LIMIT);
|
|
|
|
// Scan through all the clip rectangles, looking for intersects
|
|
// of fill areas with region rectangles
|
|
do {
|
|
|
|
// Get a batch of region rectangles
|
|
bMore = CLIPOBJ_bEnum(pco, (ULONG)sizeof(txen), (PVOID)&txen);
|
|
|
|
// Clip the rect list to each region rect
|
|
for (j = txen.c, pClipRcl = txen.arcl; j-- > 0; pClipRcl++) {
|
|
|
|
// Since the rectangles and the region enumeration are both
|
|
// rightdown, we can zip through the region until we reach
|
|
// the first fill rect, and are done when we've passed the
|
|
// last fill rect.
|
|
|
|
if (pClipRcl->top >= iLastBottom) {
|
|
// Past last fill rectangle; nothing left to do
|
|
return;
|
|
}
|
|
|
|
// Do intersection tests only if we've reached the top of
|
|
// the first rectangle to fill
|
|
if (pClipRcl->bottom > prcl->top) {
|
|
|
|
// We've reached the top Y scan of the first rect, so
|
|
// it's worth bothering checking for intersection
|
|
|
|
// Generate a list of the rects clipped to this region
|
|
// rect
|
|
prclTmp = prcl;
|
|
prclClipTmp = arclTmp;
|
|
for (i = culRcl, culRclTmp=0; i-- > 0; prclTmp++) {
|
|
|
|
// Intersect fill and clip rectangles
|
|
if (bIntersectRect(prclClipTmp, prclTmp,
|
|
pClipRcl)) {
|
|
|
|
// Add to list if anything's left to draw
|
|
culRclTmp++;
|
|
prclClipTmp++;
|
|
}
|
|
}
|
|
|
|
// Draw the clipped rects
|
|
if (culRclTmp != 0) {
|
|
vTrgBlt(ppdev, culRclTmp, arclTmp, R2_COPYPEN,
|
|
*((RBRUSH_COLOR*) &iColor), NULL);
|
|
}
|
|
}
|
|
}
|
|
} while (bMore);
|
|
|
|
break;
|
|
}
|
|
|
|
}
|