/*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 Name: FDFONT.C                                                     */
/*                                                                            */
/*      Physical font resource access dispatch routine for OS/2 DBCS PM       */
/*      font drivers.                                                         */
/*                                                                            */
/*  Created: 15-Oct-1991                                                      */
/*  Author:  Soh Ohta     [jl09057 @ ymtvm3, IBM Japan]                       */
/*                                                                            */
/*                        Refer to Copyright Inscruction Form No.G120-2083    */
/*                                                                            */
/*  Exported Functions:   none                                                */
/*                                                                            */
/*  Public Functions:     LoadFont                                            */
/*                        FreeFont                                            */
/*                        QueryFocaFont                                       */
/*                        QueryCellSize                                       */
/*                        QueryCellImage                                      */
/*                        FontFromBitmap                                      */
/*                        BitmapFromFont                                      */
/*                                                                            */
/*  Public Data:          none                                                */
/*                                                                            */
/*  General Description:                                                      */
/*                                                                            */
/******************************************************************************/

#define INCL_PM
#define INCL_DOS
#include <os2.h>
#include <memory.h>
#include "resmap.h"


extern NPRESMAPHEADER npResmapHeader;   // font resource mapping definition.
extern CPINFO   cpInfo;                 // codepage vector.
extern HMODULE  hmod;                   // FD's module handle.
extern HHEAP    hHeap;                  // FD's heap handle.
extern SEL      selDs;                  // FD's shared data segment selector.



/******************************************************************************/
/*  LoadFont                                                                  */
/*                                                                            */
/*  Relocate the font desctiptor within the automatic data segment,           */
/*  load physical font resources being associated to it, and return           */
/*  the maximum image buffer size for font image manipulation.                */
/*                                                                            */
/*  Parameter:                                                                */
/*      npVirtual = virtual font descriptor                                   */
/*      npFont    = virtual or physical font descriptor                       */
/*  Return:                                                                   */
/*      success   = image buffer size required                                */
/*      error     = 0                                                         */
/******************************************************************************/

USHORT LoadFont (NPRESMAP npVirtual, NPRESMAP npFont)
{
    register USHORT rc,cb,cbMax;
    VOID            FreeFont (NPRESMAP);

    cbMax = npFont->bitsDef.cbScan*npFont->bitsDef.nScans;

    if (npFont->refCount == 0) {

        if (npFont->fontId != FONT_FD_VIRTUAL_FONT) {
            if (!(npVirtual->fsTypeFlags & FM_TYPE_FIXED) &&
                !(npFont->fsTypeFlags & FM_TYPE_FIXED)) {
                cb = GetMappedCbBuf(npFont->xMaxCharInc,npVirtual,npFont);
                if (cb > cbMax)
                    cbMax = cb;
            }
        }

        if (npFont->npPrivate != INVALID_ADDRESS)
            (USHORT)npFont->npPrivate += (USHORT)npResmapHeader;
        if (npFont->npFont != INVALID_ADDRESS) {
            (USHORT)npFont->npFont += (USHORT)npResmapHeader;
            if ((cb = LoadFont (npVirtual,npFont->npFont)) == 0)
                return 0;
            if (cb > cbMax)
                cbMax = cb;
        }
        switch (npFont->fontId)
        {
            case FONT_FD_VIRTUAL_FONT:  rc = 0;                    break;
            case FONT_CP_MBCS_BASEFONT: rc = LoadCPFont (npFont);  break;
            case FONT_PM_SBCS_RESOURCE: rc = LoadPMFont (npFont);  break;
            case FONT_PM_SBCS_OTHERDLL: rc = LoadPMFont (npFont);  break;
            case FONT_PM_DBCS_USERFONT: rc = LoadPMFont (npFont);  break;
            case FONT_PM_DBCS_FONTFILE: rc = LoadPMFont (npFont);  break;
            case FONT_WIN_DBCS_FONTFILE:rc = LoadWinFont (npFont); break;
            default:                    rc = -1;                   break;
        }
        if ((rc != 0) && (npFont->npFont != INVALID_ADDRESS)) {
            FreeFont (npFont->npFont);
            return 0;
        }
    }
    npFont->refCount++;
    return cbMax;
}

/******************************************************************************/
/*  FreeFont                                                                  */
/*                                                                            */
/*  Free physical font resources associated to the font.                      */
/*                                                                            */
/*  Parameter:                                                                */
/*      npFont    = physical font descriptor                                  */
/*  Return:                                                                   */
/*      nothing                                                               */
/******************************************************************************/

