/*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          = EDDJCACH.C                                     */
/*                                                                    */
/*   Description     = PM Display Driver DBCS handling routine        */
/*                     Cache handling functions for DBCS              */
/*                     (Replaces some funcs in EDDNCACH.C)            */
/*                                                                    */
/*   Function        =                                                */
/*                                                                    */
/*                                                                    */
/**********************************************************************/


#define INCL_DDIMISC
#include <eddinclt.h>
#include <edddtypt.h>
#include <eddttypt.h>
#include <eddhcone.h>
#include <eddhtype.h>
#include <hwaccess.h>

#ifdef VRAMPTR
#include <eddncach.h>
#endif /* VRAMPTR */

#include <eddjdef.h>
#include <eddjsub.h>
#include <eddjfm.h>
#include <eddjcach.h>
#include <eddjfont.h>

#ifdef _8514
#include "8514.h"
extern ULONG Cache8514Char (ULONG,ULONG,ULONG,PVOID,PULONG);
#endif // _8514

#ifdef _8514
#include <cacheman.h>
extern PHWMAP           pHWMap;
extern PCACHEMAP        pCacheMap;
#endif

/**********************************************************************/
/* external functions                                                 */
/**********************************************************************/
extern LONG eddt_CacheCharacter (USHORT       usArgCodePoint,
                                 PFONTDETAILS pFontDetails);
extern VOID eddt_LocateCachedFont (PFONTDETAILS pFontDetails);

extern VOID eddt_InvalidateCache (VOID);

/**********************************************************************/
/* external variables                                                 */
/**********************************************************************/
extern TEXTPB              AIxfer;
extern DDTType             DDT;

extern PFONTCACHEINFO      pFontCacheInfo;

extern PBYTE   pSysCacheStart;
extern ULONG   offNextFree11Pos;


/**********************************************************************/
/* types                                                              */
/**********************************************************************/
typedef union
{
    ABC_CHAR_DEFN *pabcDefn;           /* these structs are defined   */
    NON_ABC_CHAR_DEFN *pnonabcDefn;    /*   in EDDTTYPT.H             */
} PFONT_CHAR_DEFN;

#define CACHE_RESERVED          0xFFFFFFFF



