/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark Corporation, 1989                                   */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/**************************************************************************
 *
 * SOURCE FILE NAME = PRDTQERY
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdt_QueryTextBox
 *             prdt_QueryCharPositions
 *             prdt_QueryWidthTable
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/


#define INCL_32                  /* CON3201 */
#define INCL_DOSPROCESS           /* CON3201 */
#define INCL_DOSSEMAPHORES
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_GPIERRORS
#include <os2.h>
#undef  INCL_DOSPROCESS           /* CON3201 */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#define INCL_DDIMISC
#define INCL_DDICOMFLAGS
#define INCL_GREALL
#include <pmddi.h>
#undef INCL_GREALL
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS
#undef INCL_DDIMISC
#undef INCL_DDICOMFLAGS

#define INCL_WINP_SELSERVER
#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_WINP_SELSERVER
#undef INCL_32                    /* CON3201 */

#include <prdconse.h>
#include <prddcone.h>
#include <prdtcone.h>

#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL

#include <prdaextf.h>
#include <prdgextf.h>
#include <prdtextf.h>
#include <prdyextf.h>



/**********************************************************************/
/* Set up external access to the engine functions (which we may have  */
/* have to use for simulations).                                      */
/**********************************************************************/
extern PFNL            da_ConvertWithMatrix;
extern PFNL            da_QueryCharPositions;
extern PFNL            da_QueryTextBox;
extern PFNL            da_QueryWidthTable;



/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdt_QueryTextBox                                      */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   See "OS/2 Technical Reference: I/O Subsytems and Device Drivers" */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function determines the size of the bounding box for the    */
/*   string of text specified by ArgCharNum and ArgCodePoints.  It    */
/*   returns all the corners of the box (in the order topleft,        */
/*   bottomleft, topright, bottomright) and also the position for a   */
/*   further character in the string (allowing for direction of       */
/*   string).                                                         */
/*                                                                    */
/**********************************************************************/
ULONG EXPENTRY prdt_QueryTextBox( HDC       DcH,
                                  LONG      ArgCharNum,
                                  PCH       ArgCodePoints,
                                  LONG      ArgCount,
                                  PPOINTL   ArgTextBox,
                                  lpDCI     DCIData,
                                  ULONG     FunN)

