Leaked source code of windows server 2003
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.
 
 
 
 
 
 

2879 lines
100 KiB

/******************************Module*Header*******************************\
*
* Module Name: TEXTOUT.c
* Author: Martin Barber
* Date: Jun. 19, 1995
* Purpose: Handle calls to DrvTxtOut
*
* Copyright (c) 1995,1996 Cirrus Logic, Inc.
*
* $Log: X:/log/laguna/nt35/displays/cl546x/TEXTOUT.C $
*
* Rev 1.34 Mar 27 1998 14:47:14 frido
* PDR#11280. In the monospaced font loop there was a problem loading
* the pointer to the next glyph bits. It always got the pointer to the
* previous glyph.
*
* Rev 1.33 Mar 04 1998 15:38:46 frido
* Added new shadow macros.
*
* Rev 1.32 Dec 17 1997 16:42:14 frido
* PDR#10875: There was a GPF inside vMmClipGlyphExpansion and NT
* 3.51 does not handle this very well. It caused the hardware to wait for
* another DWORD which was never send.
*
* Rev 1.31 Dec 10 1997 13:32:20 frido
* Merged from 1.62 branch.
*
* Rev 1.30.1.1 Dec 03 1997 18:12:20 frido
* PDR#11039. Fixed allocation of font cache. In certain cases it would
* allocate too few cells and still use the unallocated cells causing
* corruption.
*
* Rev 1.30.1.0 Nov 18 1997 15:40:16 frido
* Changed a spelling error: RWQUIRE into REQUIRE.
*
* Rev 1.30 Nov 03 1997 10:17:36 frido
* Added REQUIRE and WRITE_STRING macros.
* Removed CHECK_QFREE macros.
*
* Rev 1.29 25 Aug 1997 16:07:24 FRIDO
*
* Fixed lockup in 8-bpp vMmClipGlyphExpansion SWAT7 code.
*
* Rev 1.28 08 Aug 1997 17:24:30 FRIDO
* Added support for new memory manager.
* Added SWAT7 switches for 8-bpp hardware bug.
*
* Rev 1.27 29 Apr 1997 16:28:50 noelv
*
* Merged in new SWAT code.
* SWAT:
* SWAT: Rev 1.7 24 Apr 1997 12:05:38 frido
* SWAT: Fixed a missing "}".
* SWAT:
* SWAT: Rev 1.6 24 Apr 1997 11:22:18 frido
* SWAT: NT140b09 merge.
* SWAT: Changed pfm into pCell for SWAT3 changes.
* SWAT:
* SWAT: Rev 1.5 19 Apr 1997 17:11:02 frido
* SWAT: Added SWAT.h include file.
* SWAT: Fixed a bug in DrvDestroyFont causing hangups in 2nd WB97 pass.
* SWAT:
* SWAT: Rev 1.4 18 Apr 1997 00:34:28 frido
* SWAT: Fixed a merge bug.
* SWAT:
* SWAT: Rev 1.3 18 Apr 1997 00:15:28 frido
* SWAT: NT140b07 merge.
* SWAT:
* SWAT: Rev 1.2 10 Apr 1997 16:02:06 frido
* SWAT: Oops, I allocated the font cache in the wrong size.
* SWAT:
* SWAT: Rev 1.1 09 Apr 1997 17:37:30 frido
* SWAT: New font cache allocation scheme. Allocate from a 'pool' of cells
* SWAT: instead of putting the font cache all over the place.
*
* Rev 1.26 08 Apr 1997 12:32:50 einkauf
*
* add SYNC_W_3D to coordinate MCD/2D hw access
*
* Rev 1.25 21 Mar 1997 13:37:06 noelv
* Added checkes for QFREE.
*
* Rev 1.24 06 Feb 1997 10:38:04 noelv
* Removed WAIT_FOR_IDLE
*
* Rev 1.23 04 Feb 1997 11:11:00 SueS
* Added support for hardware clipping for the 5465.
*
* Rev 1.22 17 Dec 1996 16:59:00 SueS
* Added test for writing to log file based on cursor at (0,0).
*
* Rev 1.21 26 Nov 1996 10:46:36 SueS
* Changed WriteLogFile parameters for buffering.
*
* Rev 1.20 13 Nov 1996 17:01:28 SueS
* Changed WriteFile calls to WriteLogFile.
*
* Rev 1.19 07 Nov 1996 16:10:16 bennyn
*
* Added no offscn mem allocation if DD enabled
*
* Rev 1.18 06 Sep 1996 15:16:44 noelv
* Updated NULL driver for 4.0
*
* Rev 1.17 20 Aug 1996 11:04:36 noelv
* Bugfix release from Frido 8-19-96
*
* Rev 1.3 16 Aug 1996 14:48:20 frido
* Fixed a small wanring error.
*
* Rev 1.2 15 Aug 1996 11:54:32 frido
* Fixed precompiled headers.
*
* Rev 1.1 15 Aug 1996 11:38:32 frido
* Added precompiled header.
*
* Rev 1.0 14 Aug 1996 17:16:32 frido
* Initial revision.
*
* Rev 1.16 25 Jul 1996 15:56:28 bennyn
*
* Modified to support DirectDraw
*
* Rev 1.15 28 May 1996 15:11:36 noelv
* Updated data logging.
*
* Rev 1.14 16 May 1996 15:06:18 bennyn
*
* Added PIXEL_ALIGN to allocoffscnmem()
*
* Rev 1.13 16 May 1996 14:54:32 noelv
* Added logging code.
*
* Rev 1.12 03 May 1996 15:09:42 noelv
*
* Added flag to turn caching on and off.
*
* Rev 1.11 01 May 1996 11:01:48 bennyn
*
* Modified for NT4.0
*
* Rev 1.10 12 Apr 1996 18:13:06 andys
* Fixed bug in combining 3 bytes into DWORD (<< | bug)
*
* Rev 1.9 11 Apr 1996 18:00:56 andys
* Added Code to the > 16 PEL case to guard against walking off the end of a b
*
* Rev 1.8 04 Apr 1996 13:20:32 noelv
* Frido release 26
*
* Rev 1.16 01 Apr 1996 15:29:22 frido
* Fixed bug in font cache when glyph cannot be cached.
*
* Rev 1.15 28 Mar 1996 23:37:34 frido
* Fixed drawing of partially left-clipped glyphs.
*
* Rev 1.14 27 Mar 1996 14:12:18 frido
* Commented changes.
*
* Rev 1.13 25 Mar 1996 11:58:38 frido
* Removed warning message.
*
* Rev 1.12 25 Mar 1996 11:50:42 frido
* Bellevue 102B03.
*
* Rev 1.5 18 Mar 1996 12:34:10 noelv
*
* Added data logging stuff
*
* Rev 1.4 07 Mar 1996 18:24:14 bennyn
*
* Removed read/modify/write on CONTROL reg
*
* Rev 1.3 05 Mar 1996 11:59:20 noelv
* Frido version 19
*
* Rev 1.11 04 Mar 1996 20:23:28 frido
* Cached grCONTROL register.
*
* Rev 1.10 29 Feb 1996 20:23:08 frido
* Changed some comments.
*
* Rev 1.9 28 Feb 1996 22:39:46 frido
* Added Optimize.h.
*
* Rev 1.8 27 Feb 1996 16:38:12 frido
* Added device bitmap store/restore.
*
* Rev 1.7 24 Feb 1996 01:23:16 frido
* Added device bitmaps.
*
* Rev 1.6 03 Feb 1996 13:57:24 frido
* Use the compile switch "-Dfrido=0" to disable my extensions.
*
* Rev 1.5 03 Feb 1996 12:17:58 frido
* Added text clipping.
*
* Rev 1.4 25 Jan 1996 12:45:56 frido
* Added reinitialization of font cache after mode switch.
*
* Rev 1.3 24 Jan 1996 23:10:16 frido
* Moved font cache and entry point to assembly for i386.
*
* Rev 1.2 23 Jan 1996 15:37:20 frido
* Added font cache.
*
\**************************************************************************/
#include "precomp.h"
#include "font.h"
#include "SWAT.h" // SWAT optimizations
#define TEXT_DBG_LEVEL 1
#define TEXT_DBG_LEVEL1 1
#define RECORD_ON FALSE
#define BUFFER_EXPAND FALSE
/*
-------------------------------------------------------------------------------
Module Entry Points:
--------------------
DrvTextOut()
General Plan:
--------------------
*
* On every TextOut, GDI provides an array of 'GLYPHPOS' structures
* for every glyph to be drawn. Each GLYPHPOS structure contains a
* the glyph. (Note that unlike Windows 3.1, which provides a column-
* major glyph bitmap, Windows NT always provides a row-major glyph
* bitmap.) As such, there are three basic methods for drawing text
* with hardware acceleration:
*
* 1) Glyph caching -- Glyph bitmaps are cached by the accelerator
* (probably in off-screen memory), and text is drawn by
* referring the hardware to the cached glyph locations.
*
* 2) Glyph expansion -- Each individual glyph is colour-expanded
* directly to the screen from the monochrome glyph bitmap
* supplied by GDI.
*
* 3) Buffer expansion -- The CPU is used to draw all the glyphs into
* a 1bpp monochrome bitmap, and the hardware is then used
* to colour-expand the result.
*
* The fastest method depends on a number of variables, such as the
* colour expansion speed, bus speed, CPU speed, average glyph size,
* and average string length.
*
* Copyright (c) 1992-1994 Microsoft Corporation
*
\**************************************************************************/
//
// Data logging stuff.
// Gets compiled out in a free bulid.
//
#if LOG_CALLS
char BUF[256];
#if ENABLE_LOG_SWITCH
#define LogFile(x) \
do { \
if (pointer_switch == 1) \
{ \
int i = sprintf x ; \
WriteLogFile(ppdev->pmfile, BUF, i, ppdev->TxtBuff, &ppdev->TxtBuffIndex); \
} \
} while(0); \
#else
#define LogFile(x) \
do { \
int i = sprintf x ; \
WriteLogFile(ppdev->pmfile, BUF, i, ppdev->TxtBuff, &ppdev->TxtBuffIndex); \
} while(0); \
#endif
#else
#define BUF 0
#define LogFile(x)
#endif
POINTL gptlZero = { 0, 0 }; // Specifies that the origin of the
// temporary buffer given to the 1bpp
// transfer routine for fasttext is
// at (0, 0)
/******************************Public*Routine******************************\
* void AddToFontCacheChain
*
* Add the FONTCACHE to the Font cache chain
*
\**************************************************************************/
void AddToFontCacheChain(PDEV* ppdev,
FONTOBJ* pfo,
PFONTCACHE pfc)
{
DISPDBG((TEXT_DBG_LEVEL1," AddToFontCacheChain.\n"));
pfc->pfo = pfo;
#if !SWAT3 // We don't need this anymore. The cell grid has all the pointers.
// Hook the font cache into the chain.
if (ppdev->pfcChain != NULL)
{
ppdev->pfcChain->pfcPrev = pfc;
}
pfc->pfcPrev = NULL;
pfc->pfcNext = ppdev->pfcChain;
ppdev->pfcChain = pfc;
#endif
}
/******************************Public*Routine******************************\
* BOOL bIntersect
*
* If 'prcl1' and 'prcl2' intersect, has a return value of TRUE and returns
* the intersection in 'prclResult'. If they don't intersect, has a return
* value of FALSE, and 'prclResult' is undefined.
*
\**************************************************************************/
BOOL bIntersect(
RECTL* prcl1,
RECTL* prcl2,
RECTL* prclResult)
{
DISPDBG((TEXT_DBG_LEVEL1," bIntersect.\n"));
prclResult->left = max(prcl1->left, prcl2->left);
prclResult->right = min(prcl1->right, prcl2->right);
if (prclResult->left < prclResult->right)
{
prclResult->top = max(prcl1->top, prcl2->top);
prclResult->bottom = min(prcl1->bottom, prcl2->bottom);
if (prclResult->top < prclResult->bottom)
{
return(TRUE);
}
}
return(FALSE);
}
/******************************Public*Routine******************************\
* LONG cIntersect
*
* This routine takes a list of rectangles from 'prclIn' and clips them
* in-place to the rectangle 'prclClip'. The input rectangles don't
* have to intersect 'prclClip'; the return value will reflect the
* number of input rectangles that did intersect, and the intersecting
* rectangles will be densely packed.
*
\**************************************************************************/
LONG cIntersect(
RECTL* prclClip,
RECTL* prclIn, // List of rectangles
LONG c) // Can be zero
{
LONG cIntersections;
RECTL* prclOut;
DISPDBG((TEXT_DBG_LEVEL1," cIntersect.\n"));
cIntersections = 0;
prclOut = prclIn;
for ( ; c != 0; prclIn++, c--)
{
prclOut->left = max(prclIn->left, prclClip->left);
prclOut->right = min(prclIn->right, prclClip->right);
if (prclOut->left < prclOut->right)
{
prclOut->top = max(prclIn->top, prclClip->top);
prclOut->bottom = min(prclIn->bottom, prclClip->bottom);
if (prclOut->top < prclOut->bottom)
{
prclOut++;
cIntersections++;
}
}
}
return(cIntersections);
}
/******************************Public*Routine******************************\
* VOID vClipSolid
*
* Fills the specified rectangles with the specified colour, honouring
* the requested clipping. No more than four rectangles should be passed in.
* Intended for drawing the areas of the opaquing rectangle that extend
* 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 vClipSolid(
PDEV* ppdev,
LONG crcl,
RECTL* prcl,
ULONG iColor,
CLIPOBJ* pco)
{
BOOL bMore; // Flag for clip enumeration
ENUMRECTS8 ce; // Clip enumeration object
ULONG i;
ULONG j;
#if !(DRIVER_5465 && HW_CLIPPING)
RECTL arclTmp[4];
ULONG crclTmp;
RECTL* prclTmp;
RECTL* prclClipTmp;
LONG iLastBottom;
#endif
RECTL* prclClip;
DISPDBG((TEXT_DBG_LEVEL1,"vClipSolid: Entry.\n"));
ASSERTMSG( (crcl > 0) && (crcl <= 4), "Expected 1 to 4 rectangles");
ASSERTMSG( (pco != NULL) && (pco->iDComplexity != DC_TRIVIAL),
"Expected a non-null clip object");
// Do the loop invariant setup here
REQUIRE(2);
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 2);
if (pco->iDComplexity == DC_RECT)
{
crcl = cIntersect(&pco->rclBounds, prcl, crcl);
while (crcl--)
{
REQUIRE(5);
LL_OP0(prcl->left + ppdev->ptlOffset.x,
prcl->top + ppdev->ptlOffset.y);
LL_BLTEXT((prcl->right - prcl->left), (prcl->bottom - prcl->top));
prcl++;
}
}
else // iDComplexity == DC_COMPLEX
{
// Initialize the clip rectangle enumeration to right-down so we can
// take advantage of the rectangle list being right-down:
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_RIGHTDOWN, 0);
#if DRIVER_5465 && HW_CLIPPING
// Set up the hardware clipping
REQUIRE(6);
LL_DRAWBLTDEF(SOLID_COLOR_FILL | DD_CLIPEN, 0);
i = max(0, prcl->left);
j = max(0, prcl->top);
LL_OP0(i + ppdev->ptlOffset.x, j + ppdev->ptlOffset.y);
LL_BLTEXT_EXT(prcl->right - i, prcl->bottom - j);
do
{
// Get a batch of region rectangles:
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (VOID*)&ce);
// Clip the rect list to each region rect:
for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
{
// Draw the clipped rects
REQUIRE(5);
LL_CLIPULE(prclClip->left + ppdev->ptlOffset.x,
prclClip->top + ppdev->ptlOffset.y);
LL_CLIPLOR_EX(prclClip->right + ppdev->ptlOffset.x,
prclClip->bottom + ppdev->ptlOffset.y);
} // End for each rectangle in the list.
} while (bMore); // End loop for each batch
#else
// Bottom of last rectangle to fill
iLastBottom = prcl[crcl - 1].bottom;
// 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, sizeof(ce), (VOID*)&ce);
// Clip the rect list to each region rect:
for (j = ce.c, prclClip = ce.arcl; j-- > 0; prclClip++)
{
// Since the rectangles and the region enumeration are both
// right-down, 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 (prclClip->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 (prclClip->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 = crcl, crclTmp = 0; i-- != 0; prclTmp++)
{
// Intersect fill and clip rectangles
if (bIntersect(prclTmp, prclClip, prclClipTmp))
{
// Draw the clipped rects
REQUIRE(5);
LL_OP0(prclClipTmp->left + ppdev->ptlOffset.x,
prclClipTmp->top + ppdev->ptlOffset.y);
LL_BLTEXT ( (prclClipTmp->right - prclClipTmp->left) ,
(prclClipTmp->bottom - prclClipTmp->top) );
}
} // End for each rectangle in the batch.
} // End intersect test.
} // End for each rectangle in the list.
} while (bMore); // End loop for each batch
#endif // if !(DRIVER_5465 && HW_CLIPPING)
} // End DC_COMPLEX
}
#if SWAT7
/******************************Public*Routine******************************\
* VOID Xfer64Pixels
*
* Copy 64 pixels of font data to the Laguna memory.
*
\**************************************************************************/
VOID Xfer64Pixels(
PDEV* ppdev,
UINT x,
UINT y,
UINT bitOffset,
UINT height,
BYTE* pjGlyph,
UINT delta
)
{
delta = (delta + 7) >> 3;
REQUIRE(5);
LL_OP0(x + ppdev->ptlOffset.x, y + ppdev->ptlOffset.y);
LL_BLTEXT(64, height);
while (height--)
{
REQUIRE(3);
LL32(grHOSTDATA[0], *(ULONG*) &pjGlyph[0]);
LL32(grHOSTDATA[1], *(ULONG*) &pjGlyph[4]);
if (bitOffset > 0)
{
LL32(grHOSTDATA[2], pjGlyph[8]);
}
pjGlyph += delta;
}
}
#endif
/******************************Public*Routine******************************\
* VOID vMmClipGlyphExpansion
*
* Handles any strings that need to be clipped, using the 'glyph
* expansion' method.
*
\**************************************************************************/
VOID vMmClipGlyphExpansion(
PDEV* ppdev,
STROBJ* pstro,
CLIPOBJ* pco)
{
BOOL bMoreGlyphs;
ULONG cGlyphOriginal;
ULONG cGlyph;
GLYPHPOS* pgpOriginal;
GLYPHPOS* pgp;
GLYPHBITS* pgb;
POINTL ptlOrigin;
BOOL bMore;
ENUMRECTS8 ce;
RECTL* prclClip;
ULONG ulCharInc;
LONG cxGlyph;
LONG cyGlyph;
BYTE* pjGlyph;
BYTE* pTmp;
LONG cj;
LONG cw;
LONG xLeft;
LONG yTop;
LONG xRight;
LONG yBottom;
LONG xBias;
LONG lDelta;
LONG cx;
LONG cy;
#if SWAT7
UINT xOrigin;
#endif
DISPDBG((TEXT_DBG_LEVEL1,"vMmClipGlyphExpansion: Entry.\n"));
ASSERTMSG(pco != NULL, "Don't expect NULL clip objects here");
do // Loop for each batch of glyphs to be done.
{
//
// Get a batch of glyphs.
//
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);
}
//
// cGlyphOrigional is the number of glyphs in the batch before they
// are clipped.
// bMoreGlyphs is TRUE if there are more batches to be done after
// this one.
//
if (cGlyphOriginal > 0) // Were there any glyphs in the batch?
{
ulCharInc = pstro->ulCharInc;
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; // No more clip lists to do.
prclClip = &pco->rclBounds;
ce.c = 1; // Only one rectangle in this list.
goto SingleRectangle;
}
CLIPOBJ_cEnumStart(pco, FALSE, CT_RECTANGLES, CD_ANY, 0);
do // For each list of rectangles.
{
bMore = CLIPOBJ_bEnum(pco, sizeof(ce), (ULONG*) &ce);
// For each rectangle in the list.
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)
{
LogFile((BUF, "GC:M\r\n"));
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
pjGlyph = pgb->aj;
#if SWAT7
lDelta = (cxGlyph + 7) >> 3;
#endif
if ((prclClip->left <= ptlOrigin.x) &&
(prclClip->top <= ptlOrigin.y) &&
(prclClip->right >= ptlOrigin.x + cxGlyph) &&
(prclClip->bottom >= ptlOrigin.y + cyGlyph))
{
//-----------------------------------------------------
// Unclipped glyph
#if SWAT7
xOrigin = ptlOrigin.x;
#endif
#if SWAT7
//
// Test for 5465AD hardware bug in 8-bpp.
//
if ( (cxGlyph > 64) && (cxGlyph < 128)
&& (ppdev->iBytesPerPixel == 1)
)
{
Xfer64Pixels(ppdev, xOrigin, ptlOrigin.y, 0,
cyGlyph, pjGlyph, cxGlyph);
pjGlyph += 64 / 8;
xOrigin += 64;
cxGlyph -= 64;
}
REQUIRE(5);
LL_OP0(xOrigin + ppdev->ptlOffset.x,
ptlOrigin.y + ppdev->ptlOffset.y);
#else
REQUIRE(5);
LL_OP0(ptlOrigin.x + ppdev->ptlOffset.x,
ptlOrigin.y + ppdev->ptlOffset.y);
#endif
LL_BLTEXT(cxGlyph, cyGlyph);
if (cxGlyph <= 8)
{
//-----------------------------------------------------
// 1 to 8 pels in width
while ( cyGlyph-- )
{
REQUIRE(1);
#if SWAT7
LL32 (grHOSTDATA[0], *pjGlyph);
pjGlyph += lDelta;
#else
LL32 (grHOSTDATA[0], *pjGlyph++);
#endif
}
}
else if (cxGlyph <= 16)
{
//-----------------------------------------------------
// 9 to 16 pels in width
while ( cyGlyph-- )
{
REQUIRE(1);
#if SWAT7
LL32 (grHOSTDATA[0], *(USHORT*)pjGlyph);
pjGlyph += lDelta;
#else
LL32 (grHOSTDATA[0], *((USHORT*)pjGlyph)++);
#endif
}
}
else
{
//-----------------------------------------------------
// More than 16 pels in width
#if SWAT7
cw = (cxGlyph + 31) >> 5;
#else
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
cw = (lDelta + 3) >> 2;
#endif
pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
for (;cyGlyph!=1; cyGlyph--)
{
WRITE_STRING(pjGlyph, cw);
pjGlyph += lDelta;
}
{
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
WRITE_STRING(pjGlyph, cw - 1);
if ((BYTE *)pSrc+4<=pTmp)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *pSrc++ );
}
else
{
int Extra = (ULONG) pTmp - (ULONG) pSrc;
BYTE * pByte = (BYTE *)pSrc;
ULONG ulData;
DISPDBG((TEXT_DBG_LEVEL1,
"Caught it %s %d %d %x %x\n", __FILE__, __LINE__, Extra, pTmp, pSrc));
if (Extra == 1)
ulData = (ULONG)(*pByte);
else if (Extra == 2)
ulData = (ULONG)(*(USHORT*)pByte);
else
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
REQUIRE(1);
LL32 (grHOSTDATA[0], ulData );
}
}
} // End 16 pels or wider.
} // End unclipped glyph.
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))
{
xBias = (xLeft - ptlOrigin.x) & 7;
// 'xBias' is the bit position in the monochrome glyph
// bitmap of the first pixel to be lit, relative to
// the start of the byte. That is, if 'xBias' is 2,
// then the first unclipped pixel is represented by bit
// 2 of the corresponding bitmap byte.
//
// Normally, the accelerator expects bit 0 to be the
// first lit byte. We set the host phase to discard the
// first 'xBias' bits.
//
if ( xBias )
{
REQUIRE(2);
LL_OP2_MONO (xBias,0);
}
#if !SWAT7
REQUIRE(5);
LL_OP0(xLeft + ppdev->ptlOffset.x,
yTop + ppdev->ptlOffset.y);
LL_BLTEXT (cx, cy);
#endif
lDelta = (cxGlyph + 7) >> 3;
// compute the end-of-glyph marker before
// clipping the glyph.
pTmp = pjGlyph + lDelta * cy;
pjGlyph += (yTop - ptlOrigin.y) * lDelta
+ ((xLeft - ptlOrigin.x) >> 3);
#if SWAT7
//
// Test for 5465AD hardware bug in 8-bpp.
//
if ( (cx > 64) && (cx < 128)
&& (ppdev->iBytesPerPixel == 1)
)
{
Xfer64Pixels(ppdev, xLeft, yTop, xBias, cy,
pjGlyph, cxGlyph);
pjGlyph += 64 / 8;
xLeft += 64;
cx -= 64;
}
REQUIRE(5);
LL_OP0(xLeft + ppdev->ptlOffset.x,
yTop + ppdev->ptlOffset.y);
LL_BLTEXT (cx, cy);
#endif
cj = (cx + xBias + 31) >> 5;
for (;cy!=1; cy--)
{
WRITE_STRING(pjGlyph, cj);
pjGlyph += lDelta;
}
{
ULONG *pSrc = (ULONG*) pjGlyph + cj - 1;
int Extra = (ULONG) pTmp - (ULONG) pSrc;
BYTE * pByte = (BYTE *)pSrc;
ULONG ulData;
WRITE_STRING(pjGlyph, cj - 1);
if (Extra == 1)
ulData = (ULONG)(*pByte);
else if (Extra == 2)
ulData = (ULONG)(*(USHORT*)pByte);
else if (Extra == 3)
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
else
ulData = *pSrc;
REQUIRE(1);
LL32 (grHOSTDATA[0], ulData );
}
if (xBias != 0)
{
REQUIRE(2);
LL_OP2_MONO(0,0);
}
} // if not trivially rejected.
} // End clipped glyph.
//
// If we're out of glyphs the get next batch.
if (--cGlyph == 0)
break;
// Get ready for next glyph:
pgp++;
pgb = pgp->pgdf->pgb;
//
// Calculate where to place the next glyph.
// If this is mono spaced text, we may need to
// skip over some pixels to make our characters
// line up.
//
if (ulCharInc == 0)
{
ptlOrigin.x = pgp->ptl.x + pgb->ptlOrigin.x;
ptlOrigin.y = pgp->ptl.y + pgb->ptlOrigin.y;
}
else
{
ptlOrigin.x += ulCharInc;
}
} // End loop for each glyph in the batch.
} // End for each rectangle in the list.
} while (bMore); // Loop for each batch of clipping rectangles.
} // If there were any glyphs in this batch.
} while (bMoreGlyphs); // Loop for each batch of glyphs.
} // End clipped glyph expansion.
/******************************Public*Routine******************************\
* BOOL DrvTextOut
*
* If it's the fastest method, outputs text using the 'glyph expansion'
* method. Each individual glyph is colour-expanded directly to the
* screen from the monochrome glyph bitmap supplied by GDI.
*
* If it's not the fastest method, calls the routine that implements the
* 'buffer expansion' method.
*
\**************************************************************************/
#if (USE_ASM && defined(i386))
BOOL i386DrvTextOut(
#else
BOOL APIENTRY DrvTextOut(
#endif
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,
MIX mix)
{
PDEV* ppdev;
BOOL bTextPerfectFit;
ULONG cGlyph;
BOOL bMoreGlyphs;
GLYPHPOS* pgp;
GLYPHBITS* pgb;
BYTE* pjGlyph;
BYTE* pTmp;
#if SWAT7
LONG cxGlyph;
#endif
LONG cyGlyph;
POINTL ptlOrigin;
LONG ulCharInc;
BYTE iDComplexity;
LONG lDelta;
LONG cw;
ULONG iFGColor;
ULONG iBGColor;
ULONG bitCount;
#if SWAT7
UINT xOrigin;
#endif
#if NULL_TEXTOUT
{
if (pointer_switch) return TRUE;
}
#endif
DISPDBG((TEXT_DBG_LEVEL,"DrvTextOut: Entry.\n"));
// The DDI spec says we'll only ever get foreground and background
// mixes of R2_COPYPEN:
ASSERTMSG(mix == 0x0d0d, "GDI should only give us a copy mix");
ppdev = (PDEV*) pso->dhpdev;
SYNC_W_3D(ppdev); // if 3D context(s) active, make sure 3D engine idle before continuing...
if (pso->iType == STYPE_DEVBITMAP)
{
PDSURF pdsurf = (PDSURF)pso->dhsurf;
LogFile((BUF, "DTO Id=%p ", pdsurf));
if (pdsurf->pso)
{
if ( !bCreateScreenFromDib(ppdev, pdsurf) )
{
LogFile((BUF, "DTO: D=DH (punted)\r\n"));
return(EngTextOut(pdsurf->pso, pstro, pfo, pco, prclExtra,
prclOpaque, pboFore, pboOpaque, pptlBrush, mix));
}
else
{
LogFile((BUF, "DTO: D=DF "));
}
}
else
{
LogFile((BUF, "DTO: D=D "));
}
ppdev->ptlOffset.x = pdsurf->ptl.x;
ppdev->ptlOffset.y = pdsurf->ptl.y;
}
else
{
LogFile((BUF, "DTO: D=S "));
ppdev->ptlOffset.x = ppdev->ptlOffset.y = 0;
}
//
// Dump information about the call to the log file.
//
LogFile((BUF, "FG=%X BG=%X ",
pboFore->iSolidColor, pboOpaque->iSolidColor));
LogFile((BUF, "C=%s ",
(pco == NULL) ? "N " :
((pco->iDComplexity == DC_TRIVIAL) ? "T" :
((pco->iDComplexity == DC_RECT) ? "R" : "C" ))
));
LogFile((BUF, "%s ", (prclOpaque != NULL) ? "O" : "T"));
LogFile((BUF, "%s ", (pstro->ulCharInc == 0) ? "P" : "M"));
#if !(USE_ASM && defined(i386))
// If we have a font that is cached but the screen has been reinitialized,
// we delete the font from memory and try again.
if (ppdev->UseFontCache == 0)
pfo->pvConsumer = (VOID*) -1;
if (pfo->pvConsumer != NULL && pfo->pvConsumer != (PVOID) -1)
{
if (((PFONTCACHE) pfo->pvConsumer)->ulFontCount != ppdev->ulFontCount)
{
LogFile((BUF, "FCD "));
DrvDestroyFont(pfo);
}
else
LogFile((BUF, "GC=2 "));
}
if (pfo->pvConsumer == (PVOID) -1)
{
LogFile((BUF, "GC=3"));
}
// If we have a font that has not yet been cached, try caching it.
if (pfo->pvConsumer == NULL)
{
// New font, check it out.
int height = pstro->rclBkGround.bottom - pstro->rclBkGround.top;
LogFile((BUF, "GC="));
#if SWAT3
if (height > FONTCELL_Y * 3 / 2)
#else
if (height > LINES_PER_TILE * 3 / 2)
#endif
{
// Font too big, mark is as uncacheable.
LogFile((BUF, "0size "));
pfo->pvConsumer = (PVOID) -1;
}
else
{
// Allocate memory for the font cache.
#ifdef WINNT_VER40
pfo->pvConsumer = MEM_ALLOC(FL_ZERO_MEMORY, sizeof(FONTCACHE), ALLOC_TAG);
#else
pfo->pvConsumer = MEM_ALLOC(LMEM_FIXED | LMEM_ZEROINIT, sizeof(FONTCACHE));
#endif
if (pfo->pvConsumer == NULL)
{
// Not enough memory, mark it as uncacheable.
LogFile((BUF, "0mem "));
pfo->pvConsumer = (PVOID) -1;
}
else
{
LogFile((BUF, "1 "));
AddToFontCacheChain(ppdev, pfo, pfo->pvConsumer);
// Store device this font belongs to.
((PFONTCACHE) pfo->pvConsumer)->ppdev = ppdev;
}
}
}
#endif
// Set FG / BG colors at this level
iFGColor = pboFore->iSolidColor;
iBGColor = pboOpaque->iSolidColor;
switch (ppdev->iBitmapFormat)
{
case BMF_8BPP:
iFGColor |= iFGColor << 8;
iBGColor |= iBGColor << 8;
case BMF_16BPP:
iFGColor |= iFGColor << 16;
iBGColor |= iBGColor << 16;
break;
}
iDComplexity = (pco == NULL) ? DC_TRIVIAL : pco->iDComplexity;
#if !(USE_ASM && defined(i386))
// Can we use the font cache?
if ( (pfo->pvConsumer != (PVOID) -1) && (iDComplexity != DC_COMPLEX)
&& (((PFONTCACHE) pfo->pvConsumer)->ppdev == ppdev))
{
// Set color registers.
REQUIRE(4);
LL_BGCOLOR(iBGColor, 2);
LL_FGCOLOR(iFGColor, 2);
if (prclOpaque != NULL)
{
#if LOG_CALLS
#define FIT_FLAGS (SO_ZERO_BEARINGS | \
SO_FLAG_DEFAULT_PLACEMENT | \
SO_MAXEXT_EQUAL_BM_SIDE | \
SO_CHAR_INC_EQUAL_BM_BASE)
bTextPerfectFit =
(pstro->flAccel & FIT_FLAGS) == FIT_FLAGS;
if (!(bTextPerfectFit) ||
(pstro->rclBkGround.top > prclOpaque->top) ||
(pstro->rclBkGround.left > prclOpaque->left) ||
(pstro->rclBkGround.right < prclOpaque->right) ||
(pstro->rclBkGround.bottom < prclOpaque->bottom))
{
LogFile((BUF, "FIT=N "));
}
else
{
LogFile((BUF, "FIT=Y "));
}
#endif
// Draw opaqueing rectangle.
if (iDComplexity == DC_TRIVIAL)
{
REQUIRE(7);
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 0);
LL_OP0(prclOpaque->left + ppdev->ptlOffset.x,
prclOpaque->top + ppdev->ptlOffset.y);
LL_BLTEXT(prclOpaque->right - prclOpaque->left,
prclOpaque->bottom - prclOpaque->top);
}
else
{
LONG x, y, cx, cy;
x = max(prclOpaque->left, pco->rclBounds.left);
y = max(prclOpaque->top, pco->rclBounds.top);
cx = min(prclOpaque->right, pco->rclBounds.right) - x;
cy = min(prclOpaque->bottom, pco->rclBounds.bottom) - y;
if ( (cx > 0) && (cy > 0) )
{
REQUIRE(7);
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 0);
LL_OP0(x + ppdev->ptlOffset.x, y + ppdev->ptlOffset.y);
LL_BLTEXT(cx, cy);
}
}
}
// Enable bit swizzling and set DRAWBLTDEF.
ppdev->grCONTROL |= SWIZ_CNTL;
LL16(grCONTROL, ppdev->grCONTROL);
REQUIRE(2);
LL_DRAWBLTDEF(CACHE_EXPAND_XPAR, 2);
LogFile((BUF, "UC"));
LogFile((BUF, "\r\n"));
// Call the font cache handler.
if (iDComplexity == DC_TRIVIAL)
{
FontCache((PFONTCACHE) pfo->pvConsumer, pstro);
}
else
{
ClipCache((PFONTCACHE) pfo->pvConsumer, pstro, pco->rclBounds);
}
// Disable bit swizzling.
ppdev->grCONTROL = ppdev->grCONTROL & ~SWIZ_CNTL;
LL16(grCONTROL, ppdev->grCONTROL);
return(TRUE);
}
#endif
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting FG/BG Color.\n"));
REQUIRE(4);
LL_BGCOLOR(iBGColor, 2);
LL_FGCOLOR(iFGColor, 2);
ppdev->grCONTROL |= SWIZ_CNTL;
LL16(grCONTROL, ppdev->grCONTROL);
if (prclOpaque != NULL)
{
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting Opaque.\n"));
////////////////////////////////////////////////////////////
// Opaque Initialization
////////////////////////////////////////////////////////////
//
// If we paint the glyphs in 'opaque' mode, we may not actually
// have to draw the opaquing rectangle up-front -- the process
// of laying down all the glyphs will automatically cover all
// of the pixels in the opaquing rectangle.
//
// The condition that must be satisfied is that the text must
// fit 'perfectly' such that the entire background rectangle is
// covered, and none of the glyphs overlap (if the glyphs
// overlap, such as for italics, they have to be drawn in
// transparent mode after the opaquing rectangle is cleared).
//
#define PERFECT_FIT_FLAGS (SO_ZERO_BEARINGS | \
SO_FLAG_DEFAULT_PLACEMENT | \
SO_MAXEXT_EQUAL_BM_SIDE | \
SO_CHAR_INC_EQUAL_BM_BASE)
bTextPerfectFit =
(pstro->flAccel & PERFECT_FIT_FLAGS) == PERFECT_FIT_FLAGS;
if (!(bTextPerfectFit) ||
(pstro->rclBkGround.top > prclOpaque->top) ||
(pstro->rclBkGround.left > prclOpaque->left) ||
(pstro->rclBkGround.right < prclOpaque->right)||
(pstro->rclBkGround.bottom < prclOpaque->bottom))
{
//
// Draw opaquing rectangle.
//
if (iDComplexity == DC_TRIVIAL)
{
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Opaque DC_TRIVIAL.\n"));
REQUIRE(7);
LL_DRAWBLTDEF(SOLID_COLOR_FILL, 0);
LL_OP0(prclOpaque->left + ppdev->ptlOffset.x,
prclOpaque->top + ppdev->ptlOffset.y);
LL_BLTEXT ((prclOpaque->right - prclOpaque->left) ,
(prclOpaque->bottom - prclOpaque->top) );
}
else
{
vClipSolid(ppdev, 1, prclOpaque, pboOpaque->iSolidColor, pco);
}
LogFile((BUF, "FIT=N "));
// Opaquing rectangle has been drawn, now
// we do transparent text.
}
else
{
LogFile((BUF, "FIT=Y "));
// We don't have to draw the opaquing rectangle because
// the text is an exact fit.
goto TextInitOpaque;
}
} // End (prclOpaque != NULL)
LogFile((BUF, "\r\n"));
////////////////////////////////////////////////////////////
// Transparent Initialization
////////////////////////////////////////////////////////////
// Initialize the hardware for transparent text:
//
// Set the chip up to do transparent text.
//
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting XPAR Text.\n"));
LL_DRAWBLTDEF(TEXT_EXPAND_XPAR, 2);
goto TextInitDone;
TextInitOpaque:
//
// Set the chip up to do opaque text.
// Any opaquing rectangle needed has been drawn by now.
//
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Setting Opaque Text.\n"));
LL_DRAWBLTDEF(TEXT_EXPAND_OPAQUE, 2);
TextInitDone:
//
// We're all set up to do either opaque or transparent text.
// If necessary, any opaquing has been done by now.
// So let's draw some glyphs on the screen.
//
REQUIRE(2);
LL_OP2_MONO (0,0); // Set Zero phase for transfers
if (iDComplexity == DC_TRIVIAL)
{
do // Loop while there are glyphs to draw.
{
//
// Get a batch of glyphs to draw.
//
if (pstro->pgp != NULL)
{
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: One batch of Glyphs.\n"));
// There's only the one batch of glyphs, so save ourselves
// a call:
pgp = pstro->pgp;
cGlyph = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
DISPDBG((TEXT_DBG_LEVEL1,
"DrvTextOut: Calling STROBJ_bEnum for Glyphs.\n"));
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
}
//
// cGlyph is the count of glyphs in this batch.
// bMorGlyphs is TRUE if there is another batch waiting for
// us after this one.
//
if (cGlyph > 0)
{
//
// Check the type of spacing.
//
if (pstro->ulCharInc == 0)
{
///////////////////////////////////////////////////////////
// Proportional Spacing
DISPDBG((TEXT_DBG_LEVEL1,
"DrvTextOut: Proportional Spacing.\n"));
while (TRUE) // Loop once for each Glyph.
{
pgb = pgp->pgdf->pgb;
LogFile((BUF, "GC:M\r\n"));
#if !SWAT7
REQUIRE(5);
LL_OP0(pgp->ptl.x + pgb->ptlOrigin.x + ppdev->ptlOffset.x,
pgp->ptl.y + pgb->ptlOrigin.y + ppdev->ptlOffset.y);
LL_BLTEXT (pgb->sizlBitmap.cx, pgb->sizlBitmap.cy);
#endif
#if SWAT7
xOrigin = pgp->ptl.x + pgb->ptlOrigin.x;
cxGlyph = pgb->sizlBitmap.cx;
lDelta = (cxGlyph + 7) >> 3;
#endif
pjGlyph = pgb->aj;
cyGlyph = pgb->sizlBitmap.cy;
#if SWAT7
//
// Test for 5465AD hardware bug in 8-bpp.
//
if ( (cxGlyph > 64) && (cxGlyph < 128)
&& (ppdev->iBytesPerPixel == 1)
)
{
Xfer64Pixels(ppdev, xOrigin, pgp->ptl.y +
pgb->ptlOrigin.y, 0, cyGlyph, pjGlyph,
cxGlyph);
pjGlyph += 64 / 8;
xOrigin += 64;
cxGlyph -= 64;
}
REQUIRE(5);
LL_OP0(xOrigin + ppdev->ptlOffset.x, pgp->ptl.y +
pgb->ptlOrigin.y + ppdev->ptlOffset.y);
LL_BLTEXT (cxGlyph, cyGlyph);
#endif
// The monochrome bitmap describing the glyph is
// byte-aligned. This means that if the glyph is
// 1 to 8 pels in width, each row of the glyph is
// defined in consecutive bytes; if the glyph is 9
// to 16 pels in width, each row of the glyph is
// defined in consecutive words, etc.
//
#if SWAT7
if (cxGlyph <= 8)
#else
if (pgb->sizlBitmap.cx <= 8)
#endif
{
//--------------------------------------------------
// 1 to 8 pels in width
// 91% of all glyphs will go through this path.
while (cyGlyph--)
#if SWAT7
{
REQUIRE(1);
LL32(grHOSTDATA[0], *pjGlyph);
pjGlyph += lDelta;
}
#else
REQUIRE(1);
LL32 (grHOSTDATA[0], *pjGlyph++);
// We're a bit tricky here in order to avoid letting
// the compiler tail-merge this code (which would
// add an extra jump):
pgp++;
if (--cGlyph != 0)
continue; // Go do the next glyph.
break; // Done with all glyphs in this batch.
// breakout of Glyph Loop.
#endif
}
#if SWAT7
else if (cxGlyph <= 16)
#else
else if (pgb->sizlBitmap.cx <= 16)
#endif
{
//--------------------------------------------------
// 9 to 16 pels in width
// 5% of all glyphs will go through this path.
while ( cyGlyph-- )
#if SWAT7
{
REQUIRE(1);
LL32(grHOSTDATA[0], *(USHORT*)pjGlyph);
pjGlyph += lDelta;
}
#else
REQUIRE(1);
LL32 (grHOSTDATA[0], *((USHORT*)pjGlyph)++);
#endif
}
else
{
//--------------------------------------------------
// More than 16 pels in width
#if SWAT7
cw = (cxGlyph + 31) >> 5;
#else
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
cw = (lDelta + 3) >> 2;
#endif
pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
for (;cyGlyph!=1; cyGlyph--)
{
WRITE_STRING(pjGlyph, cw);
pjGlyph += lDelta;
}
{
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
WRITE_STRING(pjGlyph, cw - 1);
if ((BYTE *)pSrc+4<=pTmp)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *pSrc++ );
}
else
{
int Extra = (ULONG) pTmp - (ULONG) pSrc;
BYTE * pByte = (BYTE *)pSrc;
ULONG ulData;
DISPDBG((TEXT_DBG_LEVEL1,
"Caught it %s %d %d %x %x\n", __FILE__, __LINE__, Extra, pTmp, pSrc));
if (Extra == 1)
ulData = (ULONG)(*pByte);
else if (Extra == 2)
ulData = (ULONG)(*(USHORT*)pByte);
else
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
REQUIRE(1);
LL32 (grHOSTDATA[0], ulData );
}
}
} // END pel width test.
pgp++; // Next glyph
if (--cGlyph == 0)
break; // Done with this batch.
// Break out of the Glyph Loop.
} // End Glyph Loop.
} // End porportional characters.
else
{
////////////////////////////////////////////////////////////
// Mono Spacing
DISPDBG((TEXT_DBG_LEVEL1,"DrvTextOut: Mono Spacing.\n"));
ulCharInc = pstro->ulCharInc;
pgb = pgp->pgdf->pgb;
ptlOrigin.x = pgb->ptlOrigin.x + pgp->ptl.x;
ptlOrigin.y = pgb->ptlOrigin.y + pgp->ptl.y;
while (TRUE) // Loop once for each Glyph in the batch.
{
LogFile((BUF, "GC:M\r\n"));
pgb = pgp->pgdf->pgb;
#if !SWAT7
REQUIRE(5);
LL_OP0(ptlOrigin.x + ppdev->ptlOffset.x,
ptlOrigin.y + ppdev->ptlOffset.y);
ptlOrigin.x += ulCharInc;
LL_BLTEXT (pgb->sizlBitmap.cx, pgb->sizlBitmap.cy);
#endif
pjGlyph = pgb->aj;
cyGlyph = pgb->sizlBitmap.cy;
#if SWAT7
xOrigin = ptlOrigin.x;
cxGlyph = pgb->sizlBitmap.cx;
lDelta = (cxGlyph + 7) >> 3;
//
// Test for 5465AD hardware bug in 8-bpp.
//
if ( (cxGlyph > 64) && (cxGlyph < 128)
&& (ppdev->iBytesPerPixel == 1)
)
{
Xfer64Pixels(ppdev, xOrigin, ptlOrigin.y, 0,
cyGlyph, pjGlyph, cxGlyph);
pjGlyph += 64 / 8;
xOrigin += 64;
cxGlyph -= 64;
}
REQUIRE(5);
LL_OP0(xOrigin + ppdev->ptlOffset.x,
ptlOrigin.y + ppdev->ptlOffset.y);
ptlOrigin.x += ulCharInc;
LL_BLTEXT (cxGlyph, cyGlyph);
#endif
//
// Note: Mono spacing does not guarantee that all the
// glyphs are the same size -- that is, we cannot
// move the size check out of this inner loop,
// unless we key off some more of the STROBJ
// accelerator flags.
// We are not guarenteed the Glyphs are the same size,
// only that they are the same distance apart.
//
#if SWAT7
if (cxGlyph <= 8)
#else
if (pgb->sizlBitmap.cx <= 8)
#endif
{
//-----------------------------------------------------
// 1 to 8 pels in width
while ( cyGlyph-- )
#if SWAT7
{
REQUIRE(1);
LL32(grHOSTDATA[0], *pjGlyph);
pjGlyph += lDelta;
}
#else
REQUIRE(1);
LL32 (grHOSTDATA[0], *pjGlyph++);
#endif
}
#if SWAT7
else if (cxGlyph <= 16)
#else
else if (pgb->sizlBitmap.cx <= 16)
#endif
{
//-----------------------------------------------------
// 9 to 16 pels in width
while ( cyGlyph-- )
#if SWAT7
{
REQUIRE(1);
LL32(grHOSTDATA[0], *(USHORT*)pjGlyph);
pjGlyph += lDelta;
}
#else
REQUIRE(1);
LL32 (grHOSTDATA[0], *((USHORT*)pjGlyph)++);
#endif
}
else
{
//-----------------------------------------------------
// More than 16 pels in width
#if SWAT7
cw = (cxGlyph + 31) >> 5;
#else
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
cw = (lDelta + 3) >> 2;
#endif
pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
for (;cyGlyph!=1; cyGlyph--)
{
WRITE_STRING(pjGlyph, cw);
pjGlyph += lDelta;
}
{
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
WRITE_STRING(pjGlyph, cw - 1);
if ((BYTE *)pSrc+4<=pTmp)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *pSrc++ );
}
else
{
int Extra = (ULONG) pTmp - (ULONG) pSrc;
BYTE * pByte = (BYTE *)pSrc;
ULONG ulData;
DISPDBG((TEXT_DBG_LEVEL1,
"Caught it %s %d %d %x %x\n",
__FILE__, __LINE__, Extra, pTmp, pSrc));
if (Extra == 1)
ulData = (ULONG)(*pByte);
else if (Extra == 2)
ulData = (ULONG)(*(USHORT*)pByte);
else
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
REQUIRE(1);
LL32 (grHOSTDATA[0], ulData );
}
}
} // End more than 16 pels wide.
pgp++;
if (--cGlyph == 0) // We are done with this batch
break; // of glyphs. Break out of the glyph loop.
} // End Glyph Loop.
} // End Mono Spacing.
} // End if (cGlyph > 0)
//
// Done with this batch of Glyphs.
// Go get the next one.
//
} while (bMoreGlyphs);
} // End DC_TRIVIAL
else
{
// If there's clipping, call off to a function:
vMmClipGlyphExpansion(ppdev, pstro, pco);
}
ppdev->grCONTROL = ppdev->grCONTROL & ~SWIZ_CNTL;
LL16(grCONTROL, ppdev->grCONTROL);
return(TRUE);
} // End DrvTextOut.
/******************************Public*Routine******************************\
* BOOL bEnableText
*
* Performs the necessary setup for the text drawing subcomponent.
*
\**************************************************************************/
BOOL bEnableText(
PDEV* ppdev)
{
// Our text algorithms require no initialization. If we were to
// do glyph caching, we would probably want to allocate off-screen
// memory and do a bunch of other stuff here.
DISPDBG((TEXT_DBG_LEVEL,"bEnableText: Entry.\n"));
#if RECORD_ON
LL( RECORD, 1); // Switch on
LL( RECORD, 2); // Pause
DISPDBG((TEXT_DBG_LEVEL1,"xbEnableText: Recording Paused.\n"));
#endif
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'.
DISPDBG((TEXT_DBG_LEVEL,"vDisableText: Entry.\n"));
}
#if !SWAT3
#pragma optimize("", off) // Microsoft doesn't know how to do compile...
#endif
/******************************Public*Routine******************************\
* VOID vAssertModeText
*
* Disables or re-enables the text drawing subcomponent in preparation for
* full-screen entry/exit.
*
\**************************************************************************/
VOID vAssertModeText(
PDEV* ppdev,
BOOL bEnable)
{
#if SWAT3
SIZEL sizl;
POINTL pos;
int i;
if (bEnable)
{
// We are enabling the screen again, so allocate the font cache if it
// is not yet allocated.
if (ppdev->pofmFontCache == NULL)
{
#if MEMMGR
sizl.cx = ppdev->lDeltaScreen / FONTCELL_X;
#else
//sizl.cx = ppdev->cxMemory;
sizl.cx = ppdev->lDeltaScreen / ppdev->iBytesPerPixel / FONTCELL_X;
#endif
sizl.cy = (FONTCELL_COUNT + sizl.cx - 1) / sizl.cx;
sizl.cx *= FONTCELL_X;
sizl.cy *= FONTCELL_Y;
ppdev->pofmFontCache = AllocOffScnMem(ppdev, &sizl, 0, NULL);
//ppdev->pofmFontCache = AllocOffScnMem(ppdev, &sizl,
// PIXEL_AlIGN, NULL);
}
if (ppdev->pofmFontCache != NULL)
{
// Clear the entire font cell array.
pos.x = pos.y = 0;
for (i = 0; i < FONTCELL_COUNT; i++)
{
if (pos.y >= sizl.cy)
{
ppdev->fcGrid[i].x = 0;
ppdev->fcGrid[i].y = 0;
ppdev->fcGrid[i].pfc = (PFONTCACHE) -1;
}
else
{
ppdev->fcGrid[i].x = ppdev->pofmFontCache->x + pos.x;
ppdev->fcGrid[i].y = ppdev->pofmFontCache->y + pos.y;
ppdev->fcGrid[i].pfc = NULL;
ppdev->fcGrid[i].ulLastX = 0;
ppdev->fcGrid[i].pNext = NULL;
pos.x += FONTCELL_X;
if (pos.x >= (LONG) ppdev->cxMemory)
{
pos.x = 0;
pos.y += FONTCELL_Y;
}
}
}
}
}
else
{
// We are disabling the screen so destroy all cached fonts.
if (ppdev->pofmFontCache != NULL)
{
for (i = 0; i < FONTCELL_COUNT; i++)
{
if ( (ppdev->fcGrid[i].pfc != NULL)
&& (ppdev->fcGrid[i].pfc != (PFONTCACHE) -1)
)
{
DrvDestroyFont(ppdev->fcGrid[i].pfc->pfo);
}
}
// Free the font cache cells.
FreeOffScnMem(ppdev, ppdev->pofmFontCache);
ppdev->pofmFontCache = NULL;
}
}
#elif !SWAT3
if (!bEnable)
{
// Remove all chained fonts.
PFONTCACHE p = ppdev->pfcChain;
while (p != NULL)
{
DrvDestroyFont(p->pfo);
p = ppdev->pfcChain;
}
}
#endif // SWAT3
}
#if !SWAT3
#pragma optimize("", on)
#endif
#if SWAT3
/******************************************************************************\
* PFONTCELL fcAllocCell(PFONTCACGE pfc)
*
* Allocate a font cell for the given font cache. Returns NULL if there are no
* more empty font cells.
\******************************************************************************/
PFONTCELL fcAllocCell(PFONTCACHE pfc)
{
int i;
PPDEV ppdev = pfc->ppdev;
PFONTCELL p = ppdev->fcGrid;
if (ppdev->pofmFontCache == NULL)
{
// Font cache is disabled, return NULL.
return NULL;
}
for (i = 0; i < FONTCELL_COUNT; i++, p++)
{
if (p->pfc == NULL)
{
p->pfc = pfc;
return p;
}
}
return NULL;
}
/******************************************************************************\
* void fcFreeCell(PFONTCELL pCell)
*
* Mark the given font cell as free.
\******************************************************************************/
void fcFreeCell(PFONTCELL pCell)
{
pCell->pfc = NULL;
pCell->ulLastX = 0;
pCell->pNext = NULL;
}
#endif // SWAT3
/******************************Public*Routine******************************\
* VOID DrvDestroyFont
*
* We're being notified that the given font is being deallocated; clean up
* anything we've stashed in the 'pvConsumer' field of the 'pfo'.
*
\**************************************************************************/
VOID DrvDestroyFont(FONTOBJ *pfo)
{
DISPDBG((TEXT_DBG_LEVEL, "DrvDestroyFont Entry\n"));
if (pfo->pvConsumer != NULL && pfo->pvConsumer != (PVOID) -1)
{
PFONTCACHE pfc = (PFONTCACHE) pfo->pvConsumer;
#if SWAT3
PFONTCELL pCell, pCellNext;
#else
PFONTMEMORY pfm, pfmNext;
#endif
PPDEV ppdev;
ppdev = pfc->ppdev;
LogFile((BUF, "DrvDestroyFont: "));
#if SWAT3
for (pCell = pfc->pFontCell; pCell != NULL; pCell = pCellNext)
{
pCellNext = pCell->pNext;
fcFreeCell(pCell);
}
LogFile((BUF, "\r\n"));
#else
for (pfm = pfc->pFontMemory; pfm != NULL; pfm = pfmNext)
{
pfmNext = pfm->pNext;
if (pfm->pTile != NULL)
{
FreeOffScnMem(pfc->ppdev, pfm->pTile);
}
MEMORY_FREE(pfm);
}
// Unhook the font cache from the chain.
if (pfc->pfcPrev != NULL)
{
pfc->pfcPrev->pfcNext = pfc->pfcNext;
}
else
{
ppdev->pfcChain = pfc->pfcNext;
}
if (pfc->pfcNext != NULL)
{
pfc->pfcNext->pfcPrev = pfc->pfcPrev;
}
#endif
LogFile((BUF, "\r\n"));
MEMORY_FREE(pfc);
}
pfo->pvConsumer = NULL;
DISPDBG((TEXT_DBG_LEVEL, "DrvDestroyFont Exit\n"));
}
/*
* GetGlyphSize
*
* Get the size (in pixels) of the requested glyph. Return the width of the
* glyph in bytes or 0 if the glyph is too big to cache.
*
*/
long GetGlyphSize(
GLYPHBITS* pgb, // Pointer to glyph.
POINTL* pptlOrigin, // Pointer to return origin in.
DWORD* pcSize // Pointer to return size in.
)
{
long x, y, height = 0;
BYTE* pByte = pgb->aj;
int i;
x = (pgb->sizlBitmap.cx + 7) >> 3; // get width in bytes
if (x > 0)
{
// find first line in glyph that contains data
for (y = 0; y < pgb->sizlBitmap.cy; y++, pByte += x)
{
// walk trough every byte on a line
for (i = 0; i < x; i++)
{
if (pByte[i]) // we have data, so we are at the first line
{
// find the last line in te glyph that contains data
height = pgb->sizlBitmap.cy - y;
for (pByte += (height - 1) * x; height > 0; height--)
{
// walk trough every byte on a line
for (i = 0; i < x; i++)
{
if (pByte[i])
{
// test height of glyph
#if SWAT3
if (height > FONTCELL_Y)
#else
if (height > LINES_PER_TILE)
#endif
{
// glyph too big, mark it as uncacheable
*pcSize = (DWORD) -1;
return(0);
}
// fill return parameters
pptlOrigin->y = y;
*pcSize = PACK_XY(pgb->sizlBitmap.cx, height);
return(x);
}
}
pByte -= x;
}
}
}
}
}
// glyph is empty
*pcSize = 0;
return(0);
}
/*
* AllocFontCache
*
* Allocate the requsted memory in off-screen memory. Return TRUE and the x,y
* coordinates of the upper left corner of this region, or FALSE if there is
* not enough memory.
*
*/
BOOL AllocFontCache(
PFONTCACHE pfc, // Pointer to font cache.
long cWidth, // Width (in bytes) to allocate.
long cHeight, // Height to allocate.
POINTL* ppnt // Point to return cooridinate in.
)
{
#if SWAT3
PFONTCELL pCell;
#else
SIZEL sizl;
PFONTMEMORY pfm;
#endif
long x;
PPDEV ppdev = pfc->ppdev;
#if !SWAT3
if (ppdev->iBytesPerPixel == 3)
{
sizl.cx = (128 + 2) / 3;
}
else
{
sizl.cx = 128 / ppdev->iBytesPerPixel;
}
sizl.cy = 16;
#endif
#if SWAT3
if (pfc->pFontCell == NULL)
{
pfc->pFontCell = fcAllocCell(pfc);
}
#else
if (pfc->pFontMemory == NULL)
{
pfc->pFontMemory = (PFONTMEMORY)
#ifdef WINNT_VER40
MEM_ALLOC(FL_ZERO_MEMORY, sizeof(FONTMEMORY), ALLOC_TAG);
#else
MEM_ALLOC(LMEM_FIXED | LMEM_ZEROINIT, sizeof(FONTMEMORY));
#endif
}
#endif
#if SWAT3
for (pCell = pfc->pFontCell; pCell != NULL; pCell = pCell->pNext)
{
x = pCell->ulLastX;
if (x + cWidth <= FONTCELL_X)
{
pCell->ulLastX += cWidth;
ppnt->x = pCell->x + x;
ppnt->y = pCell->y;
return TRUE;
}
if (pCell->pNext == NULL)
{
pCell->pNext = fcAllocCell(pfc);
}
}
#else
for (pfm = pfc->pFontMemory; pfm; pfm = pfm->pNext)
{
if (pfm->pTile == NULL)
{
#ifdef ALLOC_IN_CREATESURFACE
if (!ppdev->bDirectDrawInUse)
#endif
pfm->pTile = AllocOffScnMem(ppdev, &sizl, PIXEL_AlIGN, NULL);
if (pfm->pTile == NULL)
{
return FALSE;
}
ppnt->x = pfm->pTile->x;
ppnt->y = pfm->pTile->y;
pfm->ulLastX = cWidth;
return TRUE;
}
x = pfm->ulLastX;
if (x + cWidth <= BYTES_PER_TILE)
{
pfm->ulLastX += cWidth;
ppnt->x = pfm->pTile->x + x;
ppnt->y = pfm->pTile->y;
return TRUE;
}
if (pfm->pNext == NULL)
{
pfm->pNext = (PFONTMEMORY)
#ifdef WINNT_VER40
MEM_ALLOC(FL_ZERO_MEMORY, sizeof(FONTMEMORY), ALLOC_TAG);
#else
MEM_ALLOC(LMEM_FIXED | LMEM_ZEROINIT, sizeof(FONTMEMORY));
#endif
}
}
#endif
return FALSE;
}
/*
* AllocGlyph
*
* Allocate memory for the requested glyph and copy the glyph into off-screen
* memory. If there is not enough off-screen memory left, or the glyph is too
* large to glyph, return FALSE, otherwise return TRUE.
*
*/
VOID AllocGlyph(
PFONTCACHE pfc, // pointer to font cache
GLYPHBITS* pgb, // pointer to glyph to cache
GLYPHCACHE* pgc // pointer to glyph cache structure
)
{
long cBytes;
BYTE *pOffScreen, *pSrc;
long y;
PDEV *ppdev;
POINTL pointl;
ppdev = pfc->ppdev;
cBytes = GetGlyphSize(pgb, &pgc->ptlOrigin, &pgc->cSize);
if (cBytes == 0)
{
pgc->xyPos = (DWORD) -1;
LogFile((BUF, "GC:F\r\n"));
return;
}
if (AllocFontCache(pfc, cBytes, pgc->cSize >> 16, &pointl) == FALSE)
{
pgc->cSize = (DWORD) -1;
LogFile((BUF, "GC:F\r\n"));
return;
}
pOffScreen = ppdev->pjScreen + pointl.x + pointl.y * ppdev->lDeltaScreen;
pSrc = &pgb->aj[pgc->ptlOrigin.y * cBytes];
y = (long) (pgc->cSize >> 16);
if (cBytes == sizeof(BYTE))
{
while (y-- > 0)
{
*pOffScreen = Swiz[*pSrc];
pOffScreen += ppdev->lDeltaScreen;
pSrc += sizeof(BYTE);
}
}
else
{
while (y-- > 0)
{
long lDelta = ppdev->lDeltaScreen - cBytes;
long i;
for (i = cBytes; i > 0; i--)
{
*pOffScreen++ = Swiz[*pSrc++];
}
pOffScreen += lDelta;
}
}
pgc->xyPos = PACK_XY(pointl.x * 8, pointl.y);
pgc->ptlOrigin.x = pgb->ptlOrigin.x;
pgc->ptlOrigin.y += pgb->ptlOrigin.y;
LogFile((BUF, "GC:S\r\n"));
}
#if !(USE_ASM && defined(i386))
/*
* FontCache
*
* Draw glyphs using the off-screen font cache.
*
*/
VOID FontCache(
PFONTCACHE pfc, // Pointer to font cache.
STROBJ* pstro // Pointer to glyphs.
)
{
PDEV* ppdev;
BOOL bMoreGlyphs = TRUE;
ULONG cGlyph;
GLYPHPOS* pgp;
POINTL ptlOrigin;
PGLYPHCACHE pgc;
ULONG ulCharInc;
// set pointer to physical device
ppdev = pfc->ppdev;
// loop until there are no more glyphs to process
while (bMoreGlyphs)
{
if (pstro->pgp != NULL)
{
// we have just one set of glyphs
pgp = pstro->pgp;
cGlyph = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
// enumerate a set of glyphs
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
}
if (pstro->ulCharInc)
{
// fixed fonts... get x and y coordinates of first glyph
ptlOrigin.x = pgp->ptl.x;
ptlOrigin.y = pgp->ptl.y;
// get glyph increment
ulCharInc = pstro->ulCharInc;
// walk through all glyphs
while (cGlyph-- > 0)
{
if (pgp->hg < MAX_GLYPHS)
{
// this glyph index is cacheable
pgc = &pfc->aGlyphs[pgp->hg];
if (pgc->xyPos == 0)
{
// cache the glyph
AllocGlyph(pfc, pgp->pgdf->pgb, pgc);
}
if ((long) pgc->cSize > 0)
{
LogFile((BUF, "GC:H\r\n"));
// the glyph is cached, blit it on the screen
REQUIRE(7);
LL_OP0(ptlOrigin.x + pgc->ptlOrigin.x + ppdev->ptlOffset.x,
ptlOrigin.y + pgc->ptlOrigin.y + ppdev->ptlOffset.y);
LL32 (grOP2_opMRDRAM, pgc->xyPos);
LL32 (grBLTEXT_EX.dw, pgc->cSize);
}
else if ((long) pgc->cSize == -1)
{
// the glyph is uncacheable, draw it directly
DrawGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin);
}
}
else
{
// the glyph index is out of range, draw it directly
DrawGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin);
}
// increment glyph x coordinate
ptlOrigin.x += ulCharInc;
// next glyph
pgp++;
}
}
else
{
// variable width fonts, walk trough all glyphs
while (cGlyph-- > 0)
{
if (pgp->hg < MAX_GLYPHS)
{
// this glyph index is cacheable
pgc = &pfc->aGlyphs[pgp->hg];
if (pgc->xyPos == 0)
{
// cache the glyph
AllocGlyph(pfc, pgp->pgdf->pgb, pgc);
}
if ((long) pgc->cSize > 0)
{
LogFile((BUF, "GC:H\r\n"));
// the glyph is cached, blit it on the screen
REQUIRE(7);
LL_OP0(pgp->ptl.x + pgc->ptlOrigin.x + ppdev->ptlOffset.x,
pgp->ptl.y + pgc->ptlOrigin.y + ppdev->ptlOffset.y);
LL32 (grOP2_opMRDRAM, pgc->xyPos);
LL32 (grBLTEXT_EX.dw, pgc->cSize);
}
else if ((long) pgc->cSize == -1)
{
// the glyph is uncacheable, draw it directly
DrawGlyph(ppdev, pgp->pgdf->pgb, pgp->ptl);
}
}
else
{
// the glyph index is out of range, draw it directly
DrawGlyph(ppdev, pgp->pgdf->pgb, pgp->ptl);
}
// next glyph
pgp++;
}
}
}
}
/*
* DrawGlyph
*
* Draw glyphs directly on the screen.
*
*/
VOID DrawGlyph(
PDEV* ppdev, // Pointer to physical device.
GLYPHBITS* pgb, // Pointer to glyph to draw.
POINTL ptl // Location of glyph.
)
{
BYTE* pjGlyph;
ULONG cyGlyph;
#if SWAT7
ULONG cxGlyph;
ULONG xOrigin;
LONG lDelta;
#endif
LogFile((BUF, "GC:M\r\n"));
#if SWAT7
xOrigin = ptl.x + pgb->ptlOrigin.x;
cxGlyph = pgb->sizlBitmap.cx;
cyGlyph = pgb->sizlBitmap.cy;
pjGlyph = pgb->aj;
lDelta = (cxGlyph + 7) >> 3;
#endif
// start the blit
REQUIRE(4);
LL_DRAWBLTDEF(TEXT_EXPAND_XPAR, 0);
LL_OP2_MONO(0, 0);
#if !SWAT7
REQUIRE(5);
LL_OP0(ptl.x + pgb->ptlOrigin.x + ppdev->ptlOffset.x,
ptl.y + pgb->ptlOrigin.y + ppdev->ptlOffset.y);
LL_BLTEXT(pgb->sizlBitmap.cx, pgb->sizlBitmap.cy);
pjGlyph = pgb->aj;
cyGlyph = pgb->sizlBitmap.cy;
#endif
#if SWAT7
//
// Test for 5465AD hardware bug in 8-bpp.
//
if ( (cxGlyph > 64) && (cxGlyph < 128)
&& (ppdev->iBytesPerPixel == 1)
)
{
Xfer64Pixels(ppdev, xOrigin, ptl.y + pgb->ptlOrigin.y, 0, cyGlyph,
pjGlyph, cxGlyph);
pjGlyph += 64 / 8;
xOrigin += 64;
cxGlyph -= 64;
}
REQUIRE(5);
LL_OP0(xOrigin + ppdev->ptlOffset.x,
ptl.y + pgb->ptlOrigin.y + ppdev->ptlOffset.y);
LL_BLTEXT(cxGlyph, cyGlyph);
#endif
#if SWAT7
if (cxGlyph <= 8)
#else
if (pgb->sizlBitmap.cx <= 8)
#endif
{
// just one byte per line
while (cyGlyph--)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *pjGlyph);
#if SWAT7
pjGlyph += lDelta;
#else
pjGlyph++;
#endif
}
}
#if SWAT7
else if (cxGlyph <= 16)
#else
else if (pgb->sizlBitmap.cx <= 16)
#endif
{
// just two bytes per line
while (cyGlyph--)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *(WORD *) pjGlyph);
#if SWAT7
pjGlyph += lDelta;
#else
pjGlyph += 2;
#endif
}
}
#if SWAT7
else if (cxGlyph <= 24)
#else
else if (pgb->sizlBitmap.cx <= 24)
#endif
{
// just three bytes per line
while (cyGlyph--)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *(DWORD *) pjGlyph);
#if SWAT7
pjGlyph += lDelta;
#else
pjGlyph += 3;
#endif
}
}
#if SWAT7
else if (cxGlyph <= 32)
#else
else if (pgb->sizlBitmap.cx <= 32)
#endif
{
// just four bytes per line
while (cyGlyph--)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *(DWORD *) pjGlyph);
#if SWAT7
pjGlyph += lDelta;
#else
pjGlyph += 4;
#endif
}
}
else
{
// any number of bytes per line
#if SWAT7
int cw = (cxGlyph + 31) >> 5;
#else
long lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
int cw = (lDelta + 3) >> 2;
#endif
BYTE * pTmp = pjGlyph + lDelta * pgb->sizlBitmap.cy;
for (;cyGlyph!=1; cyGlyph--)
{
WRITE_STRING(pjGlyph, cw);
pjGlyph += lDelta;
}
{
ULONG *pSrc = (ULONG*) pjGlyph + cw - 1;
WRITE_STRING(pjGlyph, cw - 1);
if ((BYTE *)pSrc+4<=pTmp)
{
REQUIRE(1);
LL32 (grHOSTDATA[0], *pSrc++ );
}
else
{
int Extra = (ULONG) pTmp - (ULONG) pSrc;
BYTE * pByte = (BYTE *)pSrc;
ULONG ulData;
DISPDBG((TEXT_DBG_LEVEL1,
"Caught it %s %d %d %x %x\n",
__FILE__, __LINE__, Extra, pTmp, pSrc));
if (Extra == 1)
ulData = (ULONG)(*pByte);
else if (Extra == 2)
ulData = (ULONG)(*(USHORT*)pByte);
else
ulData = (((ULONG)*(pByte+2) << 8) | (ULONG)*(pByte+1)) << 8 | *pByte;
REQUIRE(1);
LL32 (grHOSTDATA[0], ulData );
}
}
}
// reset to transparent cache expansion
LL_DRAWBLTDEF(CACHE_EXPAND_XPAR, 2);
}
VOID ClipCache(
PFONTCACHE pfc, // Pointer to font cache.
STROBJ* pstro, // Pointer to glyphs.
RECTL rclBounds // Clipping rectangle.
)
{
PDEV* ppdev;
BOOL bMoreGlyphs = TRUE;
ULONG cGlyph;
GLYPHPOS* pgp;
POINTL ptlOrigin;
PGLYPHCACHE pgc;
ULONG ulCharInc;
// set pointer to physical device
ppdev = pfc->ppdev;
// loop until there are no more glyphs to process
while (bMoreGlyphs)
{
if (pstro->pgp != NULL)
{
// we have just one set of glyphs
pgp = pstro->pgp;
cGlyph = pstro->cGlyphs;
bMoreGlyphs = FALSE;
}
else
{
// enumerate a set of glyphs
bMoreGlyphs = STROBJ_bEnum(pstro, &cGlyph, &pgp);
}
// get x and y coordinates of first glyph
ptlOrigin.x = pgp->ptl.x;
ptlOrigin.y = pgp->ptl.y;
// get glyph increment
ulCharInc = pstro->ulCharInc;
// walk through all glyphs
while (cGlyph-- > 0)
{
if (pgp->hg < MAX_GLYPHS)
{
// this glyph index is cacheable
pgc = &pfc->aGlyphs[pgp->hg];
if (pgc->xyPos == 0)
{
// cache the glyph
AllocGlyph(pfc, pgp->pgdf->pgb, pgc);
}
if ((long) pgc->cSize > 0)
{
RECTL rcl;
LONG i, cx, cy;
ULONG xyPos;
// the glyph is cached, ckeck clipping
rcl.left = ptlOrigin.x + pgc->ptlOrigin.x;
rcl.top = ptlOrigin.y + pgc->ptlOrigin.y;
rcl.right = rcl.left + (pgc->cSize & 0x0000FFFF);
rcl.bottom = rcl.top + (pgc->cSize >> 16);
xyPos = pgc->xyPos;
i = rclBounds.left - rcl.left;
if (i > 0)
{
// the glyph is partially clipped on the left, draw it
// directly
ClipGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin, rclBounds);
}
else
{
LogFile((BUF, "GC:H\r\n"));
cx = min(rcl.right, rclBounds.right) - rcl.left;
if (cx > 0)
{
i = rclBounds.top - rcl.top;
if (i > 0)
{
rcl.top += i;
xyPos += i << 16;
}
cy = min(rcl.bottom, rclBounds.bottom) - rcl.top;
if (cy > 0)
{
REQUIRE(7);
LL_OP0(rcl.left + ppdev->ptlOffset.x,
rcl.top + ppdev->ptlOffset.y);
LL32(grOP2_opMRDRAM, xyPos);
LL_BLTEXT(cx, cy);
}
}
}
}
else if ((long) pgc->cSize == -1)
{
// the glyph is uncacheable, draw it directly
ClipGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin, rclBounds);
}
}
else
{
// the glyph index is out of range, draw it directly
ClipGlyph(ppdev, pgp->pgdf->pgb, ptlOrigin, rclBounds);
}
// next glyph
pgp++;
if (ulCharInc == 0)
{
ptlOrigin.x = pgp->ptl.x;
ptlOrigin.y = pgp->ptl.y;
}
else
{
// increment glyph x coordinate
ptlOrigin.x += ulCharInc;
}
}
}
}
VOID ClipGlyph(
PDEV* ppdev, // Pointer to physical device.
GLYPHBITS* pgb, // Pointer to glyph to draw.
POINTL ptl, // Location of glyph.
RECTL rclBounds // Clipping rectangle.
)
{
BYTE* pjGlyph;
LONG cx, cy, lDelta, i;
RECTL rcl;
ULONG xBit;
LogFile((BUF, "GC:M\r\n"));
rcl.left = ptl.x + pgb->ptlOrigin.x;
rcl.top = ptl.y + pgb->ptlOrigin.y;
rcl.right = rcl.left + pgb->sizlBitmap.cx;
rcl.bottom = rcl.top + pgb->sizlBitmap.cy;
xBit = 0;
pjGlyph = pgb->aj;
lDelta = (pgb->sizlBitmap.cx + 7) >> 3;
i = rclBounds.left - rcl.left;
if (i > 0)
{
pjGlyph += i >> 3;
xBit = i & 7;
rcl.left += i;
}
cx = min(rcl.right, rclBounds.right) - rcl.left;
if (cx > 0)
{
i = rclBounds.top - rcl.top;
if (i > 0)
{
pjGlyph += i * lDelta;
rcl.top += i;
}
cy = min(rcl.bottom, rclBounds.bottom) - rcl.top;
if (cy > 0)
{
// start the blit
REQUIRE(4);
LL_DRAWBLTDEF(TEXT_EXPAND_XPAR, 0);
LL_OP2(xBit, 0);
#if SWAT7
//
// Test for 5465AD hardware bug in 8-bpp.
//
if ((cx > 64) && (cx < 128) && (ppdev->iBytesPerPixel == 1))
{
Xfer64Pixels(ppdev, rcl.left, rcl.top, xBit, cy, pjGlyph,
pgb->sizlBitmap.cx);
pjGlyph += 64 / 8;
rcl.left += 64;
cx -= 64;
}
#endif
REQUIRE(5);
LL_OP0(rcl.left + ppdev->ptlOffset.x,
rcl.top + ppdev->ptlOffset.y);
LL_BLTEXT(cx, cy);
cx = (xBit + cx + 7) >> 3;
switch (cx)
{
case 1:
while (cy--)
{
REQUIRE(1);
LL32(grHOSTDATA[0], *(BYTE *) pjGlyph);
pjGlyph += lDelta;
}
break;
case 2:
while (cy--)
{
REQUIRE(1);
LL32(grHOSTDATA[0], *(WORD *) pjGlyph);
pjGlyph += lDelta;
}
break;
case 3:
case 4:
while (cy--)
{
REQUIRE(1);
LL32(grHOSTDATA[0], *(DWORD *) pjGlyph);
pjGlyph += lDelta;
}
break;
default:
while (cy--)
{
WRITE_STRING(pjGlyph, (cx + 3) / 4);
pjGlyph += lDelta;
}
break;
}
// reset to transparent cache expansion
REQUIRE(2);
LL_DRAWBLTDEF(CACHE_EXPAND_XPAR, 2);
}
}
}
#endif // !(USE_ASM && defined(i386))