/**********************************************************************/
/*      eddj_PutStringInCache                                         */
/*                                                                    */
/* Make sure that all characters in given string are contained in     */
/* cache.  Expects SBCS or U-DBCS string according to NLSCA_UNIFIED_  */
/* DBCS bit.  Also NLSCA_CALL_DBCSFM bit is considered.               */
/*                                                                    */
/* Entry      :                                                       */
/*            - ptr to string                                         */
/*            - number of characters (not bytes)                      */
/*            - ptr to current font's FONTCACHEINFO                   */
/*            - ptr to current font's FONTDETAILS                     */
/*            - ptr to variable where total width of given string     */
/*                      is returned (may be NULL)                     */
/*                                                                    */
/* Returns    :                                                       */
/*            - Returns TRUE if completes                             */
/*            - Total of all put characters' width is returned to     */
/*              the buffer if supplied                                */
/*            - On return, array of cache index is created in global  */
/*              buffer, asCIndex[], and can be used for performance.  */
/*                                                                    */
/* Error Returns :      None                                          */
/*                                                                    */
/* Note       :                                                       */
/*            - If cache overflows, flush-and-retry is done in this   */
/*              routine, so that caller need not care.                */
/*            - Can accept all combination of NLSCA_UNIFIED_DBCS and  */
/*              NLSCA_CALL_DBCSFM.                                    */
/*            - This function does not care of charSpacing when       */
/*                      calculating width                             */
/*            - Caller should guarantee that passed string does not   */
/*                      exceed limit when NLSCA_MUST_CHOP is ON.      */
/*                                                                    */
/* Calls      :                                                       */
/*                                                                    */
/**********************************************************************/
ULONG eddj_PutStringInCache (PCHAR          pCodePoints,
                             ULONG          ulCharNum,
                             PFONTCACHEINFO pFCInfo,
                             PFONTDETAILS   pFontDetails,
                             PUSHORT        pStringWidth)
{
    ULONG ulIndex;
    ULONG ulStart, ulEnd;
    ULONG ulNotInCache;                 // # of chars not in cache
    LONG lCacheIndex;                   // index to cache entry
    USHORT usCodepoint;
    USHORT usWidth = 0;                 // string width accumulator
    USHORT usCellHeight, usCellWidth;   // size of character cell
    PFCCHARDEF pCharDefn;
    PFONT_CHAR_DEFN pDefnStart, pDefnCurrent;
    PBYTE pbImage;                      // ptr to char image
    ULONG ulCacheOffset;
    ULONG ulStartGlyph;                 // 1st glyph # in font

    const PFOCAFONT pFocaFont = pFontDetails->pFocaFont;

    const BOOL fABCFont =               // flag if it is ABC-space font
        (pFocaFont->fdDefinitions.fsChardef == FONTDEFCHAR3);
#ifdef _8514
    ULONG CharOffset;
#endif // _8514
    ULONG   retry_counter = ulCharNum + 1;

    // first check if each char is already in cache.
    // if cache is flushed, jump back to here for retry
  FLUSH_RETRY:
    if (!retry_counter--)
        return FALSE;

    ulNotInCache = 0;
    for (ulIndex = 0; ulIndex < ulCharNum; ulIndex++)
    {
        if (pFontDetails->NLSParseFlag & NLSCA_UNIFIED_DBCS)
        {
            usCodepoint = ((PUSHORT)pCodePoints)[ulIndex];
        }
        else
        {
            usCodepoint = pCodePoints[ulIndex];
        }

        lCacheIndex = eddj_LocateInCache (pFCInfo, usCodepoint);

        // remember cache index
        // Note: FLAG_NOT_IN_CACHE is kept after converted to SHORT.
        asCIndex[ulIndex] = (SHORT)lCacheIndex;

        if (lCacheIndex == ERROR_CACHE_FULL)
        {
            // if cache is full, then flush cache contents.
            eddt_InvalidateCache();
            eddt_LocateCachedFont( pFontDetails );
            // put the font info again
            pFCInfo = pFontCacheInfo +
                      pFontDetails->usCachedFontIndex;

            goto FLUSH_RETRY;
        }

        if (lCacheIndex & FLAG_NOT_IN_CACHE)
        {
            if (ulNotInCache == 0)
            {
              ulStart = ulIndex;
            }

            ulEnd = ulIndex;
            ulNotInCache ++;
        }
    }

    // if all char are in cache
    if (ulNotInCache == 0)
        goto CALC_WIDTH;

    // query the font manager
    //
    // first, convert to glyph indx
    StringToGlyph (pFontDetails, pCodePoints, ausGlyph, ulCharNum);

    // if need to call DBCS FM...
    if (pFontDetails->NLSParseFlag & NLSCA_CALL_DBCSFM)
    {
        // this call should not fail!
        eddj_ValidateFontSeg (ulEnd - ulStart + 1,
                              pFontDetails->pFocaFont,
                              ausGlyph + ulStart);
    }


    // process chars retrieved from font manager

    // maybe we should check size field of each struct???
    pDefnStart.pabcDefn = (ABC_CHAR_DEFN *)(pFocaFont + 1);

    // height is always common
    usCellHeight = pFocaFont->fdDefinitions.yCellHeight;

    ulStartGlyph = (ULONG)pFocaFont->fmMetrics.usFirstChar;

    for (ulIndex = ulStart; ulIndex <= ulEnd; ulIndex ++)
    {
        lCacheIndex = (LONG)asCIndex[ulIndex];
        if (!(lCacheIndex & FLAG_NOT_IN_CACHE))
        {
            // was already in cache, so we can skip this char
            continue;
        }

        // put actual cache index valueas caller may use it
        lCacheIndex &= ~FLAG_NOT_IN_CACHE;
        asCIndex[ulIndex] = (SHORT)lCacheIndex;

        // get char-specific parameters
        if (fABCFont)
        {
            pDefnCurrent.pabcDefn =
              pDefnStart.pabcDefn + ausGlyph[ulIndex] - ulStartGlyph;

            usCellWidth = pDefnCurrent.pabcDefn->usBSpace;
            pbImage = (PBYTE)pFocaFont +
              pDefnCurrent.pabcDefn->ulImageOffset;
        }
        else
        {
            pDefnCurrent.pnonabcDefn =
              pDefnStart.pnonabcDefn + ausGlyph[ulIndex] - ulStartGlyph;

            usCellWidth = pDefnCurrent.pnonabcDefn->usCharWidth;
            pbImage = (PBYTE)pFocaFont +
              pDefnCurrent.pnonabcDefn->ulImageOffset;
        }

        // put char in cache
#ifndef _8514
        ulCacheOffset =
          eddj_PutImageInCache (pbImage, usCellWidth, usCellHeight);
#else // _8514

        CharOffset = (ULONG)(pSysCacheStart + offNextFree11Pos);

        ulCacheOffset =
          eddj_PutImageInCache (pbImage, usCellWidth, usCellHeight,
                                pFontDetails->usCachedFontIndex);
#endif // _8514

        // if cache overflows
        if (ulCacheOffset == ERROR_ZERO)
        {
            // flush cache contents
            eddt_InvalidateCache();
            // put the font info again
            eddt_LocateCachedFont (pFontDetails);
            pFCInfo = pFontCacheInfo +
                      pFontDetails->usCachedFontIndex;

            // may change!
            goto FLUSH_RETRY;
        }

        // put actual offset to a reserved entry           */
        pFCInfo->aulCachedCharOffset[lCacheIndex] = ulCacheOffset;

#ifdef _8514

#ifdef BPP24                                                
#ifdef FULL_ADDRESS
//      pFCInfo->apCharDef[lCacheIndex] = pbImage;
        pFCInfo->apCharDef[lCacheIndex] = fABCFont ? pDefnCurrent.pabcDefn
                                                   : pDefnCurrent.pnonabcDefn;
#else /* ndef FULL_ADDRESS */
        pFCInfo->apCharDef[lCacheIndex] =
//                        (USHORT)((PBYTE)pbImage - (PBYTE)pFocaFont);
                          (USHORT)((PBYTE) (fABCFont ? pDefnCurrent.pabcDefn
                                                     : pDefnCurrent.pnonabcDefn)
                          - (PBYTE)pFocaFont);
#endif /* ndef FULL_ADDRESS */
#endif 

        /******************************************************************/
        /* Defect 75206. Update the font plane offset for this character  */
        /* and our global for the font.                                   */
        /******************************************************************/
        pFCInfo->ausPlaneOffset[lCacheIndex] =
             aulFontPlaneOffset[pFontDetails->usCachedFontIndex];

        pFCInfo->aCharOffset[lCacheIndex] = CharOffset;

#endif // _8514

        if (!fABCFont)
        {
            pFCInfo->aCharDef[lCacheIndex].nonABC.usWidth =
                  pDefnCurrent.pnonabcDefn->usCharWidth;
        }
        else
        {
            pFCInfo->aCharDef[lCacheIndex].ABC.usAspace =
                  pDefnCurrent.pabcDefn->usASpace;
            pFCInfo->aCharDef[lCacheIndex].ABC.usBspace =
                  pDefnCurrent.pabcDefn->usBSpace;
            pFCInfo->aCharDef[lCacheIndex].ABC.usCspace =
                  pDefnCurrent.pabcDefn->usCSpace;
        }
    }

  CALC_WIDTH:
    if (pStringWidth)
    {
        for (ulIndex = 0; ulIndex < ulCharNum; ulIndex++)
        {
            pCharDefn = pFCInfo->aCharDef + asCIndex[ulIndex];
            usWidth += fABCFont ?
                       pCharDefn->ABC.usAspace +
                       pCharDefn->ABC.usBspace +
                       pCharDefn->ABC.usCspace :
                       pCharDefn->nonABC.usWidth;
        }
        *pStringWidth = usWidth;
    }

    return TRUE;
}