{
#define TFUNC "prdt_QryTextBox"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG              Command;
    lpFontDataType     pFontData;
    lpFontInfoType     pFontInfo;
    LONG               RetVal;
    XFORM              xfm;
    USHORT             fsXform;
    PDCHARBUNDLE       CurTxtAts;
    USHORT             i;              /* Loop control variable       */
    LONG               Width,
                       Depth,
                       Height;
    POINTL             lPoint;
    StringInfoType     StringInfoWorld;
    CellInfoType       CellInfo;
    PBYTE              ValidatedCpts = FNULL;


    /******************************************************************/
    /* If no chars in text box return an error.                       */
    /******************************************************************/
    /******************************************************************/
    /* PD00468 : Do error checks on the parameters                    */
    /******************************************************************/
    if ( ArgCharNum <= 0L)
    {
        LOGERR(TFUNC, "Invalid Length", FNULL, 0, PMERR_INV_LENGTH_OR_COUNT);
        return (ERROR_ZERO);
    }

    /******************************************************************/
    /* Initial stuff..                                                */
    /******************************************************************/
#ifdef PRD_TIMING
    DEKHOOK0(A,9,6B)
#endif
    prdm_EnterDriver(DCIData);

/*  Command = (HIUSHORT)FunN;       CON3201 */
    Command = FunN & 0xFFFF0000; /* CON3201 */
    RetVal  = OK;

    /******************************************************************/
    /* Set up pointers.                                               */
    /******************************************************************/
    pFontData = &DCIData->DCIFontData;
    pFontInfo = &pFontData->Info;
    CurTxtAts = DCIData->DCICurTxtAts;


    /******************************************************************/
    /* Check that we can handle the text attributes - if not return   */
    /* for simulation.                                                */
    /*                                                                */
    /* The driver should handle this call for device fonts even when  */
    /* attribute bundle fFlags is set to a value for which the driver */
    /* would pass any CharString call back to the engine since the    */
    /* engine makes a hash of calculating the simulated text box (the */
    /* results vary with the resolution - the engine is probably      */
    /* using the COM_TRANSFORM bit incorrectly).                      */
    /*                                                                */
    /* The driver ignores the attributes and so passes back the       */
    /* same text box as for non-attributed text.  This is fine        */
    /* for underline, strikeout and italic attrs (note that italic    */
    /* is drawn as normal text since the driver cannot cope with the  */
    /* engine's method of italicising text).  This is reasonable for  */
    /* the bold attr as the driver will only be one pel out (the      */
    /* engine simulates bold by drawing two strings one pel apart).   */
    /*                                                                */
    /* In a future release we should consider handling these          */
    /* attribute flags ourselves.                                     */
    /*                                                                */
    /* If the direction is not left -> right we try to return for     */
    /* simulation - if this is not allowed then we calculate          */
    /* assuming left -> right.                                        */
    /*                                                                */
    /* Ditto if the font needs kerning (currently none of the device  */
    /* fonts do).                                                     */
    /*                                                                */
    /* PD00110 : Return CM_MODE2 image font textbox for simulation    */
    /* if angled/sheared                                              */
    /******************************************************************/

    /******************************************************************/
    /* New comment:                                                   */
    /* Ignore the ENG_ATTS_REQD flag for the text box (see above).    */
    /* Simulate if an engine font.                                    */
    /* Otherwise, as CharStringPos, with one exception.               */
    /* If CM_MODE2 image font, then do not simulate if Angle/Shear    */
    /* are non-zero - the call is invalid, so driver can just         */
    /* return the normal values.                                      */
    /*                                                                */
    /* PD00110 : above comment is correct, but other drivers handle   */
    /* mode 2 angled text box for image font - so return for          */
    /* simulation.                                                    */
    /* Also : shear has been taken out of TEXT_SIML_REQD flag, so     */
    /* check explicitly here.                                         */
    /******************************************************************/
    /* old code (v1.204)                                              */
    /*if ( (pFontInfo->Type == FT_ENGINE) ||                          */
    /*   ( (DCIData->DCIStateFlags & TEXT_SIML_REQD)                  */
    /*     !( (CurTxtAts->cbnd.usPrecision == CM_MODE2) &&            */
    /*        !(pFontData->pMetrics->fsDefn & FM_DEFN_OUTLINE) ) ) || */
    /*   (pFontData->pMetrics->usKerningPairs != 0) )                 */
    /******************************************************************/

    if ( (pFontInfo->Type == FT_ENGINE) ||
       ( (DCIData->DCIStateFlags & TEXT_SIML_REQD) ||
         (DCIData->DCICurTxtAts->cbnd.ptlShear.x != 0L ) ) ||
         (pFontData->pMetrics->usKerningPairs != 0) )
    {
        if ( !(Command & COM_DEVICE) )
        {
           RetVal = ENG_CALL;
           goto EXIT_FUNCTION;
        }
    }

    /******************************************************************/
    /* Pick up the string width - this is in world coords (if in      */
    /* mode 2 or outline font) or in font coords.                     */
    /******************************************************************/
    Width = prdt_GetStringWidth( ArgCharNum,
                                 ArgCodePoints,
                                 FNULL,                /*  PosVector  */
                                 DCIData );

    /******************************************************************/
    /* The text box "depth" is MaxDescender, the "height" is          */
    /* MaxAscender.  The metrics for the device fonts are such that   */
    /* we always have:                                                */
    /*                                                                */
    /*   MaxBaselineExt = MaxAscender + MaxDescender.                 */
    /*                                                                */
    /* Height and BaseOffset are set up (in the CptInfo structure     */
    /* held in the font data) as :                                    */
    /*                                                                */
    /*   Height = MaxBaselineExt; BaseOffset = MaxAscender            */
    /*                                                                */
    /* These values do not vary between characters for device fonts.  */
    /******************************************************************/
    /******************************************************************/
    /* Values are already adjusted for DW,DH attributes.              */
    /******************************************************************/
    Depth  = (LONG)(pFontData->CPtInfo.HeightInWorkCoords -
                             pFontData->CPtInfo.BaseOffsetInWorkCoords);
    Height = (LONG)pFontData->CPtInfo.BaseOffsetInWorkCoords;

    /******************************************************************/
    /* Now need to fill the text box, with transforms if necessary.   */
    /******************************************************************/
    if (!( !(Command & COM_TRANSFORM) &&
                   (pFontData->CPtInfo.WorkCoords == COORD_WORLD) ) )
    {
        /**************************************************************/
        /* Not the special case of device coords requested but world  */
        /* coords used.                                               */
        /**************************************************************/
        /******************************************************************/
        /* We only return as many coordinate pairs as there is room at    */
        /* ArgTextBox to hold (determined by ArgCount).  The bounding     */
        /* rectangle returned (i.e. the first 4 points) is EXCLUSIVE.     */
        /******************************************************************/
        for ( i = 0; i < (USHORT)ArgCount && i < 5; i++ )
        {
            switch ( i )
            {
                case TXTBOX_TOPLEFT:
                    ArgTextBox[0].x = 0L;
                    ArgTextBox[0].y = Height;
                    break;

                case TXTBOX_BOTTOMLEFT:
                    ArgTextBox[1].x = 0L;
                    ArgTextBox[1].y = -Depth;
                    break;

                case TXTBOX_TOPRIGHT:
                    ArgTextBox[2].x = Width;
                    ArgTextBox[2].y = Height;
                    break;

                case TXTBOX_BOTTOMRIGHT:
                    ArgTextBox[3].x = Width;
                    ArgTextBox[3].y = -Depth;
                    break;

                case TXTBOX_CONCAT:
                    ArgTextBox[4].x = Width;
                    ArgTextBox[4].y = 0L;
                    break;
            }
            /*.. switch ( i ) ........................................... */

        }
        /*.... for ( i = 0; i < (Word)ArgCount && i < 5; i++ ) .......... */


        /******************************************************************/
        /* The text box values will be in font or world coords depending  */
        /* on the text mode; they are required in device or world coords  */
        /* depending on whether COM_TRANSFORM is set or not.              */
        /******************************************************************/
        if ( !(Command & COM_TRANSFORM) &&
                           (pFontData->CPtInfo.WorkCoords == COORD_FONT) )
        {
            fsXform = FONT_TO_DEVICE | IGNORE_ORIGIN_SHIFT;
        }
        else if ( (Command & COM_TRANSFORM) &&
                           (pFontData->CPtInfo.WorkCoords == COORD_FONT) )
        {
            fsXform = FONT_TO_WORLD | IGNORE_ORIGIN_SHIFT;
        }
        else if ( !(Command & COM_TRANSFORM) &&
                           (pFontData->CPtInfo.WorkCoords == COORD_WORLD) )
        {
            fsXform = WORLD_TO_DEVICE | IGNORE_ORIGIN_SHIFT;
        }
        else
        {
            /**************************************************************/
            /* World -> World - nowt to do.                               */
            /**************************************************************/
            goto EXIT_FUNCTION;
        }

        /******************************************************************/
        /* Get the xform matrix and use it.                               */
        /******************************************************************/
        if ( prdg_GetXformMatrix( DcH,
                                  fsXform,
                                  (PXFORM)&xfm,
                                  DCIData ) != OK )
        {
            RetVal = ERROR_ZERO;
            goto EXIT_FUNCTION;
        }

        if ( !da_ConvertWithMatrix(
                      DcH,
                      (PPOINTL)ArgTextBox,
                      ((USHORT)ArgCount <= 5) ? (LONG)ArgCount : 5L,
                      (PXFORM)&xfm ,
                      0L,
                      NGreConvertWithMatrix) )
        {
            RetVal = ERROR_ZERO;
            goto EXIT_FUNCTION;
        }
    }
    else
    {
        /**************************************************************/
        /* We need to do a special here: if we're at CM_MODE2 with    */
        /* angle or shear (so that we send text drawing and query     */
        /* functions back for simulation) the engine calls us back    */
        /* with QueryTextBox, one char at a time, with COM_DEVICE     */
        /* set and COM_TRANSFORM not set. It expects us to be working */
        /* in device coords, so that we can return the text box       */
        /* without any transforming, orthogonal to the (device        */
        /* coords) axes.                                              */
        /*                                                            */
        /* If we transform from world to device coords here, then     */
        /* our matrix might end up skew w.r.t. the device coords      */
        /* axes, which messes up the engine's positioning.            */
        /*                                                            */
        /* Get the Xform matrix.                                      */
        /**************************************************************/
        fsXform = WORLD_TO_DEVICE | IGNORE_ORIGIN_SHIFT;

        if ( prdg_GetXformMatrix( DcH,
                                  WORLD_TO_DEVICE | IGNORE_ORIGIN_SHIFT,
                                  (PXFORM)&xfm,
                                  DCIData ) != OK )
        {
           RetVal = ERROR_ZERO;
           goto EXIT_FUNCTION;
        }

        /**************************************************************/
        /* Instead, use prdt_XformPoint.                              */
        /*                                                            */
        /* Transform the width.                                       */
        /**************************************************************/
        lPoint.x = Width;
        lPoint.y = 0;
        Width = prdg_XformPoint( DcH, (PPOINTL)&lPoint, (PXFORM)&xfm);

        /**************************************************************/
        /* The depth and height.                                      */
        /**************************************************************/
        lPoint.x = 0;
        lPoint.y = Depth;
        Depth = prdg_XformPoint( DcH, (PPOINTL)&lPoint, (PXFORM)&xfm);

        lPoint.x = 0;
        lPoint.y = Height;
        Height = prdg_XformPoint( DcH, (PPOINTL)&lPoint, (PXFORM)&xfm);

        /**************************************************************/
        /* Fill the text box.                                         */
        /*                                                            */
        /* Note the fall-through on the switch statement to fill as   */
        /* many points as necessary.                                  */
        /**************************************************************/
        switch ( (USHORT)ArgCount - 1 )
        {
           case TXTBOX_CONCAT:
               ArgTextBox[4].x = Width;
               ArgTextBox[4].y = 0L;

           case TXTBOX_BOTTOMRIGHT:
               ArgTextBox[3].x = Width;
               ArgTextBox[3].y = -Depth;

           case TXTBOX_TOPRIGHT:
               ArgTextBox[2].x = Width;
               ArgTextBox[2].y = Height;

           case TXTBOX_BOTTOMLEFT:
               ArgTextBox[1].x = 0L;
               ArgTextBox[1].y = -Depth;

           case TXTBOX_TOPLEFT:
               ArgTextBox[0].x = 0L;
               ArgTextBox[0].y = Height;
        }
    }

EXIT_FUNCTION:

    /**********************************************************/
    /* Free any memory allocated for Validated codepoints     */
    /*  in the case of device outline fonts                   */
    /**********************************************************/
    if (ValidatedCpts != FNULL)
    {
        (VOID)prdg_FreeHeapItem(DCIData, (USHORT)ArgCharNum,
                                      /* (PUSHORT)&ValidatedCpts); */
                                         (PUSHORT)ValidatedCpts); /*CON3201*/
    }

#ifdef PRD_TIMING
    DEKHOOK0(A,9,EB)
#endif
    prdm_LeaveDriver(DCIData);

    if ( RetVal == ENG_CALL )
    {
        /**************************************************************/
        /* Return to engine if the COM_DEVICE bit allows, otherwise   */
        /* do nowt.                                                   */
        /**************************************************************/
        if ( !(Command & COM_DEVICE) )
            return ( da_QueryTextBox( DcH,
                                      ArgCharNum, ArgCodePoints,
                                      ArgCount, ArgTextBox,
                                      DCIData,
                                      FunN ) );
        else
            return (OK);
    }
    else
        return (RetVal);

}
#undef TFUNC