VOID FreeFont (NPRESMAP npFont)
{
    if ((npFont->refCount != 0) && (--npFont->refCount == 0)) {
        switch (npFont->fontId)
        {
            case FONT_CP_MBCS_BASEFONT: FreeCPFont (npFont);  break;
            case FONT_PM_SBCS_RESOURCE: FreePMFont (npFont);  break;
            case FONT_PM_SBCS_OTHERDLL: FreePMFont (npFont);  break;
            case FONT_PM_DBCS_USERFONT: FreePMFont (npFont);  break;
            case FONT_PM_DBCS_FONTFILE: FreePMFont (npFont);  break;
            case FONT_WIN_DBCS_FONTFILE:FreeWinFont (npFont); break;
        }
        if (npFont->npFont != INVALID_ADDRESS)
            FreeFont (npFont->npFont);
    }
}

/******************************************************************************/
/*  QueryFocaFont                                                             */
/*                                                                            */
/*  Return specified font's FOCAFONT structure.                               */
/*                                                                            */
/*  Parameter:                                                                */
/*      ires      = FD font resource id                                       */
/*      lpFoca    = buffer address to return FOCAFONT structure               */
/*  Return:                                                                   */
/*      success   = 0                                                         */
/*      error     = -1                                                        */
/******************************************************************************/

USHORT QueryFocaFont (USHORT ires, PFOCAFONT lpFoca)
{
    PFOCAFONT   lpRes;

    if (DosGetResource2 (hmod,RT_VFONT,npResmapHeader->aFonts[ires].resId,&lpRes) == 0) {
        *lpFoca = *lpRes;
        DosFreeResource (lpRes);

        if (npResmapHeader->aFonts[ires].fsTypeFlags & FM_TYPE_DBCS) {

            lpFoca->fmMetrics.usFirstChar   = cpInfo.usFirstChar;
            lpFoca->fmMetrics.usLastChar    = cpInfo.usLastChar;
            lpFoca->fmMetrics.usDefaultChar = cpInfo.usDefaultChar;
            lpFoca->fmMetrics.usBreakChar   = cpInfo.usBreakChar;
        }
        return 0;
    }
    return -1;
}

/******************************************************************************/
/*  QueryWidth                                                                */
/*                                                                            */
/*  Return specified character cell width.                                    */
/*                                                                            */
/*  Parameter:                                                                */
/*      index     = glyph index                                               */
/*      npVirtual = virtual  font descriptor (FD font being requested)        */
/*      npFont    = physical font descriptor (font to be modified)            */
/*  Return:                                                                   */
/*      success   = character cell width                                      */
/*      error     = 0                                                         */
/******************************************************************************/

USHORT QueryWidth (USHORT index, NPRESMAP npVirtual, NPRESMAP npFont)
{
    register USHORT cx;

    switch (npFont->fontId)
    {
        case FONT_CP_MBCS_BASEFONT: cx = QueryCPWidth (index,npVirtual,npFont); break;
        case FONT_PM_SBCS_RESOURCE: cx = QueryPMWidth (index,npVirtual,npFont); break;
        case FONT_PM_SBCS_OTHERDLL: cx = QueryPMWidth (index,npVirtual,npFont); break;
        case FONT_PM_DBCS_USERFONT: cx = QueryPMWidth (index,npVirtual,npFont); break;
        case FONT_PM_DBCS_FONTFILE: cx = QueryPMWidth (index,npVirtual,npFont); break;
        case FONT_WIN_DBCS_FONTFILE:cx = QueryWINWidth (index,npVirtual,npFont); break;
        default:                    cx = 0;
    }
    if ((cx == 0) && (npFont->npFont != INVALID_ADDRESS))
        cx = QueryWidth (index,npVirtual,npFont->npFont);

    return cx;
}

/******************************************************************************/
/*  QueryDefWidth                                                             */
/*                                                                            */
/*  Return default character cell width.                                      */
/*                                                                            */
/*  Parameter:                                                                */
/*      npVirtual = virtual  font descriptor (FD font being requested)        */
/*      npFont    = physical font descriptor (font to be modified)            */
/*  Return:                                                                   */
/*      success   = character cell width                                      */
/*      error     = 0                                                         */
/******************************************************************************/