/**********************************************************************/
/*      eddj_PutImageInCache                                          */
/*                                                                    */
/* Put given image of a character into font cache                     */
/*                                                                    */
/* Entry      :                                                       */
/*            - Ptr to the character's image                          */
/*            - Width of the character (in pels)                      */
/*            - Height of the character (in pels)                     */
/*                                                                    */
/* Returns    :                                                       */
/*            - Returns offset in the cache where the image has been  */
/*              stored                                                */
/*                                                                    */
/* Error Returns :                                                    */
/*            - Returns ERROR_ZERO (==0) if cache is full             */
/*                                                                    */
/* Note       :                                                       */
/*            - This function is extracted from eddt_CacheCharacter   */
/*              for DBCS performance reason.                          */
/*                                                                    */
/* Calls      :                                                       */
/*                                                                    */
/**********************************************************************/
extern SHORT            foregroundSession;
#ifndef   _8514
extern MMReg            ShadowXGARegs;
#else
extern MM8514Reg        Shadow8514Regs;
#endif

extern SHORT            softDrawInUse;
extern VOID             eddf_MESS(VOID);

#ifndef   _8514
extern FLATLOCKDATA     flatlockdata;
extern HFILE            ring0_handle;
#endif

#ifdef SEAMLESS
extern ULONG            fSeamlessActive;
extern ULONG            fSeamlessCCConflict;
#endif /* SEAMLESS */

extern ULONG   pSysCacheStartPhy;
// extern PBYTE   pSysCacheStart;

