/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDNAATX                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor function handlers  */
/*                                                                    */
/*   Function        =                                                */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/

#define INCL_DDIMISC
#include <eddinclt.h>
#ifndef PALETTE_MGR

 /********************************************************************/
 /* NOTE:                                                            */
 /*                                                                  */
 /* SDBM20 changes have not been added to this file because AA text  */
 /* is not planned to be supported at 2.0.                           */
 /*                                                                  */
 /********************************************************************/

#include <edddtypt.h>
#include <eddecone.h>
#include <eddhcone.h>
#include <eddtcone.h>
#include <eddhtype.h>
#include <eddttypt.h>
#include <eddbextf.h>
#include <eddcextf.h>
#include <eddhextf.h>
#include <eddtextf.h>
#include <eddacone.h>
#include <eddhmacr.h>

#include <eddfcone.h>
#include <eddftype.h>

extern DDTType                DDT;
extern AATextPB               AIxfer;
extern BYTE                   SPad[];
extern HQMODE_DATA            hqmode_data;
extern lpPalette              PhysicalColorTable;

#ifdef CC20
extern ULONG   pSysCacheStartPhy ;
extern PBYTE   pSysCacheStart ;
extern ULONG   charCacheLength ;

/**********************************************************************/
/* Only the non-Seamless         version of the driver makes use of a */
/* VRAM character cache                                               */
/**********************************************************************/
#ifndef SEAMLESS

extern ULONG   pVRAMCacheStart ;

#endif /* ifndef SEAMLESS */

extern ULONG   offNextFree11Pos ;
extern ULONG   offLastFree81Pos ;

#pragma message( __FILE__"(70) : Warning : Not sure if pCurCacheBasePhy is set correctly")
/**********************************************************************/
/* pCurCacheBasePhy is the physical address of either the VRAM or     */
/* system memory character caches.  It is used within this module to  */
/* set the .CharCacheAddr and .CharMaskAddr fields of AIxfer.         */
/* This assumes that the underlying code is going to get the hardware */
/* to do the work - BUT I do not know if that is a valid assumption.  */
/**********************************************************************/
extern ULONG   pCurCacheBasePhy ;

#else /* CC20 */
extern ULONG                  pCacheStart;
extern ULONG                  pCacheEnd;
extern ULONG                  pCacheNextFreePos;
#endif /* CC20 */

extern BYTE                   WinToXWay[];
extern USHORT                  ResidentFonts;
extern USHORT                 DefaultFontListIndex;
extern POINTL                 MarkerCoords[];
extern ULONG                  data_seg_physical_base;

extern pMMReg                 AIBase ;
extern pMMReg                 AIBaseA ;
extern pMMReg                 AIBaseB ;
extern pMMReg                 AIBaseC ;

extern SHORT                  softDrawInUse ;
extern VOID                   eddf_MESS(VOID);

extern BYTE                   BlackOnWhiteColorRamp[];
extern BYTE                   WhiteOnBlackColorRamp[];

#ifdef SDBM20
extern SHORT                  foregroundSession ;
#endif /* SDBM20 */

extern pDrawFunctionsTable      pDrawFunctions ;

/**********************************************************************/
/* calls to PMLOCK/UNLOCK need parameters to be in locked memory      */
/* already - hence we put them in the data segment not as local       */
/* variables on the stack                                             */
/**********************************************************************/
static LockDataStruct     DAATLockData;   /* parameter to PMLOCK      */
static BitmapHeader       DAATLockInfo;   /* info used for locking def*/