USHORT QueryDefWidth (NPRESMAP npVirtual, NPRESMAP npFont)
{
    register USHORT cx;

    switch (npFont->fontId)
    {
        case FONT_CP_MBCS_BASEFONT: cx = QueryDefCPWidth (npVirtual,npFont); break;
        case FONT_PM_SBCS_RESOURCE: cx = QueryDefPMWidth (npVirtual,npFont); break;
        case FONT_PM_SBCS_OTHERDLL: cx = QueryDefPMWidth (npVirtual,npFont); break;
        case FONT_PM_DBCS_USERFONT: cx = QueryDefPMWidth (npVirtual,npFont); break;
        case FONT_PM_DBCS_FONTFILE: cx = QueryDefPMWidth (npVirtual,npFont); break;
        case FONT_WIN_DBCS_FONTFILE:cx = QueryDefWINWidth (npVirtual,npFont); break;
        default:                    cx = 0;
    }
    if ((cx == 0) && (npFont->npFont != INVALID_ADDRESS))
        cx = QueryDefWidth (npVirtual,npFont->npFont);

    return cx;
}

/******************************************************************************/
/*  QueryCellSize                                                             */
/*                                                                            */
/*  Return specified character cell size.                                     */
/*                                                                            */
/*  Parameter:                                                                */
/*      ires      = FD font resource id                                       */
/*      index     = glyph index                                               */
/*      npszsCell = buffer address to return cell size                        */
/*  Return:                                                                   */
/*      success   = 0                                                         */
/*      error     = -1                                                        */
/******************************************************************************/

USHORT QueryCellSize (USHORT ires, USHORT index, SIZES NEAR *npszsCell)
{
    register NPRESMAP   npVirtual = &npResmapHeader->aFonts[ires];
    register NPRESMAP   npFont    = npResmapHeader->aFonts[ires].npFont;

    if (npVirtual->fsTypeFlags & FM_TYPE_FIXED)
        npszsCell->cx = npVirtual->xAveCharWidth;
    else {
        if ((npszsCell->cx = QueryWidth (index,npVirtual,npFont)) == 0)
            if ((npszsCell->cx = QueryDefWidth (npVirtual,npFont)) == 0)
                return -1;
    }
    npszsCell->cy = npVirtual->yMaxBaselineExt;
    return 0;
}

/******************************************************************************/
/*  QueryImage                                                                */
/*                                                                            */
/*  Get specified character image and return its width.                       */
/*                                                                            */
/*  Parameter:                                                                */
/*      index     = glyph index                                               */
/*      npVirtual = virtual  font descriptor (FD font being requested)        */
/*      npFont    = physical font descriptor (font to be modified)            */
/*      lpBuf     = image buffer into which the font is to be built           */
/*      cbBuf     = image buffer size                                         */
/*  Return:                                                                   */
/*      success   = character cell width                                      */
/*      error     = 0                                                         */
/******************************************************************************/