extern ULONG   pVRAMCacheStart;
// extern ULONG   offNextFree11Pos;
extern ULONG   offLastFree81Pos;

#ifndef _8514
ULONG eddj_PutImageInCache( PBYTE pImageData,
                            USHORT xGlyphWidth,
                            USHORT yGlyphHeight )
#else // _8514
ULONG eddj_PutImageInCache( PBYTE pImageData,
                            USHORT xGlyphWidth,
                            USHORT yGlyphHeight,
                            USHORT usCachedFontIndex)
#endif // _8514
{
    USHORT xGlyphWidthInBytes;
    USHORT xGlyphWidthHW;
    USHORT usImageSize;
    PBYTE  pCacheDest;
    SHORT  tempDrawMode;
    ULONG  i;
    ULONG  j;
    PBYTE  pDest;
    ULONG  ulOffSave;
    ULONG       FontPlaneOffset;                // Defect 75206
#ifdef _8514
    ULONG       pVRAM;
    USHORT      destX;
    USHORT      destY;
#endif // _8514


    /******************************************************************/
    /* Calculate how much memory the image definition takes up.       */
    /* In Winthorn format the rows are padded to byte boundaries.     */
    /* In the cache they are also padded this way for the benefit of  */
    /* the MESS code.                                                 */
    /******************************************************************/
    xGlyphWidthInBytes = (xGlyphWidth + 7)/8;
    xGlyphWidthHW = (xGlyphWidthInBytes*8)-1;
    usImageSize = xGlyphWidthInBytes * yGlyphHeight;

    /******************************************************************/
    /* First check whether there is enough room in the cache for      */
    /* this character. If not, trash the cache and return zero to     */
    /* indicate that the character was not cached. The main problem   */
    /* will now be that any earlier characters in the current string  */
    /* are now no longer cached! The calling routine will therefore   */
    /* have to call LocateFont to set up a new CacheInfo structure    */
    /* and re-cache all of the characters in the string.              */
    /******************************************************************/
    if (offNextFree11Pos + (ULONG)usImageSize >= offLastFree81Pos )
    {
      return ERROR_ZERO;
    }

#ifdef _8514
    //*****************************************************************
    // 8514 NOTES
    //
    // At this point, we have already checked to see whether the height
    // of one character in this font exceeds the height of the entire
    // font cache.  If so, we abandoned any attempt to cache the font
    // and, instead, use the SrcDestBlt() code to blt the monochrome
    // glyph image directly to the screen.
    //
    // Therefore, we now must check to see if the current cache request
    // will fit into the cache at the current cache destination.  Note
    // that we first check to see if the width of the character exceeds
    // the screen width.  If so, we will start a new row in the font
    // cache and the Y coordinate must be adjusted before we make the
    // check to see if enough room exists.
    //
    // SEAMLESS NOTES
    //
    // Bottom8514FontCache is a global variable that is normally set
    // to the bottom of off-screen VRAM.  This provides us with a
    // 128x1024 area for our PM font cache.  However, when seamless
    // enters the picture, we move the font cache to reside next to
    // the bitmap cache.  The font cache will then cover scan lines
    // 0 through 127 of off-screen VRAM from column 256 to 1016.
    // This provides a 128x1024 area for the Window's driver to use for
    // its' fonts, bitmaps, and screen save area.
    //*****************************************************************
    pVRAM = p8514FontCache [usCachedFontIndex];

    //*****************************************************************
    // Defect 75206. 800x600x16bit in 1 MB VRAM doesn't leave enough room
    // to cache large AVio fonts in one plane.  So, for this resolution,
    // we reduce the number of cached fonts to 8 and allow them to wrap
    // (once) to plane index + 8. aulFontPlaneOffset indicates whether
    // we've wraped yet:
    //              0 - in plane 0 through 7
    //              1 - in plane 8 through 15
    //             -1 - not in 16 bit color, ignore
    //*****************************************************************
    if ( DDT.BitCount == 16 )
       FontPlaneOffset = aulFontPlaneOffset[usCachedFontIndex];
    else
       FontPlaneOffset = -1;

//    Calc8514XY(pVRAM,destX,destY)
    destY = (USHORT)pVRAM;
#ifndef TMP                                                 
    destX = (USHORT)(pVRAM << 16);
#else 
    destX = (USHORT)((pVRAM & 0x0fffffff) >> 16);           
#endif 

    if (destX +  xGlyphWidth >= (USHORT) pCacheMap->font_cache_right)
        destY += yGlyphHeight;

    if (destY +  yGlyphHeight > (USHORT) pCacheMap->font_cache_bottom)
    {
        return(ERROR_ZERO);
    }
#endif

    pCacheDest = pSysCacheStart + offNextFree11Pos;

    for (i = xGlyphWidthInBytes; i--; )
    {
        pDest = pCacheDest++;
        for (j = yGlyphHeight; j--; )
        {
            *pDest = *pImageData++;
            pDest += xGlyphWidthInBytes;
        }
    }

    /******************************************************************/
    /* The character image is now in the buffer, in horizontal row    */
    /* format, but still with rows padded to byte boundaries.         */
    /******************************************************************/
    /******************************************************************/
    /* If we are using the VRAM character cache then we must copy the */
    /* character into it.                                             */
    /******************************************************************/
#ifdef SEAMLESS
    if (foregroundSession && !(fSeamlessActive && fSeamlessCCConflict))
#else
    if (foregroundSession)
#endif
    {
        yGlyphHeight--;

#ifndef   _8514
        /**************************************************************/
        /* Set up the hardware mixes.                                 */
        /**************************************************************/
        ShadowXGARegs.FgMix = HWMIX_SOURCE;
        ShadowXGARegs.BgMix = HWMIX_SOURCE;

        ShadowXGARegs.ColCompCond = COLCOMP_ALWAYS;

        /**************************************************************/
        /* Set up destination pixmap details.                         */
        /**************************************************************/
        ShadowXGARegs.PixMapBaseA   = pVRAMCacheStart + offNextFree11Pos;
        ShadowXGARegs.PixMapWidthA  = xGlyphWidthHW;
        ShadowXGARegs.PixMapHeightA = yGlyphHeight;
        ShadowXGARegs.PixMapFormatA = ONE_BPP;

        /**************************************************************/
        /* Set up source pixmap details.                              */
        /**************************************************************/
        ShadowXGARegs.PixMapBaseB = pSysCacheStartPhy + offNextFree11Pos;
        ShadowXGARegs.PixMapWidthB  = xGlyphWidthHW;
        ShadowXGARegs.PixMapHeightB = yGlyphHeight;
        ShadowXGARegs.PixMapFormatB = ONE_BPP | MOTOROLA;

        /**************************************************************/
        /* Set up blt details - we want to copy the whole character.  */
        /**************************************************************/
        ShadowXGARegs.SrcXAddr =
         ShadowXGARegs.SrcYAddr =
          ShadowXGARegs.DstXAddr =
           ShadowXGARegs.DstYAddr = 0;

        ShadowXGARegs.OpDim1 = xGlyphWidthHW;
        ShadowXGARegs.OpDim2 = yGlyphHeight;

        /**************************************************************/
        /* Set up the pixel op to do the blt we want.                 */
        /**************************************************************/
        ShadowXGARegs.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 blt. We have to use the hardware to do this.    */
        /* Set softDrawInUse to false, and then restore it after the  */
        /* blt has been done. (Higher level functions may be in       */
        /* software drawing mode, but we must still keep the VRAM     */
        /* cache copy up to date.)                                    */
        /**************************************************************/
        tempDrawMode = softDrawInUse;
        softDrawInUse = FALSE;
        TransferShadowRegisters( TSR_MAP_A |
                                 TSR_MAP_B |
                                 TSR_COLOUR_MIX |
                                 TSR_COORDINATES |
                                 TSR_PIXELOP );
        softDrawInUse = tempDrawMode;

#else // _8514

        tempDrawMode = softDrawInUse;
        softDrawInUse = FALSE;

        pVRAM = Cache8514Char ((ULONG) usCachedFontIndex,
                               (ULONG) xGlyphWidth,
                               (ULONG) yGlyphHeight,
                               (PVOID) (pSysCacheStart + offNextFree11Pos),
                               (PULONG) &FontPlaneOffset );

        softDrawInUse = tempDrawMode;

#endif // _8514

    }

    /******************************************************************/
    /* Update the cache pointer to the next free space.               */
    /******************************************************************/
#ifndef _8514
    ulOffSave = offNextFree11Pos;
#else // _8514
    /******************************************************************/
    /* Defect 75206. Update the font plane offset for this character  */
    /* and our global for the font.                                   */
    /******************************************************************/
    aulFontPlaneOffset[usCachedFontIndex] = FontPlaneOffset;

    ulOffSave = pVRAM;
#endif // _8514

    offNextFree11Pos += usImageSize;
    return ulOffSave;
}