/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdt_QueryCharPositions                                */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   See "OS/2 Technical Reference: I/O Subsytems and Device Drivers" */
/*                                                                    */
/*   HDC               DcH;                                           */
/*   PPOINTL           ArgStart;                                      */
/*   ULONG             ArgOptions;                                    */
/*   LONG              ArgCharNum;                                    */
/*   PCH               ArgCodePoints;                                 */
/*   PLONG             ArgPosVector;                                  */
/*   PPOINTL           ArgXY;                                         */
/*   lpDCI             DCIData;                                       */
/*   ULONG             FunN;                                          */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function returns an array of coords which give the          */
/*   positions of each character in the string specified by           */
/*   ArgCodePoints and also the position of the first character after */
/*   the string.                                                      */
/*                                                                    */
/*   Hence ArgXY should have room for ArgCharNum + 1 coords.  The     */
/*   code automatically handles the case of ArgCharNum = 0.           */
/*                                                                    */
/*   This function should return the same set of points as are        */
/*   used by CharStringPos.  We force the y-coord to be constant -    */
/*   comment in PRDTSUBR.C on non-orthogonal xforms.                  */
/*                                                                    */
/**********************************************************************/
ULONG EXPENTRY prdt_QueryCharPositions ( HDC         DcH,
                                         PPOINTL     ArgStart,
                                         ULONG       ArgOptions,
                                         LONG        ArgCharNum,
                                         PCH         ArgCodePoints,
                                         PLONG       ArgPosVector,
                                         PPOINTL     ArgXY,
                                         lpDCI       DCIData,
                                         ULONG       FunN)