USHORT QueryImage (USHORT index, NPRESMAP npVirtual, NPRESMAP npFont, PBYTE lpBuf, USHORT cbBuf)
{
    register USHORT cx;

    switch (npFont->fontId)
    {
        case FONT_CP_MBCS_BASEFONT: cx = QueryCPImage (index,npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_SBCS_RESOURCE: cx = QueryPMImage (index,npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_SBCS_OTHERDLL: cx = QueryPMImage (index,npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_DBCS_USERFONT: cx = QueryPMImage (index,npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_DBCS_FONTFILE: cx = QueryPMImage (index,npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_WIN_DBCS_FONTFILE:cx = QueryWINImage (index,npVirtual,npFont,lpBuf,cbBuf); break;
        default:                    cx = 0;
    }
    if ((cx == 0) && (npFont->npFont != INVALID_ADDRESS))
        cx = QueryImage (index,npVirtual,npFont->npFont,lpBuf,cbBuf);

    return cx;
}

/******************************************************************************/
/*  QueryDefImage                                                             */
/*                                                                            */
/*  Get default character image and return its width.                         */
/*                                                                            */
/*  Parameter:                                                                */
/*      npVirtual = virtual  font descriptor (FD font being requested)        */
/*      npFont    = physical font descriptor (font to be modified)            */
/*      lpBuf     = image buffer into which the font is to be built           */
/*      cbBuf     = image buffer size                                         */
/*  Return:                                                                   */
/*      success   = character cell width                                      */
/*      error     = 0                                                         */
/******************************************************************************/

USHORT QueryDefImage (NPRESMAP npVirtual, NPRESMAP npFont, PBYTE lpBuf, USHORT cbBuf)
{
    register USHORT cx;

    switch (npFont->fontId)
    {
        case FONT_CP_MBCS_BASEFONT: cx = QueryDefCPImage (npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_SBCS_RESOURCE: cx = QueryDefPMImage (npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_SBCS_OTHERDLL: cx = QueryDefPMImage (npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_DBCS_USERFONT: cx = QueryDefPMImage (npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_PM_DBCS_FONTFILE: cx = QueryDefPMImage (npVirtual,npFont,lpBuf,cbBuf); break;
        case FONT_WIN_DBCS_FONTFILE:cx = QueryDefWINImage (npVirtual,npFont,lpBuf,cbBuf); break;
        default:                    cx = 0;
    }
    if ((cx == 0) && (npFont->npFont != INVALID_ADDRESS))
        cx = QueryDefImage (npVirtual,npFont->npFont,lpBuf,cbBuf);

    return cx;
}

/******************************************************************************/
/*  QueryCellImage                                                            */
/*                                                                            */
/*  Get specified character image and return its size.                        */
/*                                                                            */
/*  Parameter:                                                                */
/*      ires      = FD font resource id                                       */
/*      index     = glyph index                                               */
/*      npszsCell = buffer address to return cell size                        */
/*      lpBuf     = image buffer into which the font is to be built           */
/*      cbBuf     = image buffer size                                         */
/*  Return:                                                                   */
/*      success   = 0                                                         */
/*      error     = -1                                                        */
/******************************************************************************/

USHORT QueryCellImage (USHORT ires, USHORT index, SIZES NEAR *npszsCell, PBYTE lpBuf, USHORT cbBuf)
{
    register NPRESMAP   npVirtual = &npResmapHeader->aFonts[ires];
    register NPRESMAP   npFont    = npResmapHeader->aFonts[ires].npFont;

    if ((npszsCell->cx = QueryImage (index,npVirtual,npFont,lpBuf,cbBuf)) == 0)
        if ((npszsCell->cx = QueryDefImage (npVirtual,npFont,lpBuf,cbBuf)) == 0)
            return -1;

    npszsCell->cy = npVirtual->yMaxBaselineExt;
    return 0;
}

/******************************************************************************/
/*  FontFromBitmap                                                            */
/*                                                                            */
/*  Convert bitmap image to font image.                                       */
/*                                                                            */
/*  Parameter:                                                                */
/*      lpFont    = destination font image                                    */
/*      npBd      = source bitmap image                                       */
/*  Return:                                                                   */
/*      nothing                                                               */
/******************************************************************************/

VOID FontFromBitmap (PBYTE lpFont, NPBITSDEF npBd)
{
    register NPBYTE npBitmap;
    register USHORT cbScan,nScans,n;

    cbScan = npBd->cbScan;
    for (n=0; n<cbScan; n++) {
        npBitmap = npBd->npBits+n;
        nScans   = npBd->nScans;
        while (nScans--) {
            *lpFont = *npBitmap;
            npBitmap += cbScan;
            lpFont++;
        }
    }
}

/******************************************************************************/
/*  BitmapFromFont                                                            */
/*                                                                            */
/*  Convert font image to bitmap image.                                       */
/*                                                                            */
/*  Parameter:                                                                */
/*      npBd      = destination bitmap image                                  */
/*      lpFont    = source font image                                         */
/*  Return:                                                                   */
/*      nothing                                                               */
/******************************************************************************/

VOID BitmapFromFont (NPBITSDEF npBd, PBYTE lpFont)
{
    register NPBYTE npBitmap;
    register USHORT cbScan,nScans,n;

    cbScan = npBd->cbScan;
    for (n=0; n<cbScan; n++) {
        npBitmap = npBd->npBits+n;
        nScans   = npBd->nScans;
        while (nScans--) {
            *npBitmap = *lpFont;
            npBitmap += cbScan;
            lpFont++;
        }
    }
}

/******************************************************************************/
/*  InitDiskCache                                                             */
/*                                                                            */
/*  Initialize disk cache for the specified font.                             */
/*  Be sure that we don't return the error even if the cache allocation       */
/*  is failed. We can access the fontfile in that case.                       */
/*                                                                            */
/*  Parameter:                                                                */
/*      npFileInfo= font file information table                               */
/*  Return:                                                                   */
/*      success   = 0                                                         */
/*      error     = -1                                                        */
/******************************************************************************/

#define ulFileSize  (0L)                // DosOpen fixed parameters.
#define usAttribute (0)
#define fsOpenFlags (FILE_OPEN)
#define fsOpenMode  (OPEN_SHARE_DENYWRITE)
#define ulReserved  (0L)


USHORT InitDiskCache (NPFONTFILEINFO npFileInfo)
{
    if ((npFileInfo->cbCache != 0) &&
        (npFileInfo->npCache == INVALID_ADDRESS) &&
        ((npFileInfo->npCache = WinAllocMem (hHeap,npFileInfo->cbCache)) == NULL)) {

        // cannot allocate cache buffer.
        npFileInfo->npCache = INVALID_ADDRESS;
        return 0;   // be sure no error.
    }
    npFileInfo->ulOffset = 0;   // top of file
    npFileInfo->cbValid  = 0;   // no data in the cache
    return 0;
}

/******************************************************************************/
/*  FreeDiskCache                                                             */
/*                                                                            */
/*  Free disk cache allocated for the specified font.                         */
/*                                                                            */
/*  Parameter:                                                                */
/*      npFileInfo= font file information table                               */
/*  Return:                                                                   */
/*      nothing                                                               */
/******************************************************************************/

VOID FreeDiskCache (NPFONTFILEINFO npFileInfo)
{
    if (npFileInfo->npCache != INVALID_ADDRESS) {
        WinFreeMem (hHeap,npFileInfo->npCache,npFileInfo->cbCache);
        npFileInfo->npCache = INVALID_ADDRESS;
    }
}

/******************************************************************************/
/*  ReadDiskCache                                                             */
/*                                                                            */
/*  Read font image whether from the cache or from the font file.             */
/*                                                                            */
/*  Parameter:                                                                */
/*      npFileInfo= font file information table                               */
/*      ulOffset  = offset from the top of file                               */
/*      npBuf     = address to save font image                                */
/*      cbBuf     = image buffer size                                         */
/*  Return:                                                                   */
/*      success   = number of bytes read                                      */
/*      error     = 0                                                         */
/******************************************************************************/

USHORT ReadDiskCache (NPFONTFILEINFO npFileInfo, ULONG ulOffset, NPBYTE npBuf, USHORT cbBuf)
{
    HFILE            hFile;
    USHORT           usAction;
    USHORT           cbBytesRead;
    register USHORT  usOffset;

    if ((npFileInfo->cbCache < cbBuf) ||
        (npFileInfo->npCache == INVALID_ADDRESS)) {

        // requested data is too large, or cache is not allocated.
        // read image from the file directly.

        if (DosOpen (npFileInfo->szFile,&hFile,&usAction,ulFileSize,
                     usAttribute,fsOpenFlags,fsOpenMode,ulReserved) == 0) {
            if ((DosChgFilePtr (hFile,ulOffset,FILE_BEGIN,&ulOffset) == 0) &&
                (DosRead (hFile,MAKEP(selDs,npBuf),cbBuf,&cbBytesRead) == 0) &&
                (cbBytesRead == cbBuf)) {
                DosClose (hFile);
                return cbBuf;
            }
            DosClose (hFile);
        }
        return 0;
    }

    if ((ulOffset >= npFileInfo->ulOffset) &&
        (ulOffset+cbBuf <= npFileInfo->ulOffset+npFileInfo->cbValid)) {

        // requested image is fullly in the cache.
        // return cached image.

        usOffset = ulOffset-npFileInfo->ulOffset;
        memcpy (npBuf,npFileInfo->npCache+usOffset,(size_t)cbBuf);
        return cbBuf;
    }

    // a part or whole of requested image is not cached.
    // read fresh copy of image, cache it and return the image.

    cbBytesRead = 0;
    if (DosOpen (npFileInfo->szFile,&hFile,&usAction,ulFileSize,
                 usAttribute,fsOpenFlags,fsOpenMode,ulReserved) == 0) {
        if ((DosChgFilePtr (hFile,ulOffset,FILE_BEGIN,&ulOffset) == 0) &&
            (DosRead (hFile,MAKEP(selDs,npFileInfo->npCache),npFileInfo->cbCache,&cbBytesRead) == 0) &&
            (cbBytesRead >= cbBuf)) {

            memcpy (npBuf,npFileInfo->npCache,(size_t)cbBuf);
            npFileInfo->ulOffset = ulOffset;
            npFileInfo->cbValid  = cbBytesRead;
            DosClose (hFile);
            return cbBuf;
        }
        npFileInfo->ulOffset = ulOffset;
        npFileInfo->cbValid  = cbBytesRead;
        DosClose (hFile);
    }
    return 0;
}