// The following codes are not used. Rewritten in ASM code.
// reference only.

#ifdef OMIT                            /* 'reserved' entry offset     */
/*===================== Exported Routine =============================*/
/*      eddj_LocateInCache                                            */
/*                                                                    */
/* Check if given codepoint is already in cache, and returns cache    */
/* index if found.                                                    */
/*                                                                    */
/* Entry      :                                                       */
/*            - ptr to current font's FONTCACHEINFO structure         */
/*            - codepoint to be checked                               */
/*              (if SBCS codepoint, it should be expanded to USHORT   */
/*               before calling this routine)                         */
/*                                                                    */
/* Returns    :                                                       */
/*              Returns index to font cache if found                  */
/*              Returns cache index, with MSB set, when the codepoint */
/*                      is not in cache, but could reserve new entry  */
/*              Returns ERROR_CACHE_FULL   (0xFFFFFFFF) if not found  */
/*                      in cache, and could not reserve an entry as   */
/*                      DBCS index table was already full             */
/*                                                                    */
/* Error Returns :      None                                          */
/*                                                                    */
/* Note       :                                                       */
/*            - 1 additional function of this routine is to 'reserve' */
/*              cache entry for given codepoint.  By this function,   */
/*              later call to this function with same codepoint should*/
/*              return 'Yes, Exist', hence should avoid retrieving    */
/*              1 char's image many times from DBCS FM.  Assumes      */
/*              caller surely put char, for which this routine        */
/*              returns 'Not exist', into cache.                      */
/*                                                                    */
/* Calls      :                                                       */
/*                                                                    */
/*====================================================================*/
LONG eddj_LocateInCache( PFONTCACHEINFO pFCInfo,
                         USHORT usCodepoint )
{                                      /* top of func: LocateInCache  */
  PUSHORT pusIndex;
  LONG lIndex;                         /*                             */

  /*------------------------------------------------------------------*/
  /* Single byte char...                                              */
  /*    We can do this since with SBCS font, all 2bytes chars must be */
  /*    already converted to SBCS default char.  With DBCS font, we   */
  /*    will handle SBCS chars as is for a while, expecting DBCS font */
  /*    manager will change them to DBCS default char.                */
  /*------------------------------------------------------------------*/
  if (!HIBYTE( usCodepoint ))
    {                                  /*                             */
      if (!pFCInfo->aulCachedCharOffset[usCodepoint])
        {                              /* if not in cache             */
          pFCInfo->aulCachedCharOffset[usCodepoint] = CACHE_RESERVED;
          return (LONG)usCodepoint | FLAG_NOT_IN_CACHE;
        }                              /* end of if:                  */
      else                             /* if already in cache         */
        {                              /*                             */
          return (LONG)usCodepoint;    /*                             */
        }                              /* end of else:                */
    }                                  /* end of if:                  */

  /*------------------------------------------------------------------*/
  /* double byte char case                                            */
  /*------------------------------------------------------------------*/
  pFCInfo->ausDBGIndexTable[pFCInfo->usDBGITableNext]
                        = usCodepoint; /* put centinel here           */
                                       /* (1 extra entry is reserved  */
                                       /* in table for the case table */
                                       /* is already full)            */
  for (pusIndex = pFCInfo->ausDBGIndexTable;
       *pusIndex != usCodepoint;
       pusIndex ++);                   /* search the index            */
                                       /*                             */
  lIndex = (LONG)(pusIndex - pFCInfo->ausDBGIndexTable);
                                       /* offset is the index         */
  if (lIndex == (LONG)(pFCInfo->usDBGITableNext))
    {                                  /* if it actually is centinel  */
                                       /*   then could not find it    */
      lIndex = (LONG)pFCInfo->usDBGITableNext ++;
      if (lIndex == MAX_NUM_DBCODEPOINTS)
        {                              /* if index table already full */
          return ERROR_CACHE_FULL;     /*                             */
        }                              /* end of if:                  */

      pFCInfo->ausDBGIndexTable[lIndex] = usCodepoint;
      pFCInfo->aulCachedCharOffset[lIndex + MAX_NUM_CODEPOINTS] =
            CACHE_RESERVED;            /* reserve 1 entry             */
                                       /*                             */
      return (lIndex + MAX_NUM_CODEPOINTS) | FLAG_NOT_IN_CACHE;
    }                                  /* end of if:                  */
  else                                 /*                             */
    {                                  /*                             */
      return lIndex + MAX_NUM_CODEPOINTS;
                                       /* DBCS char is after SBCS     */
    }                                  /* end of else:                */
}                                      /* end of func: LocateInCache  */