USHORT PASCAL NEAR eddt_DrawAAText(SHORT *      pVector,
                                   BOOL         DrawMarkers)
{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
#define TFUNC "eddt_DrawAAText"
    pFontCacheInfoType pCacheInfo;      /* cache information for font */
    USHORT             i;               /* loop variable              */
    BOOL               XLateFound;      /* if XLate set up already    */
    BYTE               XLateToUse;      /* index of table to use      */
    BYTE               XLateToFree;     /* index of table to remove   */
    BYTE               FlagToFree;      /* flag of combination to free*/
    BYTE               FlagToUse;       /* flag of combination to use */
    ULONG              Font;            /* defset of current font     */
    BYTE               XLate[8];        /* local XLate table          */
    SHORT              CharCount;       /* Characters processed so far*/
    USHORT             CharOffset;      /* offset of char def in font */
    PBYTE              pCharDef1;       /* pointer to def in plane 1  */
    PBYTE              pCharDef2;       /* pointer to def in plane 2  */
    PBYTE              pCharDef3;       /* pointer to def in plane 3  */
    BYTE               LeftEnvelope;    /* values from the envelope   */
    BYTE               RightEnvelope;   /* table for this character   */
    USHORT             CacheCharSize;   /* size of cached definition  */
    BYTE               SrcByte1;        /* byte from char plane 1     */
    BYTE               SrcByte2;        /* byte from char plane 2     */
    BYTE               SrcByte3;        /* byte from char plane 3     */
    BYTE               CurrBitPos;      /* mask for bit from src byte */
    BYTE               BitsToProcess;   /* bits remaining on row      */
    BYTE               BitsFromByte;    /* bits to take from SrcByte's*/
    PBYTE              pPixelDef;       /* pixel definition of char   */
    PBYTE              pMaskDef;        /* mask for charcter          */
    ULONG              pCharLog;        /* logical address fo char    */
    BYTE               TrgIndex;        /* XLATE index for pel        */
    BYTE               CodePoint;       /* code point being processed */
    USHORT             BltWidth;        /* width of data being blt'ed */
    ULONG              pCharVRAM;       /* VRAM location of character */
    USHORT             MaskSize;        /* size of character mask     */
    USHORT             PixDefSize;      /* size of pixel definition   */
    BYTE               MaskBit;         /* character mask bit to set  */
    SHORT              LastX;           /* xcoord before DrawGiantText*/
    SHORT              LastY;           /* ycoord before DrawGiantText*/
    PBYTE              pCharDefSeg;     /* segment for cached defn    */
    USHORT             GlyphIndex;      /* glyph index being output   */
    USHORT             RetCode;         /* return code from procedure */
#ifdef CC20
    USHORT             BltHeight;
    ULONG              offCharImage ;
    ULONG              offCharMask ;
    PBYTE              pCharImage ;
    PBYTE              pCharMask ;
#endif /* CC20 */

    /******************************************************************/
    /* Get access to the current cache information for this font      */
    /******************************************************************/
    if ( !pdc->DCICurTxtAts.cdef.defSet)
        pCacheInfo = DDT.FontList[DefaultFontListIndex].pCacheInfo;
    else
    {
        Font = (ULONG)pdc->DCICurTxtAts.cdef.defSet - FTB_LCID_BASE;
        pCacheInfo = DDT.FontList[pdc->DCIRealizedFonts
                                  [Font].EntryInFontMetrics].pCacheInfo;
    }

    /******************************************************************/
    /* See if we have already have an XLate table set up for this     */
    /* color combination.                                             */
    /******************************************************************/
    XLateFound = FALSE;
    for (i = 0; i < pCacheInfo->XLateCount; i++)
    {
        if ((pCacheInfo->XLateTables[i][0] == (byte)AIxfer.BColor) &&
            (pCacheInfo->XLateTables[i][7] == (byte)AIxfer.FColor) )
        {
            XLateFound = TRUE;
            XLateToUse = (BYTE)i;
            break;
        }
    }

    /******************************************************************/
    /* Take action if the combination has not been used before        */
    /* color combination.                                             */
    /******************************************************************/
    if (XLateFound == FALSE)
    {
        /**************************************************************/
        /* There is room for upto eight XLate tables in the cache data*/
        /* structures. See if any of them are free.                   */
        /**************************************************************/
        if (pCacheInfo->XLateCount < 8)
        {
            XLateToUse = pCacheInfo->XLateCount++;
        }
        else
        {
            /**********************************************************/
            /* All the Xlate entries are being used. Once all the     */
            /* tables have been used once we then cycle round the     */
            /* entries. Decide which XLate to free and what the       */
            /* corresponding flag is                                  */
            /**********************************************************/
            DebugOutput("> 8 Colours. Remove XLATE entry\n\r");
            XLateToFree = pCacheInfo->CurrentXLate;
            FlagToFree  = (BYTE)(0x80 >> XLateToFree);

            /**********************************************************/
            /* Search through all the characters. If it is cached for */
            /* this combination, mark it as free                      */
            /**********************************************************/
            for (i = 0; i < NUM_AA_GLYPHS; i++)
            {
                if (pCacheInfo->CacheFlag[i] & FlagToFree)
                    pCacheInfo->CacheFlag[i] = 0;
            }
            XLateToUse = pCacheInfo->CurrentXLate;

            /**********************************************************/
            /* Update the counter so that we cycle through the entries*/
            /**********************************************************/
            pCacheInfo->CurrentXLate = (pCacheInfo->CurrentXLate + 1)
                                                                   % 8;
        }

        /**************************************************************/
        /* We now have an XLate entry to use, set up the table        */
        /**************************************************************/
        eddt_Interpolate( pCacheInfo->XLateTables[XLateToUse]);

    }

    /******************************************************************/
    /* Make a local copy of the XLate table. It is more efficient to  */
    /* access and is  available if we flush the cache                 */
    /******************************************************************/
    for (i = 0; i < numberoflevels; i++)
        XLate[i] = pCacheInfo->XLateTables[XLateToUse][i];
    FlagToUse  = (BYTE)(0x80 >> XLateToUse);
    AIxfer.CharHeight = AIxfer.pAIFont->cellheight;
    pCharDefSeg = FNULL;

    /******************************************************************/
    /* Lets go ahead and draw the characters. There are three         */
    /* different scenarios that can happen for each character         */
    /* 1) It is cached for our colors. Use the cached representation. */
    /* 2) It is cached with different colors. Reconvert the cached    */
    /*    representation.                                             */
    /* 3) It is not cached. Create a cached reprenstation for our     */
    /*    color combination.                                          */
    /*The final output is always from a cached peresentation          */
    /******************************************************************/
    for (CharCount = 0; CharCount < AIxfer.NumberOfCharacters;
                                                            CharCount++)
    {
        /**************************************************************/
        /* Get the next codepoint                                     */
        /**************************************************************/
        CodePoint = AIxfer.CodePoints[0];
        GlyphIndex = pdc->AACPVector[CodePoint];

        if (pCacheInfo->CacheFlag[GlyphIndex] & FlagToUse)
        {
            /**********************************************************/
            /* Character is already cached for this color combination */
            /* Set up variables to call hardware interface            */
            /**********************************************************/
            AIxfer.CharWidth     =pCacheInfo->CharacterWidth[GlyphIndex];
#ifdef CC20
            AIxfer.CharCacheAddr =pCacheInfo->ImagPosInCache[GlyphIndex] +
                                  pCurCacheBasePhy;
            AIxfer.CharMaskAddr = pCacheInfo->MaskPosInCache[GlyphIndex] +
                                  pCurCacheBasePhy;
#else
            AIxfer.CharCacheAddr =pCacheInfo->CharPosInCache[GlyphIndex];
            AIxfer.CharMaskAddr = AIxfer.CharCacheAddr +
                   ((ULONG)AIxfer.CharWidth * (ULONG)AIxfer.CharHeight);
#endif
        }
        else
        {
            /**********************************************************/
            /* Character is either cached for a different colour      */
            /* combination or not cached at all.                      */
            /* For characters cached for different colours we could   */
            /* simply convert the old XLATE values to corresponding   */
            /* values in the new table. However, in some cases two    */
            /* or more indices in the old XLATE table may be          */
            /* repeated and so we would not know which new index to   */
            /* map to. We therefore re-convert the character.         */
            /* Only difference between this  and converting for first */
            /* time is whether we reuse VARM or get a new bit.        */
            /**********************************************************/
            CharOffset = AIxfer.pAIFont->indextbl[CodePoint];
            pCharDef1 =  AIxfer.pAIFont->chardef1 + CharOffset;
            pCharDef2 =  AIxfer.pAIFont->chardef2 + CharOffset;
            pCharDef3 =  AIxfer.pAIFont->chardef3 + CharOffset;
            LeftEnvelope = AIxfer.pAIFont->enveltbl[2*CodePoint];
            RightEnvelope = AIxfer.pAIFont->enveltbl[2*CodePoint+1];
            AIxfer.CharWidth = AIxfer.pAIFont->cellwidth -
                                       LeftEnvelope - RightEnvelope;

            /**********************************************************/
            /* A cached character consists of the character pixel     */
            /* representation together with a (1,1) mask used to      */
            /* control the mixes. A 1 in the mask indicates that the  */
            /* foreground mix is to be used, otherwise background mix.*/
            /* Caclulate how much space is required.                  */
            /* Note that anti-aliased text is not supported for 4 bit */
            /* per pel configuration.                                 */
            /**********************************************************/
            MaskSize = (((((USHORT)AIxfer.CharWidth+7)/8) *
                                      (USHORT)AIxfer.CharHeight));
            PixDefSize = (USHORT)AIxfer.CharWidth *
                                                (USHORT)AIxfer.CharHeight;
#ifndef CC20
            CacheCharSize = PixDefSize + MaskSize;
#endif

            /**********************************************************/
            /* Decide where in VRAM the cached definition will reside */
            /**********************************************************/
            if (pCacheInfo->CacheFlag[GlyphIndex] == 0)
            {
                /******************************************************/
                /* See if there is room for the character in the cache*/
                /******************************************************/
#ifdef CC20
                if ((offLastFree81Pos - offNextFree11Pos) <
                                         (MaskSize + PixDefSize))
#else
                if ((pCacheNextFreePos + (ULONG)CacheCharSize) >
                                                              pCacheEnd)
#endif
                {
                    /**************************************************/
                    /* No room in cache and so flush it. Clear all the*/
                    /* the cache flags and reset the VRAM pointers    */
                    /**************************************************/
                    eddt_InvalidateCache();
                }

#ifdef CC20
                offLastFree81Pos -= PixDefSize ;
                offCharImage = offLastFree81Pos ;

                offCharMask = offNextFree11Pos ;
                offNextFree11Pos += MaskSize ;
#else
                pCharVRAM = pCacheNextFreePos;
                pCacheNextFreePos += CacheCharSize;
#endif
            }
            else
            {
                /******************************************************/
                /* Use VRAM for other colour combination              */
                /******************************************************/
#ifdef CC20
                offCharImage = pCacheInfo->ImagPosInCache[GlyphIndex];
                offCharMask = pCacheInfo->MaskPosInCache[GlyphIndex];
#else
                pCharVRAM = pCacheInfo->CharPosInCache[GlyphIndex];
#endif
            }

#ifndef CC20
            /**********************************************************/
            /* See if the character will fit into the work area       */
            /**********************************************************/
            if (CacheCharSize <= SPAD_SIZE_IN_BYTES && !pCharDefSeg)
            {
                /******************************************************/
                /* Since the work area is in the data segment it will */
                /* be already locked                                  */
                /******************************************************/
                pPixelDef = SPad;
                DAATLockInfo.BMPhys = data_seg_physical_base +
                                                    OFFSETOF(pPixelDef);
                pMaskDef  = SPad + (ULONG)PixDefSize;
            }
            else
            {
                /******************************************************/
                /* See if we have already allocated a segment to act  */
                /* as the work area                                   */
                /******************************************************/
                if (!pCharDefSeg)
                {
                    /**************************************************/
                    /* Allocate a work area which can accomodate the  */
                    /* largest character. We can then be certain that */
                    /* we can use this work area for all subsequent   */
                    /* characters to be output in this string         */
                    /**************************************************/
                    DAATLockInfo.BMSize = ((USHORT)AIxfer.pAIFont->cellwidth *
                    (USHORT)AIxfer.pAIFont->cellheight) +
                                             AIxfer.pAIFont->cellnbytes;
                    if ( SSAllocSeg((USHORT)DAATLockInfo.BMSize,
                                  &SELECTOROF(pCharDefSeg),
                                  0) != DOS_OK)
                    {
                        LOGDOSERR(TFUNC, "Error in DosAllocSeg", FNULL,
                                                                  0, 0);
                        return(ERROR_ZERO);
                    }
                    OFFSETOF(pCharDefSeg) = 0;

                    /**************************************************/
                    /* Lock the work area                             */
                    /**************************************************/
                    DAATLockData.Count = 1;
                    DAATLockData.Address[0] = (ULONG)&DAATLockInfo;
                    DAATLockInfo.BMPhys   = FNULL;
                    DAATLockInfo.Bitmap   = (lpBitmap)pCharDefSeg;
                    PMLOCK(&DAATLockData);
                }
                /******************************************************/
                /* Set up pointers for the charcter definition        */
                /******************************************************/
                pPixelDef = pCharDefSeg;
                pMaskDef  = pCharDefSeg + (ULONG)PixDefSize;
            }

            /**********************************************************/
            /* Save the logical address of the character for software */
            /* drawing                                                */
            /**********************************************************/
            pCharLog = (ULONG)pPixelDef ;
#endif /* ndef CC20 */

#ifdef CC20
            pPixelDef = pSysCacheStart + offCharImage ;
            pMaskDef = pSysCacheStart + offCharMask ;
#endif /* CC20 */

            /**********************************************************/
            /* Clear the mask and set the mask bit                    */
            /**********************************************************/
            memset((PVOID)pMaskDef, 0, MaskSize);
            MaskBit = 0x80;

            /**********************************************************/
            /* Let's get converting                                   */
            /**********************************************************/
            CurrBitPos = 0;
            for (i = 0; i < (int)AIxfer.CharHeight; i++)
            {
                /******************************************************/
                /* Deal with leading bits not required                */
                /******************************************************/
                CurrBitPos += LeftEnvelope;
                if (CurrBitPos > 7)
                {
                    pCharDef1 += (CurrBitPos / 8);
                    pCharDef2 += (CurrBitPos / 8);
                    pCharDef3 += (CurrBitPos / 8);
                    CurrBitPos = CurrBitPos % 8;
                }

                BitsToProcess = AIxfer.CharWidth;
                do
                {
                    /**************************************************/
                    /* Calculate number of bits to process from the   */
                    /* current source bytes                           */
                    /**************************************************/
                    if ((8 - CurrBitPos) <= BitsToProcess)
                    {
                        BitsFromByte = (BYTE)(8 - CurrBitPos);
                        SrcByte1 = *pCharDef1++ << CurrBitPos;
                        SrcByte2 = *pCharDef2++ << CurrBitPos;
                        SrcByte3 = *pCharDef3++ << CurrBitPos;
                        CurrBitPos = 0;
                    }
                    else
                    {
                        BitsFromByte = BitsToProcess;
                        SrcByte1 = *pCharDef1 << CurrBitPos;
                        SrcByte2 = *pCharDef2 << CurrBitPos;
                        SrcByte3 = *pCharDef3 << CurrBitPos;
                        CurrBitPos += BitsToProcess;
                    }

                    BitsToProcess -= BitsFromByte;
                    for (; BitsFromByte--; )
                    {
                        /**********************************************/
                        /* The bits under scrutiny are always in the  */
                        /* msb. Combine them to form an XLATE index   */
                        /**********************************************/
                        TrgIndex = ((SrcByte1 & 0x80) >> 7) |
                                   ((SrcByte2 & 0x80) >> 6) |
                                   ((SrcByte3 & 0x80) >> 5);
                        *pPixelDef++ = XLate[TrgIndex];

                        SrcByte1 = SrcByte1 << 1;
                        SrcByte2 = SrcByte2 << 1;
                        SrcByte3 = SrcByte3 << 1;

                        /**********************************************/
                        /* If index is not the background set the bit */
                        /* in the character mask. Then adjust mask bit*/
                        /**********************************************/
                        if (TrgIndex)
                            *pMaskDef |= MaskBit;
                        MaskBit = MaskBit >> 1;
                        if (!MaskBit)
                        {
                            MaskBit = 0x80;
                            pMaskDef++;
                        }
                    }
                }
                while (BitsToProcess);

                /******************************************************/
                /* Deal with trailing bits not required               */
                /******************************************************/
                CurrBitPos += RightEnvelope;
                if (CurrBitPos > 7)
                {
                    pCharDef1 += (CurrBitPos / 8);
                    pCharDef2 += (CurrBitPos / 8);
                    pCharDef3 += (CurrBitPos / 8);
                    CurrBitPos = CurrBitPos % 8;
                }

                /******************************************************/
                /* Make the mask byte padded                          */
                /******************************************************/
                if (MaskBit != 0x80)
                {
                    MaskBit = 0x80;
                    pMaskDef++;
                }

            } /*.....................i < CharHeight...................*/

#ifdef CC20
            /**********************************************************/
            /* Now we have the image and mask cached in the system    */
            /* memory cache.                                          */
            /* For non SEAMLESS version of driver we need to transfer */
            /* the image and mask from the system memory cache to the */
            /* VRAM cache.                                            */
            /**********************************************************/
#ifndef SEAMLESS

#ifdef SDBM20
            if (foregroundSession)
#else /* SDBM20 */
            if (!softDrawInUse)
#endif /* SDBM20 */
            {
                /**********************************************************/
                /* Perform the copy for the image definition first        */
                /**********************************************************/
                WaitForHW ;

                /**********************************************************/
                /* Set the mixes                                          */
                /**********************************************************/
                AIBase->FgMix = HWMIX_SOURCE ;
                AIBase->BgMix = HWMIX_SOURCE ;

                /**********************************************************/
                /* Assign PixDefSize    to a seperate variable. This is   */
                /* because if we try to assign the expression             */
                /* PixDefSize    - 1 to AIBaseA->PixMapWidth and then     */
                /* AIBaseB->PixMapWidth it will try and read back the     */
                /* value from AIBaseA->PixMapWidth for the second         */
                /* assignment. But the register is read only.......       */
                /**********************************************************/
                BltWidth = PixDefSize - 1;

                /**********************************************************/
                /* First set up the destination                           */
                /**********************************************************/
                AIBaseA->PixMapIndex = SEL_PIX_MAP_A ;
                AIBaseA->PixMapBase = pVRAMCacheStart+offCharImage;
                AIBaseA->PixMapWidth = BltWidth;
                AIBaseA->PixMapHeight = 0 ;
                AIBaseA->PixMapFormat = EIGHT_BPP;

                /**********************************************************/
                /* Now set up the source..                                */
                /**********************************************************/
                AIBaseB->PixMapIndex = SEL_PIX_MAP_B;
                AIBaseB->PixMapBase = pSysCacheStartPhy+offCharImage;
                AIBaseB->PixMapWidth = BltWidth;
                AIBaseB->PixMapHeight = 0 ;
                AIBaseB->PixMapFormat = EIGHT_BPP | MOTOROLA;

                /**********************************************************/
                /* Now set up the blt                                     */
                /**********************************************************/
                AIBase->SrcXAddr = 0 ;
                AIBase->SrcYAddr = 0 ;
                AIBase->DstXAddr = 0 ;
                AIBase->DstYAddr = 0 ;

                AIBase->OpDim1 = BltWidth;
                AIBase->OpDim2 = 0 ;

                /**********************************************************/
                /* Do the blt                                             */
                /**********************************************************/
                AIBase->PixOp = BACK_SRC_SRC_PIX_MAP |
                                FORE_SRC_SRC_PIX_MAP |
                                STEP_PXBLT |
                                SRC_PIX_MAP_B |
                                DST_PIX_MAP_A |
                                PAT_PIX_MAP_FORE |
                                MASK_PIX_MAP_OFF |
                                DRAW_MODE_DONTCARE |
                                DIR_OCTANT_LRTB ;

                /**********************************************************/
                /* Now do the copy for the mask defineition               */
                /**********************************************************/
                WaitForHW ;

                /**********************************************************/
                /* Assign MaskSize      to a seperate variable. This is   */
                /* because if we try to assign the expression             */
                /* MaskSize      - 1 to AIBaseA->PixMapWidth and then     */
                /* AIBaseB->PixMapWidth it will try and read back the     */
                /* value from AIBaseA->PixMapWidth for the second         */
                /* assignment. But the register is read only.......       */
                /**********************************************************/
                BltHeight = MaskSize - 1;

                /**********************************************************/
                /* First set up the destination                           */
                /**********************************************************/
                AIBaseA->PixMapIndex = SEL_PIX_MAP_A ;
                AIBaseA->PixMapBase = pVRAMCacheStart+offCharMask;
                AIBaseA->PixMapWidth = 7 ;
                AIBaseA->PixMapHeight = BltHeight ;
                AIBaseA->PixMapFormat = ONE_BPP;

                /**********************************************************/
                /* Now set up the source..                                */
                /**********************************************************/
                AIBaseB->PixMapIndex = SEL_PIX_MAP_B;
                AIBaseB->PixMapBase = pSysCacheStartPhy+offCharMask;
                AIBaseB->PixMapWidth = 7 ;
                AIBaseB->PixMapHeight = BltHeight ;
                AIBaseB->PixMapFormat = ONE_BPP | MOTOROLA;

                /**********************************************************/
                /* Now set up the blt                                     */
                /**********************************************************/
                AIBase->SrcXAddr = 0 ;
                AIBase->SrcYAddr = 0 ;
                AIBase->DstXAddr = 0 ;
                AIBase->DstYAddr = 0 ;

                AIBase->OpDim1 = 7 ;
                AIBase->OpDim2 = BltHeight ;

                /**********************************************************/
                /* Do the blt                                             */
                /**********************************************************/
                AIBase->PixOp = BACK_SRC_SRC_PIX_MAP |
                                FORE_SRC_SRC_PIX_MAP |
                                STEP_PXBLT |
                                SRC_PIX_MAP_B |
                                DST_PIX_MAP_A |
                                PAT_PIX_MAP_FORE |
                                MASK_PIX_MAP_OFF |
                                DRAW_MODE_DONTCARE |
                                DIR_OCTANT_LRTB ;

            }

#endif /* ifndef SEAMLESS */

#else /* CC20 */

            /**********************************************************/
            /* Perform the copy                                       */
            /**********************************************************/
            WaitForHW ;

            /**********************************************************/
            /* Set the mixes                                          */
            /**********************************************************/
            AIBase->FgMix = HWMIX_SOURCE ;
            AIBase->BgMix = HWMIX_SOURCE ;

            /**********************************************************/
            /* Assign CacheCharSize to a seperate variable. This is   */
            /* because if we try to assign the expression             */
            /* CacheCharSize - 1 to AIBaseA->PixMapWidth and then     */
            /* AIBaseB->PixMapWidth it will try and read back the     */
            /* value from AIBaseA->PixMapWidth for the second         */
            /* assignment. But the register is read only.......       */
            /**********************************************************/
            if (softDrawInUse)
            {
                BltWidth = CacheCharSize - 1;
            }
            else
            {
                BltWidth = PixDefSize - 1;
            }

            /**********************************************************/
            /* First set up the destination                           */
            /**********************************************************/
            AIBaseA->PixMapIndex = SEL_PIX_MAP_A ;
            AIBaseA->PixMapBase = pCharVRAM;
            AIBaseA->PixMapWidth = BltWidth;
            AIBaseA->PixMapHeight = 0 ;

            /**********************************************************/
            /* Set up the format for the desination                   */
            /**********************************************************/
            AIBaseA->PixMapFormat = EIGHT_BPP;

            /**********************************************************/
            /* Now set up the source..                                */
            /**********************************************************/
            AIBaseB->PixMapIndex = SEL_PIX_MAP_B;
            if (softDrawInUse)
            {
                AIBaseB->PixMapBase = pCharLog ;
            }
            else
            {
                AIBaseB->PixMapBase = DAATLockInfo.BMPhys;
            }
            AIBaseB->PixMapWidth = BltWidth;
            AIBaseB->PixMapHeight = 0 ;
            AIBaseB->PixMapFormat = EIGHT_BPP | MOTOROLA;

            /**********************************************************/
            /* Now set up the blt                                     */
            /**********************************************************/
            AIBase->SrcXAddr = 0 ;
            AIBase->SrcYAddr = 0 ;
            AIBase->DstXAddr = 0 ;
            AIBase->DstYAddr = 0 ;

            AIBase->OpDim1 = BltWidth;
            AIBase->OpDim2 = 0 ;

            /**********************************************************/
            /* Do the blt                                             */
            /**********************************************************/
            AIBase->PixOp = BACK_SRC_SRC_PIX_MAP |
                            FORE_SRC_SRC_PIX_MAP |
                            STEP_PXBLT |
                            SRC_PIX_MAP_B |
                            DST_PIX_MAP_A |
                            PAT_PIX_MAP_FORE |
                            MASK_PIX_MAP_OFF |
                            DRAW_MODE_DONTCARE |
                            DIR_OCTANT_LRTB ;

            if (softDrawInUse)
            {
                eddf_MESS();
            }

            if (!softDrawInUse)
            {
                WaitForHW;

                /**********************************************************/
                /* That transferred the colour information - now transfer */
                /* the mask information using 1BPP and flipping from      */
                /* motorola to intel format (only if h/w draw in use)     */
                /**********************************************************/
                BltWidth = MaskSize*8 -1;

                /**********************************************************/
                /* First set up the destination                           */
                /**********************************************************/
                AIBaseA->PixMapIndex = SEL_PIX_MAP_A ;
                AIBaseA->PixMapBase = pCharVRAM+PixDefSize;
                AIBaseA->PixMapWidth = BltWidth;
                AIBaseA->PixMapHeight = 0 ;

                /**********************************************************/
                /* Set up the format for the desination                   */
                /**********************************************************/
                AIBaseA->PixMapFormat = ONE_BPP | INTEL;

                /**********************************************************/
                /* Now set up the source..                                */
                /**********************************************************/
                AIBaseB->PixMapIndex = SEL_PIX_MAP_B;
                AIBaseB->PixMapBase = DAATLockInfo.BMPhys+PixDefSize;
                AIBaseB->PixMapWidth = BltWidth;
                AIBaseB->PixMapHeight = 0 ;
                AIBaseB->PixMapFormat = ONE_BPP | MOTOROLA;

                /**********************************************************/
                /* Now set up the blt                                     */
                /**********************************************************/
                AIBase->SrcXAddr = 0 ;
                AIBase->SrcYAddr = 0 ;
                AIBase->DstXAddr = 0 ;
                AIBase->DstYAddr = 0 ;

                AIBase->OpDim1 = BltWidth;
                AIBase->OpDim2 = 0 ;

                /**********************************************************/
                /* Do the blt                                             */
                /**********************************************************/
                AIBase->PixOp = BACK_SRC_SRC_PIX_MAP |
                                FORE_SRC_SRC_PIX_MAP |
                                STEP_PXBLT |
                                SRC_PIX_MAP_B |
                                DST_PIX_MAP_A |
                                PAT_PIX_MAP_FORE |
                                MASK_PIX_MAP_OFF |
                                DRAW_MODE_DONTCARE |
                                DIR_OCTANT_LRTB ;
            }
#endif /* CC20 */

            /**********************************************************/
            /* Update our cache information                           */
            /**********************************************************/
#ifdef CC20
            pCacheInfo->ImagPosInCache[GlyphIndex] = offCharImage ;
            pCacheInfo->MaskPosInCache[GlyphIndex] = offCharMask ;
            AIxfer.CharCacheAddr = pCurCacheBasePhy + offCharImage;
            AIxfer.CharMaskAddr = pCurCacheBasePhy + offCharMask;
#else /* CC20 */
            pCacheInfo->CharPosInCache[GlyphIndex] = pCharVRAM;
            AIxfer.CharCacheAddr = pCharVRAM;
            AIxfer.CharMaskAddr = pCharVRAM + (ULONG)PixDefSize;
#endif /* CC20 */
            pCacheInfo->CacheFlag[GlyphIndex] = FlagToUse;
            pCacheInfo->CharacterWidth[GlyphIndex] = AIxfer.CharWidth;
        }

        /**************************************************************/
        /* set up the mixes from the current text attribute bundle    */
        /* and the colors (only relevant if going to a 1:1 bitmap)   */
        /**************************************************************/
        WaitForHW;
        AIBase->FgMix = WinToXWay[pdc->DCICurTxtAts.cbnd.usMixMode];
        AIBase->BgMix = WinToXWay[pdc->DCICurTxtAts.cbnd.usBackMixMode];
        AIBase->FgCol = (*(pTextPB)&AIxfer).FColor;
        AIBase->BgCol = (*(pTextPB)&AIxfer).BColor;

        /**************************************************************/
        /* see if we have been asked to output some markers           */
        /**************************************************************/
        if ( DrawMarkers)
        {
            /**********************************************************/
            /* We are outputting markers and so repeatedly drawing    */
            /* the same character which will be cached. We can simply */
            /* loop here to draw all the markers and then exit        */
            /**********************************************************/
            for (i = 0; i < AIxfer.NumberOfCharacters; i++)
            {
                AIxfer.FirstCharacterPosition.X =
                                               (SHORT)MarkerCoords[i].x;
                AIxfer.FirstCharacterPosition.Y =
                                               (SHORT)MarkerCoords[i].y;

                eddb_DrawThroughClips((*pDrawFunctions)[index_drawaachar],
                                   (USHORT *)&AIxfer.NumDstClipRegions);
            }
            RetCode = OK;
            goto TIDY_UP_AND_EXIT;
        }
        else
        {
            eddb_DrawThroughClips((*pDrawFunctions)[index_drawaachar],
                                   (USHORT *)&AIxfer.NumDstClipRegions);

            /**********************************************************/
            /* An extra test which helps for when we are clipping to  */
            /* an opaque rect.  If there are less than four clips     */
            /* that intersect with the opaque rect than indicate that */
            /* the clips have not changed.  This prevents us calling  */
            /* the engine for more.  Once we have finished drawing    */
            /* the clip cache is invalidated                          */
            /**********************************************************/
/*          if (pdc->DCIEngineClips <= CACHED_CLIPS )
                pdc->ClipChanged = FALSE; */

            /**********************************************************/
            /* Adjust the starting position for the next character    */
            /* taking position vectors into account                   */
            /**********************************************************/
            if (pVector)
                AIxfer.FirstCharacterPosition.X += *pVector++;
            else
                AIxfer.FirstCharacterPosition.X +=
                    (int)AIxfer.CharWidth +
                    pdc->DCICurTxtAts.cdef.charSpacing ;

            AIxfer.CodePoints++;
        }
    } /* .............for each character to be output................*/

    /******************************************************************/
    /* Unlock any locked buffers and free memory                      */
    /******************************************************************/
    RetCode = OK;
TIDY_UP_AND_EXIT:
    if (pCharDefSeg)
    {
        /**************************************************************/
        /* wait fot the HW to finish before freeing                   */
        /**************************************************************/
        WaitForHW;
        DAATLockData.Address[0] = DAATLockInfo.LockHandle;
        PMUNLOCK(&DAATLockData);
        SSFreeSeg(SELECTOROF(pCharDefSeg));
    }

    return RetCode;
}
#undef TFUNC


