/******************************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))