/*===================== Exported Routine =============================*/
/*      eddj_ForceCharInCache                                         */
/*                                                                    */
/* If given character is in cache, return cache-index to it.          */
/* If not, put it to cache and return cache-index to it.              */
/*                                                                    */
/* Entry      :                                                       */
/*            - ptr to current font's FONTDETAILS structure           */
/*            - codepoint to be checked                               */
/*              (if SBCS codepoint, it should be expanded to USHORT   */
/*               before calling this routine)                         */
/*                                                                    */
/* Returns    :                                                       */
/*              Returns index to font cache if found                  */
/*                                                                    */
/* Error Returns :      None                                          */
/*                                                                    */
/* Note       :                                                       */
/*            - If cache is flushed because of overflow, this func    */
/*              automatically put the font and the char again.        */
/*                                                                    */
/*            - Font must be in cache when this func is called.       */
/*                                                                    */
/* Calls      :                                                       */
/*                                                                    */
/*====================================================================*/
LONG eddj_ForceCharInCache( PFONTDETAILS pFontDtl, USHORT usCodepoint )
{                                      /* top of func: ForceCharInCach*/
  LONG lCacheIndex;                    /*                             */
                                       /*                             */
  lCacheIndex
    = eddj_LocateInCache( pFontCacheInfo + pFontDtl->usCachedFontIndex,
                          usCodepoint );

  if (lCacheIndex != ERROR_NEG)
    {                                  /* if is already in cache      */
      return lCacheIndex;              /*   return now                */
    }                                  /* end of if:                  */

  lCacheIndex = eddt_CacheCharacter( usCodepoint, pFontDtl );
                                       /* try to put in cache         */
  if (lCacheIndex != ERROR_NEG)
    {                                  /* if cache is not flushed     */
      return lCacheIndex;              /*                             */
    }                                  /* end of if:                  */

  eddt_LocateCachedFont( pFontDtl );   /* put the font in cache again */
  AIxfer.pFontCacheInfo = pFontCacheInfo + pFontDtl->usCachedFontIndex;

  lCacheIndex = eddt_CacheCharacter( usCodepoint, pFontDtl );
                                       /* and retry to put in cache   */
                                       /* MUST NOT fail!              */
  return lCacheIndex;                  /*                             */
}                                      /* end of func: ForceCharInCach*/