{
#define TFUNC "prdt_QryCharPos"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    USHORT             WorkCoords,
                       ReqdCoords,
                       StartCoords;
    BOOL               bFixedPitch;
    lpFontDataType     pFontData;
    lpFontInfoType     pFontInfo;
    lpCodePointType    pCPtInfo;
    POINTL             CurrPos;
    POINTL             StartPos;
    XFORM              xfm;
    ULONG              fsXform;
    PDCHARBUNDLE       CurTxtAts;
    LONG               RetVal;
    BOOL               InclStartPos;
    ULONG              Command;
    USHORT             j;
    ULONG              Width;
    StringInfoType     StringInfoWorld;
    CellInfoType       CellInfo;
    PBYTE              ValidatedCpts = FNULL;              /* PD00461 */


    /******************************************************************/
    /* Lock this DC to this thread                                    */
    /******************************************************************/
#ifdef PRD_TIMING
    DEKHOOK0(A,9,6C)
#endif
    prdm_EnterDriver(DCIData);

    /******************************************************************/
    /* PD00287 : Do error checks on the parameters                    */
    /******************************************************************/
    if ( ArgCharNum < 0)
    {
        LOGERR(TFUNC, "Invalid Length", FNULL, 0, PMERR_INV_LENGTH_OR_COUNT);
        RetVal = ERROR_ZERO;
        goto EXIT_FUNCTION;
    }

    /******************************************************************/
    /* PD00790 : Do error checks on start postion flag.               */
    /******************************************************************/
    if (ArgStart == FNULL)
    {
        if (!(ArgOptions | CHS_START_XY))
        {
            LOGERR(TFUNC, "Invalid option", FNULL, 0,
                                 PMERR_INV_CHAR_POS_OPTIONS);
            RetVal = ERROR_ZERO;
            goto EXIT_FUNCTION;
        }
    }

    /******************************************************************/
    /* Now start the work.                                            */
    /******************************************************************/
/*  Command = (HIUSHORT)FunN;       CON3201 */
    Command = FunN & 0xFFFF0000; /* CON3201 */
    RetVal  = OK;

    /******************************************************************/
    /* Set up pointers.                                               */
    /******************************************************************/
    pFontData = &DCIData->DCIFontData;
    pFontInfo = &pFontData->Info;
    pCPtInfo  = &pFontData->CPtInfo;
    CurTxtAts = DCIData->DCICurTxtAts;

    /******************************************************************/
    /* Call engine if this is an engine font.                         */
    /* If TEXT_SIML_REQD is set (see prdasetb.c) then simulate        */
    /* (as for CharStringPos).                                        */
    /* The driver does not support kerning directly.                  */
    /*                                                                */
    /* If COM_DEVICE is set then we have to proceed.                  */
    /******************************************************************/

    if ( ( (pFontInfo->Type == FT_ENGINE) ||
           (DCIData->DCIStateFlags & TEXT_SIML_REQD) ||
           (pFontData->pMetrics->usKerningPairs != 0) )  &&
           !(Command & COM_DEVICE) )
    {
       RetVal = ENG_CALL;
       goto EXIT_FUNCTION;
    }

    /******************************************************************/
    /* Can't use device fonts in Memory DC...                         */
    /******************************************************************/
    if ( DCIData->DCIDCType == OD_MEMORY )
    {
       LOGERR(TFUNC, "Invalid DC type", FNULL, 0, PMERR_INCORRECT_DC_TYPE);
       RetVal = ERROR_ZERO;
       goto EXIT_FUNCTION;
    }

    /******************************************************************/
    /* Set up method flags; the method is chosen to retain maximum    */
    /* accuracy and to avoid rounding errors.                         */
    /*                                                                */
    /*  - ReqdCoords depends on the COM_TRANSFORM bit                 */
    /*  - WorkCoords depends on the positioning method - i.e. font    */
    /*     metrics, mode 2 cell width or position vectors.            */
    /*  - StartCoords is the same as ReqdCoords except when we are    */
    /*     working in font metrics and returning in device coords.    */
    /*                                                                */
    /* If StartCoords = WorkCoords the start position is included in  */
    /* the points array as we build it up (i.e. before any xform is   */
    /* done).  Otherwise we build up the points array relative to     */
    /* (0,0), xform it and then add in the start position.            */
    /*                                                                */
    /* At this stage we also pick up any transform matrix required.   */
    /* We ignore the origin shift when converting to or from World    */
    /* coords as in these cases (in turns out) we are in effect       */
    /* converting widths and not coords.  For a conversion between    */
    /* Font and Device coords the origin shift will always be null.   */
    /*                                                                */
    /* Put another way...                                             */
    /*                                                                */
    /*          Ý   Dont use font metrics  Ý  Use font metrics        */
    /*          Ý                          Ý                          */
    /*          Ý   C_T        !C_T        Ý  C_T        !C_T         */
    /*          Ý                          Ý                          */
    /*  Work    Ý    W          W          Ý   F          F           */
    /*  Reqd    Ý    W          D          Ý   W          D           */
    /*  Start   Ý    W          D          Ý   W          F           */
    /*  InclSP  Ý    Yes        No         Ý   No         Yes         */
    /*  Xform   Ý    None       W->D       Ý   F->W       F->D        */
    /*                                                                */
    /******************************************************************/
    if ( (ArgOptions & CHS_VECTOR) ||
         (CurTxtAts->cbnd.usPrecision == CM_MODE2) ||
         (pFontData->pMetrics->fsDefn & FM_DEFN_OUTLINE) )
    {
       WorkCoords = COORD_WORLD;
       ReqdCoords = (Command & COM_TRANSFORM) ? COORD_WORLD : COORD_DEVICE;
       StartCoords = ReqdCoords;

       if ( Command & COM_TRANSFORM )
           fsXform = VALUE_NOT_SET;       /* would be World -> World */
       else
           fsXform = WORLD_TO_DEVICE | IGNORE_ORIGIN_SHIFT;
    }
    else
    {
       WorkCoords = COORD_FONT;
       ReqdCoords = (Command & COM_TRANSFORM) ? COORD_WORLD : COORD_DEVICE;

       if ( Command & COM_TRANSFORM )
       {
          StartCoords = COORD_WORLD;
          fsXform = FONT_TO_WORLD | IGNORE_ORIGIN_SHIFT;
       }
       else
       {
          StartCoords = COORD_FONT;
          fsXform = FONT_TO_DEVICE | KEEP_ORIGIN_SHIFT;
       }
    }

    if ( StartCoords == WorkCoords )
       InclStartPos = TRUE;
    else
       InclStartPos = FALSE;


    /******************************************************************/
    /* Pick up the starting position in ULONGs.                       */
    /******************************************************************/
    if ( prdt_GetStartPos( DcH,
                           ArgStart,
                           ArgOptions,
                           &StartPos,
                           StartCoords,
                           Command,
                           DCIData ) != OK )
    {
       RetVal = ERROR_ZERO;
       goto EXIT_FUNCTION;
    }

    /******************************************************************/
    /* Pick up any xform matrix reqd.                                 */
    /******************************************************************/
    if ( fsXform != VALUE_NOT_SET ) /* CON3203 */
    {
       if ( prdg_GetXformMatrix( DcH,
                                 (USHORT)fsXform,
                                 (PXFORM)&xfm,
                                 DCIData ) != OK )
       {
          RetVal = ERROR_ZERO;
          goto EXIT_FUNCTION;
       }
    }

    /******************************************************************/
    /* Include that start position - yo!                              */
    /******************************************************************/
    if ( InclStartPos )
    {
       ArgXY[0].x = StartPos.x;
       ArgXY[0].y = StartPos.y;
    }
    else
    {
       ArgXY[0].x = 0L;
       ArgXY[0].y = 0L;
    }

    /******************************************************************/
    /* Set flag to indicate fixed pitch.                              */
    /******************************************************************/
    bFixedPitch = pFontInfo->pFont->WidthFlag & FMF_WIDTH_MASK;

    /******************************************************************/
    /* Now cycle through through each character picking up the next   */
    /* positioning coord.                                             */
    /******************************************************************/
    for ( j = 0; j < (USHORT)ArgCharNum; j++ )
    {
       /**************************************************************/
       /* Set up access to current code point information -          */
       /* in fact since only the width is used no need to call       */
       /* if this is a fixed pitch font.                             */
       /**************************************************************/
       if ( !bFixedPitch )
           prdt_NextCodePoint( (USHORT)ArgCodePoints[j],
                               pFontData,
                               DCIData );

       /**************************************************************/
       /* Calculate width of this character.                         */
       /**************************************************************/
       if ( ArgOptions & CHS_VECTOR )
            Width = ArgPosVector[j];
       else
            Width = (ULONG)pCPtInfo->WidthInWorkCoords;

       /**************************************************************/
       /* Now store the position of the next character.              */
       /**************************************************************/
       ArgXY[j+1].x = ArgXY[j].x + Width;
       ArgXY[j+1].y = ArgXY[0].y;
    }

    /******************************************************************/
    /* Convert the points to the reqd coord system.                   */
    /******************************************************************/
    if ( fsXform != VALUE_NOT_SET ) /* CON3203 */
    {
        if ( !da_ConvertWithMatrix( DcH,
                                    (PPOINTL)ArgXY,
                                    ArgCharNum + 1,
                                    (PXFORM)&xfm,
                                    0L,
                                    NGreConvertWithMatrix ) )
        {
          RetVal = ERROR_ZERO;
          goto EXIT_FUNCTION;
        }
    }

    /******************************************************************/
    /* Add in the start position if necessary.  This condition        */
    /* coincides with the cases where we do a xform to or from World  */
    /* coords - i.e. where there is a danger of a non-orthogonal      */
    /* xform matrix which will cause the y-coords to vary.  We dont   */
    /* want this - CharStringPos assumes all y coords are the same.   */
    /* Hence we force the y-coord to remain constant.                 */
    /******************************************************************/
    if ( !InclStartPos )
    {
       for ( j = 0; j < (USHORT)ArgCharNum + 1; j++ )
       {
          ArgXY[j].x += StartPos.x;
          ArgXY[j].y  = StartPos.y;
        }
    }

EXIT_FUNCTION:

    /**********************************************************/
    /* Free any memory allocated for Validated codepoints     */
    /*  in the case of device outline fonts                   */
    /**********************************************************/
    if (ValidatedCpts != FNULL)
    {
        (VOID)prdg_FreeHeapItem(DCIData, (USHORT)ArgCharNum,
                                      /* (PUSHORT)&ValidatedCpts); */
                                         (PUSHORT)ValidatedCpts); /*CON3201*/
    }

    prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,EC)
