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