/*===================== Exported Routine =============================*/
/*      eddh_update_cache                                             */
/*                                                                    */
/* Make sure that all characters in given string are contained in     */
/* cache.                                                             */
/*                                                                    */
/* Entry      :                                                       */
/*            - ptr to string                                         */
/*                if SBCS CP, string is passed as is                  */
/*                if DBCS/MBCS CP, unified DBCS string is passed      */
/*                      (i.e. all chars are represended by 2 bytes)   */
/*            - number of characters                                  */
/*                      (Note that if DBCS/MBCS CP, is not #bytes)    */
/*            - ptr to current font's FONTCACHEINFO                   */
/*            - ptr to current font's FONTDETAILS                     */
/*            - ptr to variable where total width of given string     */
/*                      is returned (may be NULL)                     */
/*                                                                    */
/* Returns    :                                                       */
/*            - Returns TRUE if completes                             */
/*            - Total of all put characters' width is returned to     */
/*              the buffer if supplied                                */
/*                                                                    */
/* Error Returns :                                                    */
/*              Returns FALSE if error is found                       */
/*                                                                    */
/* Note       :                                                       */
/*            - This replaces the function of same name in            */
/*                      EDDHGCHS.ASM                                  */
/*            - If cache becomes overflow while putting char, this    */
/*                      func returns error (FALSE)                    */
/*            - This function does not care of charSpacing.           */
/*                                                                    */
/* Calls      :                                                       */
/*                                                                    */
/*====================================================================*/
ULONG eddh_update_cache( PCHAR          pCodePoints,
                         ULONG          ulCharNum,
                         PFONTCACHEINFO pFontCacheInfo,
                         PFONTDETAILS   pFontDetails,
                         PUSHORT        pStringWidth )
{                                      /* top of func: eddh_update_cac*/
  ULONG ulIndex;                       /*                             */
  LONG lCacheIndex;                    /* index to cache entry        */
  USHORT usCodepoint;                  /*                             */
  USHORT usWidth;                      /* string width accumulator    */

  const USHORT usSbcsParsing           /* flag if CP is SBCS          */
    = (USHORT)(pFontDetails->NLSParseFlag & NLSCA_SBCS);
  const USHORT usABCFont               /* flag if ABC space font      */
    = (USHORT)(pFontDetails->pFocaFont->fdDefinitions.fsChardef
                 == FONTDEFCHAR3);

  usWidth = 0;
  for (ulIndex = ulCharNum; ulIndex > 0; ulIndex --)
    {                                  /*                             */
      /*--------------------------------------------------------------*/
      /* get 1 char from string                                       */
      /*--------------------------------------------------------------*/
      if (usSbcsParsing)               /* if SBCS CP                  */
        {                              /*                             */
          usCodepoint = (USHORT)*(pCodePoints ++);
                                       /* string is byte basis        */
        }                              /* end of if:                  */
      else                             /* or if DBCS/MBCS CP          */
        {                              /*                             */
          usCodepoint = *( ((PUSHORT)pCodePoints) ++);
                                       /* string is word basis        */
        }                              /* end of else:                */

      /*--------------------------------------------------------------*/
      /* put in cache                                                 */
      /*--------------------------------------------------------------*/
      lCacheIndex
        = eddj_LocateInCache( pFontCacheInfo, usCodepoint );
                                       /* check if it is in cache     */
      if (lCacheIndex == ERROR_NEG)    /* if not in cache now         */
        {                              /*                             */
          lCacheIndex
            = eddt_CacheCharacter( usCodepoint, pFontDetails );
                                       /* try to put it in cache      */
        }                              /* end of if:                  */

      if (lCacheIndex == ERROR_NEG)    /* if still not in cache       */
        {                              /* (i.e. cache was flushed)    */
          return FALSE;                /* no try to recover:return err*/
        }                              /* end of if:                  */

      /*--------------------------------------------------------------*/
      /* codepoint is in cache... now calculate width                 */
      /*--------------------------------------------------------------*/
      if (usABCFont)                   /* if it is ABC space font     */
        {                              /*                             */
          usWidth
            += pFontCacheInfo->aCharDef[lCacheIndex].ABC.usAspace
             + pFontCacheInfo->aCharDef[lCacheIndex].ABC.usBspace
             + pFontCacheInfo->aCharDef[lCacheIndex].ABC.usCspace;
                                       /* add all of 3 widths         */
        }                              /* end of if:                  */
      else                             /* or if it is not ABC font    */
        {                              /*                             */
          usWidth
            += pFontCacheInfo->aCharDef[lCacheIndex].nonABC.usWidth;
        }                              /* end of else:                */
    }                                  /* end of for:                 */

  if (pStringWidth)                    /* if width buffer is supplied */
    {
      *pStringWidth = usWidth;         /* set string width for caller */
    }                                  /* end of if:                  */

  return TRUE;                         /* complete!                   */
}                                      /* end of func: eddh_update_cac*/