/**********************************************************************/
/* Set up the HXLATE table for use with anti aliased text fonts       */
/* The values in the table are calculated by linear interpolation     */
/* between the currently set foreground and background colours        */
/**********************************************************************/

VOID PASCAL eddt_Interpolate(PBYTE      pXLateTable)

{
#define TFUNC "eddt_Interpolate"
    SHORT         i, j;              /* loop variables                */
    SHORT         x, x1, x2 ;        /* used in interpolating         */
    SHORT         levels;            /* number of XLATE table levels  */
    PBYTE         fg;                /* foreground palette entry      */
    PBYTE         bg;                /* background palette entry      */
    BYTE          color[4];          /* space for interpolated value  */
    USHORT        Index;
    ULONG         RGBColor;

    /******************************************************************/
    /* use the physical colour table to pick up RGB values            */
    /******************************************************************/
    fg = (PBYTE)(&PhysicalColorTable[AIxfer.FColor]);
    bg = (PBYTE)(&PhysicalColorTable[AIxfer.BColor]);

    /******************************************************************/
    /* check for the special precalculated XLATE tables               */
    /******************************************************************/
    if (fg[0] == 0xff &&
        fg[1] == 0xff &&
        fg[2] == 0xff &&
        bg[0] == 0x00 &&
        bg[1] == 0x00 &&
        bg[2] == 0x00 )
    {
        /**************************************************************/
        /* white on black                                             */
        /**************************************************************/
        for (i = numberoflevels; i--; )
        {
            pXLateTable[i] = WhiteOnBlackColorRamp[i];
        }
    }
    else if (fg[0] == 0x00 &&
             fg[1] == 0x00 &&
             fg[2] == 0x00 &&
             bg[0] == 0xff &&
             bg[1] == 0xff &&
             bg[2] == 0xff )
    {
        /**************************************************************/
        /* black on white                                             */
        /**************************************************************/
        for (i = numberoflevels; i--; )
        {
            pXLateTable[i] = BlackOnWhiteColorRamp[i];
        }
    }
    else
    {
        /**************************************************************/
        /* set the number of XLATE table levels                       */
        /**************************************************************/
        levels = numberoflevels-1;

        /**************************************************************/
        /* first HXLATE entry is background, last is foreground       */
        /**************************************************************/
        pXLateTable[0]  = (BYTE)AIxfer.BColor;
        pXLateTable[levels] = (BYTE)AIxfer.FColor;

        /**************************************************************/
        /* calculate the intermediate RGB values, and find closest    */
        /* available colour for entry in the HXLATE table             */
        /**************************************************************/
        for (i = 1; i < (numberoflevels-1); i++)
        {
            for (j = 0; j < 3; j++)
            {
                x1 = fg[j];
                x2 = bg[j];

                x = x2 + ((x1 - x2) * i) / (numberoflevels - 1);
                color[j] = (BYTE) x;
            }
            RGBColor = ((ULONG)color[2] << 16) |
                       ((ULONG)color[1] << 8 ) |
                       ((ULONG)color[0]);
            eddc_NearestPhysicalColor(RGBColor,(PUSHORT)&Index);
            pXLateTable[i] = (BYTE)Index;
        }
    }
}
#undef TFUNC

#endif /* ndef PALETTE_MGR */