#endif

    if ( RetVal == ENG_CALL )
    {
        /**************************************************************/
        /* Return to engine if the COM_DEVICE bit allows, otherwise   */
        /* do nowt.                                                   */
        /**************************************************************/
        if ( !(Command & COM_DEVICE) )
        {
            return (da_QueryCharPositions( DcH, ArgStart, ArgOptions,
                                           ArgCharNum, ArgCodePoints,
                                           ArgPosVector, ArgXY,
                                           DCIData, FunN ));
        }
        else
        {
            return (OK);
        }
    }
    else
    {
        return (RetVal);
    }

}
#undef TFUNC






/**********************************************************************/
/*                                                                    */
/*   FUNCTION: prdt_QueryWidthTable                                   */
/*                                                                    */
/*   PARAMETERS:                                                      */
/*                                                                    */
/*   See "OS/2 Technical Reference: I/O Subsytems and Device Drivers" */
/*                                                                    */
/*   HDC           DcH;                                               */
/*   ULONG         ulFirstChar;                                       */
/*   ULONG         cChars;                                            */
/*   PULONG        WidthTable;                                        */
/*   lpDCI         DCIData;                                           */
/*   ULONG         FunN;                                              */
/*                                                                    */
/*   DESCRIPTION:                                                     */
/*                                                                    */
/*   This function determines the widths of the current font          */
/*   codepoints, commencing at ulFirstChar and returning cChars       */
/*   widths.                                                          */
/*                                                                    */
/**********************************************************************/
ULONG EXPENTRY prdt_QueryWidthTable( HDC      DcH,
                                     LONG     lFirstChar,
                                     LONG     cChars,
                                     PLONG    pWidthTable,
                                     lpDCI    DCIData,
                                     ULONG    FunN)