/*===================== Exported Routine =============================*/
/*      eddj_force_update_cache                                       */
/*                                                                    */
/* Make sure that all characters in given string are contained in     */
/* cache.  Different from eddh_update_cache since if cache becomes    */
/* overflow while putting characters, this func would re-try to put   */
/* them from the beginning.                                           */
/*                                                                    */
/* Entry      :                                                       */
/* Returns    :                                                       */
/* Error Returns :                                                    */
/*              See eddh_update_cache()                               */
/*                                                                    */
/* Note       :                                                       */
/*            - If cache-overlow re-trial still fails, this func      */
/*                      returns error (FALSE)                         */
/*                                                                    */
/* Calls      :                                                       */
/*                                                                    */
/*====================================================================*/
ULONG eddj_force_update_cache( PCHAR          pCodePoints,
                               ULONG          ulCharNum,
                               PFONTCACHEINFO pFontCacheInfo,
                               PFONTDETAILS   pFontDetails,
                               PUSHORT        pStringWidth )
{                                      /* top of func: eddj_force_upda*/
  if (eddh_update_cache( pCodePoints, ulCharNum, pFontCacheInfo,
                         pFontDetails, pStringWidth ))
    {                                  /* if complete, then return    */
      return TRUE;                     /*                             */
    }                                  /* end of if:                  */

  eddt_LocateCachedFont( pFontDetails );
                                       /* if cache is flushed, then   */
                                       /* put the font again          */
  AIxfer.pFontCacheInfo
    = pFontCacheInfo + pFontDetails->usCachedFontIndex;
                                       /* set ptr for lower level     */
  if (eddh_update_cache( pCodePoints, ulCharNum, pFontCacheInfo,
                         pFontDetails, pStringWidth ))
    {                                  /* if complete, then return    */
      return TRUE;                     /*                             */
    }                                  /* end of if:                  */
  else                                 /* if retrial fails,           */
    {                                  /*                             */
      return FALSE;                    /* no way...                   */
    }                                  /* end of else:                */
}                                      /* end of func: eddj_force_upda*/
#endif /*OMIT*/