{
#define TFUNC "prdt_QryWdthTab"

    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG              Command;
    lpFontDataType     pFontData;
    lpFontInfoType     pFontInfo;
    LONG               RetVal;
    LONG               Width;
    SHORT              i;
    USHORT             fsAttrs;      /* The font attribute in terms   */
                                     /* of bit flags                  */
    POINTL             Step;
    XFORM              xfm;
    ULONG              fsXform;
    BOOL               bOutline;
    BYTE               CodePoint;


    /******************************************************************/
    /* If no widths to return then nowt to do.                        */
    /******************************************************************/
    if ( cChars == 0L )
        return (OK);

    /******************************************************************/
    /* Initial stuff..                                                */
    /******************************************************************/
#ifdef PRD_TIMING
    DEKHOOK0(A,9,6D)
#endif
    prdm_EnterDriver(DCIData);

/*  Command = HIUSHORT(FunN);       CON3201 */
    Command = FunN & 0xFFFF0000; /* CON3201 */
    RetVal  = OK;

    /******************************************************************/
    /* Set up pointers.                                               */
    /******************************************************************/
    pFontData = &DCIData->DCIFontData;
    pFontInfo = &pFontData->Info;

    /******************************************************************/
    /* Call engine for an engine font.                                */
    /* Note: CharMode, attributes etc. do not affect this function.   */
    /******************************************************************/
    if ( pFontInfo->Type == FT_ENGINE )
    {
        RetVal = ENG_CALL;
        goto EXIT_FUNCTION;
    }

    /******************************************************************/
    /* This is a device font - check for invalid lFirstChar and       */
    /* cChars parameters.  Our device fonts have a width table of     */
    /* length 256 and we need to avoid trying to pick up info for     */
    /* characters outside of this range.                              */
    /*                                                                */
    /* However we follow the example of the Graphics Engine in        */
    /* ignoring the value of lFirstChar (provided it is not > 255)    */
    /* when error checking.  Note that the above this checking on     */
    /* lFirstChar done by the Engine implies that it counts the code  */
    /* points from 0.                                                 */
    /*                                                                */
    /* If cChars takes us beyond 256 we loop round back to the        */
    /* start again.                                                   */
    /******************************************************************/
    if ( (lFirstChar > 255L) || (lFirstChar < 0L) )
    {
        LOGERR(TFUNC, "Invalid first character", FNULL, 0,
                                                 PMERR_INV_FIRST_CHAR);
        RetVal = ERROR_ZERO;
        goto EXIT_FUNCTION;
    }

    if ( (cChars > 256L) || (cChars < 0L) )
    {
        LOGERR(TFUNC, "Invalid count", FNULL, 0,
                                       PMERR_INV_LENGTH_OR_COUNT);
        RetVal = ERROR_ZERO;
        goto EXIT_FUNCTION;
    }


    /******************************************************************/
    /* If the font is outline then we take the charbox  into account. */
    /* The width of each character from the widthtable is scaled by   */
    /* the CharBox.                                                   */
    /*                                      PD00073                   */
    /******************************************************************/

    if ( (pFontData->pMetrics->fsDefn & FM_DEFN_OUTLINE) &&
         (pFontData->Genre == DEVICE_FONT) )
    {
        for ( i = (SHORT)lFirstChar; cChars--; i++ )
        {
            /**********************************************************/
            /* Wraparound if we reach the end of the font table.      */
            /**********************************************************/
            if ( i == 256 )
            {
                i = 0;
            }

            /**********************************************************/
            /* Get the character width from the FMF data.             */
            /**********************************************************/
            /**********************************************************/
            /* Allow for simulated codepage                           */
            /**********************************************************/
//          CodePoint = prdt_ValidateCodePoint( (BYTE)i,
//                                               pFontData,
//                                               DCIData );

            Width =(pFontInfo->pFont->WidthFlag & FMF_WIDTH_MASK);

            /**********************************************************/
            /* If not fixed space font then get the character width   */
            /**********************************************************/
            if ( !Width )
            {
              Width = (LONG)pFontInfo->pFont->CharWidth[CodePoint];
            }


            if ( !(Command & COM_TRANSFORM) )
            {
                Width = (LONG)prdt_ScaleXMetricToDevice(
                                    DCIData,
                                    pFontData, Width);
            }
            else
            {
                Width = (LONG)prdg_ScaleValue(
                             Width,
                             (LONG)DCIData->DCICurTxtAts->cbnd.sizfxCell.cx,
                             (LONG)pFontData->pMetrics->xEmInc << 16 );
            }
            /**********************************************************/
            /* Put the entry into the width table                     */
            /**********************************************************/
            *pWidthTable++ = Width;

        }
    }
    else
    {
       /******************************************************************/
       /*                                                                */
       /* If the font is image then we should just return the width in   */
       /* the width table, even at CM_MODE_2. This follows the engine    */
       /* and the pcl driver.                                            */
       /*                                                                */
       /******************************************************************/

       /******************************************************************/
       /* Ignore the origin shift as we are converting widths not        */
       /* positions.                                                     */
       /******************************************************************/
       fsXform = VALUE_NOT_SET;
       if ( !(Command & COM_TRANSFORM) )
       {
          fsXform = FONT_TO_DEVICE | IGNORE_ORIGIN_SHIFT;
       }
       else
       {
          fsXform = FONT_TO_WORLD | IGNORE_ORIGIN_SHIFT;
       }

       /******************************************************************/
       /* Get the xform matrix.                                          */
       /******************************************************************/
       if (fsXform != VALUE_NOT_SET) /* CON3203 */
       {
           if ( prdg_GetXformMatrix( DcH,
                                     fsXform,
                                     (PXFORM)&xfm,
                                     DCIData ) != OK )
           {
               RetVal = ERROR_ZERO;
               goto EXIT_FUNCTION;
           }
       }

       /******************************************************************/
       /* If the width flag is non-zero it contains the width of a fixed */
       /* pitch font.                                                    */
       /******************************************************************/
       if ( (pFontInfo->pFont->WidthFlag & FMF_WIDTH_MASK) !=0 )
       {
           /**************************************************************/
           /* Convert width from CptInfo.                                */
           /**************************************************************/
           Width = (LONG)pFontData->CPtInfo.Width;

           Step.x = Width;
           Step.y = 0L;

           /**************************************************************/
           /* Use prdt_XformPoint to convert the width - this returns    */
           /* the length of the transformed vector.                      */
           /**************************************************************/
           if (fsXform != VALUE_NOT_SET) /* CON3203 */
               Width = prdg_XformPoint( DcH, (PPOINTL)&Step, (PXFORM)&xfm);

           /**************************************************************/
           /* Fill up the width table.                                   */
           /**************************************************************/
           for ( ; cChars-- ; *pWidthTable++ = Width );
        }
        else
        {
           /**************************************************************/
           /* Loop through characters whose width is to be returned.     */
           /**************************************************************/
           for ( i = (SHORT)lFirstChar; cChars--; i++ )
           {
               /**********************************************************/
               /* Wraparound if we reach the end of the font table.      */
               /**********************************************************/
               if ( i == 256 )
               {
                   i = 0;
               }

               /**********************************************************/
               /* Get the character width from the FMF data.             */
               /**********************************************************/
               prdt_NextCodePoint( (USHORT)i,
                                   pFontData,
                                   DCIData );

               Width = (LONG)pFontData->CPtInfo.Width;

               /**********************************************************/
               /*  Convert width.                                        */
               /**********************************************************/
               Step.x = Width;
               Step.y = 0L;

               /**********************************************************/
               /* Use prdt_XformPoint to convert the width - this        */
               /* returns the length of the transformed vector.          */
               /**********************************************************/
               if (fsXform != VALUE_NOT_SET) /* CON3203 */
               {
                   Width = prdg_XformPoint( DcH,
                                            (PPOINTL) &Step,
                                            (PXFORM) &xfm );
               }

               /**********************************************************/
               /* Put the entry into the width table                     */
               /**********************************************************/
               *pWidthTable++ = Width;
           }
           /* .... for ( i = (SHORT)lFirstChar; cChars--; i++ ) ........ */
       }
       /* .... if not fixed pitch ...................................... */
    }

EXIT_FUNCTION:
    prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,9,ED)
#endif

    if ( RetVal == ENG_CALL )
    {
        /**************************************************************/
        /* Return to engine if the COM_DEVICE bit allows, otherwise   */
        /* do nowt.                                                   */
        /**************************************************************/
        if ( !(Command & COM_DEVICE) )
            return ( da_QueryWidthTable( DcH, lFirstChar, cChars,
                                         pWidthTable, DCIData, FunN ) );
        else
            return (OK);
    }
    else
        return (RetVal);

}
#undef TFUNC

